Pergunta

Eu herdei um programa 10K-line escrito em linguagem assembly 8051 que requer algumas mudanças. Infelizmente está escrito nas melhores tradições de código espaguete. O programa - escrita como um único arquivo - é um labirinto de CALL e declarações LJMP (cerca de 1200 total), com sub-rotinas ter múltiplos pontos de entrada e / ou saída, se eles podem ser identificados como sub-rotinas em tudo. Todas as variáveis ??são globais. Há comentários; alguns estão corretas. Não há testes existentes, e nenhum orçamento para refatoração.

Um pouco de fundo sobre a aplicação: O código controla um centro de comunicações em um aplicativo de venda automática que é actualmente destacados internacionalmente. Ele lida com dois córregos de série simultaneamente (com a ajuda de um processador de comunicações separado) e pode estar falando com até quatro dispositivos físicos diferentes, cada um de um fornecedor diferente. O fabricante de um dos dispositivos recentemente fez uma mudança ( "Sim, fizemos uma mudança, mas o software é absolutamente o mesmo!") Que faz com que algumas configurações de sistema para não funcionam mais, e não está interessado em imutável-lo (seja lá o que era eles não mudar).

O programa foi originalmente escrito por outra empresa, transferido para o meu cliente, em seguida, modificada há nove anos por outro consultor. Nem a empresa original, nem o consultor, estão disponíveis como recursos.

Com base na análise do tráfego em um dos barramentos seriais, eu vim acima com um hack, que parece trabalho, mas é feio e não aborda a causa raiz. Se eu tivesse uma melhor compreensão do programa, eu acredito que eu poderia resolver o problema real. Tenho cerca de mais uma semana antes do código congelado para apoiar uma data de fim-de-navio mês.

pergunta original: Eu preciso entender o programa bem o suficiente para fazer as mudanças sem ruptura. Alguém técnicas desenvolvidas para trabalhar com esse tipo de confusão?

Eu vejo algumas sugestões grande aqui, mas estou limitado pelo tempo. No entanto I pode ter outra oportunidade no futuro para perseguir alguns dos cursos mais envolvidos de ação.

Foi útil?

Solução

Em primeiro lugar, gostaria de tentar entrar em contato com as pessoas que originalmente desenvolvido o código ou que, pelo menos, mantido antes de mim, espero obter informações suficientes para obter uma compreensão básica do código em geral, de modo que você pode começar a adicionar comentários úteis a ele.

Talvez você ainda pode conseguir alguém para descrever as APIs mais importantes (incluindo a sua assinatura, valores de retorno e propósito) para o código. Se o estado global é modificado por uma função, isso também deve ser explicitado. Da mesma forma, começam a diferenciar entre as funções e procedimentos, bem como dados de entrada / saída.

Você deve deixar muito claro ao seu empregador que esta informação é necessária, se não acreditar em você, eles têm realmente sentar com você na frente de este código enquanto você descrever o que é suposto fazer e como você tem que fazer isso (engenharia reversa). Tendo um empregador com experiência em computação e programação vai ser realmente útil, nesse caso!

Se o seu empregador não tem um fundo como técnico, pedir-lhe para trazer um outro programador / colega para explicar seus passos para ele, isso vai realmente mostrar-lhe que você é sério e honesto sobre isso, porque é um problema real -. e não apenas a partir de seu ponto de vista (certifique-se de ter colegas que sabem sobre este 'projecto')

Se estiver disponível e viável, Também gostaria de deixar bem claro, que a contratação (ou pelo menos entrar em contato) ex-desenvolvedores / mantenedores (se eles já não estão trabalhando para sua empresa, que é) para documento ajuda desse código, ser um pré-requisito para melhorar de forma realista o código dentro de um curto período de tempo e para garantir que ele pode ser mais facilmente mantida no futuro.

Enfatize que toda esta situação é devido a deficiências no processo de desenvolvimento de software anterior e que estas medidas irão ajudar a melhorar a base de código. Assim, a base de código em sua forma atual é um problema crescente e tudo o que é feito agora para lidar com este problema é um investimento para o futuro.

Isto em si também é importante para ajudá-los a avaliar e compreender sua situação: Para fazer o que é suposto fazer agora está longe de ser trivial, e eles devem saber sobre isso - se apenas para definir as suas expectativas em linha reta (por exemplo, em relação a prazos e complexidade da tarefa).

Além disso, pessoalmente eu iria começar a adicionar testes de unidade para aquelas partes que eu entendo bem o suficiente, para que eu possa começar devagar refatoração / reescrevendo algum código.

Em outras palavras, boa documentação e código fonte comentários são uma coisa, mas ter um conjunto de teste abrangente é outra coisa importante, ninguém pode esperar realisticamente para modificar uma base de código desconhecido sem qualquer forma estabelecida de testar a funcionalidade chave.

Uma vez que o código é 10K, eu também olhar para factoring fora sub-rotinas em arquivos separados para fazer componentes mais identificáveis, de preferência usando invólucros de acesso em vez de variáveis ??globais e também nomes de arquivos intuitiva.

Além disso, eu gostaria olhar sobre medidas para melhorar a legibilidade do código-fonte, diminuindo a complexidade, tendo sub rotinas com múltiplos pontos de entrada (e possivelmente até mesmo assinaturas diferentes parâmetros?) Se parece com uma maneira de ofuscar o código desnecessariamente .

Da mesma forma, grandes sub rotinas também poderia ser reformulado em partes menores para ajudar a melhorar a legibilidade.

Assim, uma das primeiras coisas, eu olhar em fazer seria determinar essas coisas que fazem realmente complicado para Grokar a base de código e, em seguida, refazer as partes, por exemplo, dividindo enormes sub rotinas com entrada múltipla pontos em sub rotinas distintas que chamam uns aos outros em vez. Se isso não pode ser feito devido a razões de desempenho ou chamada sobrecarga, uso de macros em vez.

Além disso, se for uma opção viável, eu consideraria porções de forma incremental reescrita do código usando uma linguagem mais alto nível,quer através da utilização de um subconjunto de C, ou, pelo menos, através de uma utilização bastante excessivo de macros de montagem para ajudar a padronizar o código base, mas também para ajudar a localizar possíveis erros.

Se uma reescrita incremental no C é uma opção viável, uma forma possível de começar seria transformar todas as funções óbvias para funções C cujos corpos são -no início-copiados / colados do arquivo de montagem, de modo que você acaba com funções C com lotes de linha de montagem.

Pessoalmente, eu também tente executar o código em um simulador / emulador para facilmente percorrer o código e espero começar a entender a maioria dos blocos importantes (ao examinar registo e uso da pilha), um simulador bom 8051 com um built-in depurador deve ser disponibilizado para você, se você realmente tem que fazer isso em grande parte por conta própria.

Isso também iria ajudá-lo a vir para cima com a seqüência de inicialização e estrutura de loop principal, bem como um callgraph.

Talvez, você pode até encontrar um bom open source 80851 simulador que pode ser facilmente modificado para também fornecer uma callgraph cheia automaticamente, apenas fazendo uma rápida pesquisa, descobri gsim51 , mas há, obviamente, várias outras opções, vários os proprietários também.

Se eu estivesse na sua situação, eu iria sequer considerar a terceirização do esforço de modificar as minhas ferramentas para simplificar o trabalho com este código-fonte, ou seja, muitos projetos SourceForge aceitar doações e talvez você pode falar o seu empregador para patrocinar uma tal modificação.

Se não financeiramente, talvez por você fornecendo manchas correspondentes a ele?

Se você já estiver usando um produto proprietário, você pode até ser capaz de falar com o fabricante deste software e detalhe suas necessidades e perguntar-lhes se eles estão dispostos a melhorar este produto dessa forma ou se eles podem, pelo menos, expor um interface para permitir que os clientes façam essas personalizações (alguma forma de API interna ou talvez até mesmo scripts cola simples).

Se eles não são sensíveis, indicam que seu empregador tem sido o pensamento de usar um produto diferente por algum tempo e agora que você foi o único a insistir em que determinado produto para ser usado ...; -)

Se o software espera que determinado hardware I / O e periféricos, você pode até querer olhar para escrever um loop de simulação de hardware correspondente para executar o software em um emulador.

Em última análise, eu sei para um fato que eu pessoalmente muito mais apreciar o processo de personalização de outro software para me ajudar a entender um monstro código espaguete, do que pisar manualmente através do código e jogar emulador mim mesmo, não importa quantos litros de café eu posso começar.

Conseguir um callgraph utilizável fora de uma fonte aberta 8051 emulador não deve demorar muito mais do que dizer um fim de semana (no máximo), porque a maioria significa olhar para opcodes chamada e gravar seus endereços (posição e destino), para que tudo de despejado em um arquivo para posterior inspeção.

Ter acesso a partes internas de um emulador iria realmente ser também uma maneira grande para inspecionar ainda mais o código, por exemplo, a fim de encontrar padrões de opcodes (dizer 20-50 +) recorrentes, que podem ser tidos em funções autônomas / procedimentos, isso realmente pode ajudar a diminuir o tamanho ea complexidade da base de código ainda mais.

O próximo passo seria provavelmente para examinar a pilha e registrar o uso. E para determinar o tipo / tamanho dos parâmetros da função utilizada, bem como a sua faixa de valor -. Modo que você pode conceber testes de unidade correspondente

Usando ferramentas como pontos / graphviz para visualizar a estrutura da seqüência de inicialização e do próprio loop principal, será uma alegria pura comparado a fazer tudo isso manualmente.

Além disso, você vai realmente acabar com dados e documentos úteis que podem servir como base para uma melhor documentação na long prazo.

Outras dicas

Eu tenho medo não há nenhuma bala mágica para este tipo de problema. Acho que a única solução é imprimir o arquivo ASM, em seguida, ir a algum lugar tranquilo e para simular a execução do programa de linha por linha em sua mente (ao escrever o conteúdo dos registros e locais de memória em um bloco de notas). Depois de um tempo você acha que isso não demorar tanto tempo como seria de esperar. Esteja preparado para gastar muitas horas fazendo isso e beber litros de café. Depois de um tempo, você terá uma compreensão do que está fazendo e você pode considerar alterações.

Será que o 8051 tem nenhum portas IO não utilizados? Se isso acontecer e você pode não funcionar para fora quando determinadas rotinas estão sendo chamados em seguida, adicione código para enviar essas portas peças de alta ou baixa. Então quando o programa está sendo executado assistir essas portas com um osciloscópio.

Boa sorte

Eu sei que isso parece loucura .... mas estou desempregado (eu escolhi hora errada para dizer ao parceiro marjority ir para o inferno) e ter algum tempo livre. Eu estaria disposto a dar uma olhada no que faz. Eu costumava escrever de montagem para a maçã] [e o PC original. Se eu pudesse brincar com o seu código no simulador por algumas horas eu poderia lhe dar uma idéia se eu tiver a chance de documentar isso para você (sem runing minhas férias não planejadas). Desde que eu não sei nada sobre 8051 Isto pode não ser possível para alguém como eu, mas o simulador parecia promissor. Eu não quero nenhum dinheiro para fazer isso. Sua suficiente apenas para obter exposição a 8051 desenvolvimento de sistemas embarcados. Eu disse que isso iria parecer loucura.

Encontre outro trabalho- sério! Falhando que o livro "trabalhar de forma eficaz com código legado" pode ajudar- embora eu acho que ele está se referindo ao código legado como código sem testes de unidade.

Eu fiz este tipo de coisa que um par de vezes. Algumas recomendações:

  • Comece por rever o esquema, Isso deve ajudar a entender o que portos e pins as alterações desejadas impacto.
  • Use grep para encontrar todas as chamadas, ramos, salta e retorna. Isso pode ajudar a compreender o fluxo e identificar os pedaços de código.
  • Olhe para o vetor de reset e mesa de interrupção para identificar o principais linhas.
  • Use grep para criar uma referência cruzada para todas as etiquetas de código e dados referências (se o seu assembler ferramentas não pode fazer isso para você).

Tenha em mente Lei de Hofstadter: É sempre leva mais tempo do que o esperado, mesmo quando você levar em conta a Lei de Hofstadter .

Boa sorte.

Como você entender a plataforma de hardware este código está sendo executado em?

  • É sido colocado em modo poder para baixo (Pcon = 2) para economizar energia Se sim, como é que foi acordado. (Um reset ou em interrupção de hardware)

  • Você tem que esperar um para o oscilador para estábulos depois de um power-up antes de fazer comunicação serial

  • É sido colocado no modo sleep (Pcon = 1)

Existem diferentes versões do hardware no campo?

Certifique-se de que você tem todas as diferentes variações de hardware para testar.

Não desperdice o seu tempo com um simulador - é muito difícil trabalhar com e você tem que fazer um monte de suposições sobre o hardware. Arranja um In Circuit Emulator (ICE) e executado no hardware.

O software foi escrito em assembler por uma razão que você precisa para descobrir o porquê. i.e. - restrições de memória - restrições de velocidade

Pode haver uma razão para que este código é uma bagunça

Tenha um olhar para o arquivo de link para:

XDATA SPACE, IDATA espaço e espaço código:

Se não houver espaço de código livre ou Xdata ou iData?

O autor original pode ter Optimizationed-lo para caber no espaço de memória disponível.

Se for esse o caso, você precisa falar com o desenvolvedor original para descobrir o que ele fez .

Você não precisa de um orçamento especial para refatoração e teste - Eles lhe poupar dinheiro e deixá-lo trabalhar mais rápido - chegar a ele. É a técnica que você deve usar para adicionar alterações ao legado, código herdado porque é a forma mais barata de fazê-lo sem "sem ruptura".

Na maioria das vezes, eu acho que há um trade-off, onde você tem mais qualidade em troca de passar mais tempo, mas com código legado que você está familiarizado com, eu acho que é mais rápido para fazer testes - você tem que correr o código antes de enviá-lo, certo?

Esta é uma das poucas vezes que eu vou recomendar que você colocar suas habilidades sociais para o trabalho, e apresentar o seu PM / Gerente / CXO com o seu raciocínio por trás de uma re-escrita, e as economias de tempo / custo envolvido com tais uma empresa

Corte-o em pedaços.

eu tinha algum problema muito semelhante com um software 8052. Assim, a empresa herdado um tal animal, ROM código completo (64Kbytes), cerca de 1,5 MB de módulos de montagem espaguete mais duas linhas 3000 módulos de PL / M, composto este monstrosity codificação. Os desenvolvedores originais do software foram mortos há muito tempo (isso não significa que não havia ninguém, mas na verdade ninguém que iria entendê-la como um todo), os compiladores que compilam estes eram de meados dos anos 80 em execução em um MDS-70 emulador, e vários críticos módulos estavam nos limites destes compiladores. Como adicionar um símbolo mais global, eo vinculador iria falhar. Adicionar mais um símbolo para um arquivo ASM, eo compilador iria falhar.

Então, como pode-se começar a cortar isso?

Primeiro você vai precisar de ferramentas. Notepad ++, por exemplo, é uma coisa muito agradável, uma vez que pode ser usado para pesquisa transversal ao longo de vários arquivos de uma vez, ideal para descobrir quais módulos referem-se um símbolo global. Este é provavelmente o elemento mais importante.

Se possível, obter quaisquer documentos que você pode encontrar no software. O problema mais imediato para resolver com esses animais é entender como eles estão mais ou menos composto, qual é a sua arquitetura. Isso geralmente não é incluído no software em si, nem mesmo se for de outra forma adequadamente comentou.

Para obter a arquitectura-se, em primeiro lugar você pode tentar construir uma chamada gráfico . É mais simples para fazer do que um gráfico de fluxo de dados desde normalmente há menos chamadas cross-arquivo e salta de variáveis ??globais. Para esta chamada gráficos consideram apenas símbolos globais assumindo os arquivos de origem é suposto ser módulos (o que não é necessariamente verdade, mas geralmente eles devem ser).

Para fazer isso, use a ferramenta de pesquisa de arquivo cruz, criar uma lista grande (por exemplo, em OpenOffice Calc) onde você coletar que símbolo é definido no qual arquivo e quais arquivos se referem a este símbolo chamá-lo.

Em seguida, roubar algumas grandes (!) Folhas do plotter, e começar a desenhar. Se você é muito proficiente em algum software gráfico, você pode usá-lo, mas a menos que seja assim, é mais provável que prendê-lo de volta. Então esboçar-se uma exibição gráfico de chamadas que arquivo tem chamadas para que outros arquivos (não mostrando os próprios símbolos, com 50 ou mais arquivos, você não seria capaz de controlá-lo).

O mais provável é o resultado disso será um espaguete. O objetivo é endireitar isto para obtê-lo uma árvore hierárquica com uma raiz (que será o arquivo que contém o ponto de entrada do programa) sem loops. Você pode devorar várias folhas durante este processo de forma iterativa endireitar o fora besta. Você também pode encontrar determinados arquivos são muito inter-emaranhado que não podem ser representados sem loops. Neste caso, é mais provável que um único "módulo" foi de alguma forma separada em dois arquivos, ou mais módulos conceituais foram enroscado. Volte para a sua lista de chamadas, e do grupo os símbolos de modo a cortar os arquivos problemáticos em unidades independentes menores (você terá que verificar o arquivo em si também para saltos locais aqui para ver o seu corte assumida é possível).

Para o fim, a menos que você já está trabalhando em outro lugar para o seu próprio bem, você vai ter um gráfico de chamadas hierárquica com módulos conceituais. A partir disso, é possível deduzir arquitetura intencional do software e trabalhar ainda mais.

A próxima meta é o arquitetura . Por seu feito anteriormente mapear você precisará navegar ao longo do software, figura para fora é threads (tarefas principais do programa de interrupção e), e os fins ásperas de cada um dos módulos arquivos / de origem. Como você pode fazer isso e que você chegar aqui depende mais do domínio da aplicação.

Quando estes dois são feitos, o "resto" é bastante simples. Por estes você deve, essencialmente, saber o que cada parte da coisa é suposto fazer, e para que você saiba o que você está provavelmente lidar com quando você começar a trabalhar em um arquivo de origem. É importante ainda que sempre que você encontrar algo "suspeito" em uma fonte, queo programa parece fazer algo irrelevante, para voltar à sua arquitetura e gráfico de chamadas, e fazer as correções, se necessário.

Para o resto dos métodos de outros mencionados aplicam-se bem. Eu só esboçou estes para dar algumas dicas sobre o que pode ser feito em casos realmente horríveis. Eu gostaria de ter apenas 10K linhas de código para lidar com naquela época ...

Eu diria que a resposta de IanW (basta imprimi-lo e mantê-tracing) é provavelmente o melhor. Dito isto, eu tenho um pouco fora a ideia de parede:

Tente executar o código (provavelmente o binário) através de um dissimulador que pode reconstruir código C (se você pode encontrar um para o 8051). Talvez ele irá identificar algumas rotinas que você não pode (facilmente).

Talvez ele vai ajudar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top