Pregunta

Heredé un programa de 10K líneas escrito en lenguaje ensamblador 8051 que requiere algunos cambios.Desafortunadamente, está escrito en las mejores tradiciones del código espagueti.El programa, escrito como un solo archivo, es un laberinto de declaraciones CALL y LJMP (alrededor de 1200 en total), con subrutinas que tienen múltiples puntos de entrada y/o salida, si es que pueden identificarse como subrutinas.Todas las variables son globales.Hay comentarios;algunas son correctas.No existen pruebas ni presupuesto para refactorizar.

Un poco de historia sobre la aplicación:El código controla un centro de comunicaciones en una aplicación de venta que actualmente se implementa a nivel internacional.Maneja dos flujos en serie simultáneamente (con la ayuda de un procesador de comunicaciones independiente) y puede comunicarse con hasta cuatro dispositivos físicos diferentes, cada uno de un proveedor diferente.El fabricante de uno de los dispositivos hizo recientemente un cambio ("Sí, hicimos un cambio, ¡pero el software es absolutamente el mismo!"), lo que provoca que algunas configuraciones del sistema ya no funcionen y no está interesado en cambiarlo (sea lo que sea). no cambiaron).

El programa fue escrito originalmente por otra empresa, transferido a mi cliente y luego modificado hace nueve años por otro consultor.Ni la empresa original ni el consultor están disponibles como recursos.

Basándome en el análisis del tráfico en uno de los buses serie, se me ocurrió un truco que parece funcionar, pero es feo y no aborda la causa raíz.Si tuviera una mejor comprensión del programa, creo que podría abordar el problema real.Tengo aproximadamente una semana más antes de que se congele el código para respaldar una fecha de envío de fin de mes.

Pregunta original:Necesito entender el programa lo suficientemente bien como para realizar los cambios sin interrupciones.¿Alguien ha desarrollado técnicas para trabajar con este tipo de desorden?

Veo algunas sugerencias excelentes aquí, pero estoy limitado por el tiempo.Sin embargo, es posible que tenga otra oportunidad en el futuro de seguir algunos de los cursos de acción más complicados.

¿Fue útil?

Solución

En primer lugar, me gustaría tratar de ponerse en contacto con esas personas que originalmente desarrollaron el código o que al menos se mantenga antes que yo, es de esperar obtener suficiente información para obtener una comprensión básica del código en general, para que pueda empezar a añadir útiles comentarios a la misma.

Tal vez incluso se puede conseguir a alguien para describir las API más importantes (incluyendo su firma, valores y el propósito de retorno) para el código. Si el estado global es modificada por una función, esto también debe hacerse explícito. Del mismo modo, empezar a diferenciar entre funciones y procedimientos, así como registros de entrada / salida.

Usted debe dejar muy claro a su empleador que se requiere esta información, si no te creen, tienen ellos en realidad se sientan con usted delante de este código, mientras que describa lo que se supone que deben hacer y cómo hay que hacerlo (ingeniería inversa). Tener un empleador con un fondo en la informática y la programación será realmente útil en ese caso!

Si su empleador no tiene un fondo tan técnico, pedirle que traiga otro programador / compañero de trabajo para explicar sus medidas para él, al hacerlo, de hecho mostrarle que usted es serio y honesto sobre ello, porque es un problema real -. no sólo desde su punto de vista (asegúrese de tener colegas que saben acerca de este 'proyecto')

Si está disponible y factible, también me gustaría dejar muy claro, que la contratación (o por lo menos en contacto con) los antiguos desarrolladores / mantenedores (si es que ya no están trabajando para su empresa, que es) para ayudar a documentar el código haría ser un requisito previo para mejorar de manera realista el código dentro de un corto período de tiempo y para asegurar que se puede mantener más fácilmente en el futuro.

Haga hincapié en que toda esta situación se debe a deficiencias en el proceso de desarrollo de software anterior y que estas medidas ayudarán a mejorar la base de código. Por lo tanto, la base de código en su forma actual es un problema creciente y lo que se hace ahora para manejar este problema es una inversión para el futuro.

Esto en sí mismo es también importante para ayudar a evaluar y comprender su situación: Para hacer lo que se supone que hacer ahora es lejos de ser trivial, y debe saber sobre él - aunque sólo sea para establecer sus expectativas recta (por ejemplo, con respecto a los plazos y la complejidad de la tarea).

Además, personalmente me gustaría empezar a añadir pruebas de unidad para aquellas partes que entiendo bastante bien, de modo que pueda comenzar lentamente refactorización / reescritura de algo de código.

En otras palabras, una buena documentación y código de comentarios de código son una cosa, pero tener una suite completa de los ensayos es otra cosa importante, nadie se puede esperar de manera realista para modificar una base de código desconocido sin ninguna forma establecida de probar la funcionalidad clave.

Dado que el código es de 10K, también me miro en factorización de subrutinas en archivos separados para hacer componentes más identificable, preferiblemente usando envolturas de acceso en lugar de las variables globales y también los nombres de archivo intuitivos.

Además, me gustaría ver en medidas para mejorar aún más la legibilidad del código fuente mediante la disminución de la complejidad, tener rutinas sub con múltiples puntos de entrada (y posiblemente incluso diferentes signaturas de parámetros?) Que parece ser una manera segura para ofuscar el código innecesariamente .

Del mismo modo, enormes rutinas sub podrían también ser refactorizan en otros más pequeños para ayudar a mejorar la legibilidad.

Por lo tanto, una de las primeras cosas, me vería en hacer sería determinar aquellas cosas que hacen que sea muy complicado de asimilar la base de código y luego volver a trabajar las partes, por ejemplo mediante el fraccionamiento de grandes rutinas sub con entradas múltiples puntos en las rutinas sub distintas que se llaman entre sí en su lugar. Si esto no se puede hacer debido a razones de rendimiento o llame por encima, utilizar macros en su lugar.

Además, si se trata de una opción viable, consideraría porciones de forma incremental reescritura del código utilizando un lenguaje más alto nivel,ya sea mediante el uso de un subconjunto de C, o al menos haciendo uso bastante excesivo de macros de montaje para ayudar a estandarizar la base de código, sino también para ayudar a localizar los errores potenciales.

Si una reescritura incremental en la C es una opción factible, una posible manera de empezar sería convertir todas las funciones obvias en funciones de C cuyos cuerpos están -en principio- el copiado / pegado desde el archivo de ensamblaje, de manera que se termina con funciones de C con las porciones de montaje en línea.

En lo personal, yo también intente ejecutar el código en un simulador / emulador al paso fácilmente a través del código y espero empezar a entender los bloques de construcción más importantes (al examinar el registro y la utilización de pila), un buen simulador de 8051 con un depurador integrado deberían estar disponibles para usted si usted realmente tiene que hacer esto en gran medida por su cuenta.

Esto también ayudaría a llegar a la secuencia de inicialización y la estructura de bucle principal, así como un callgraph.

Tal vez, incluso se puede encontrar una buena 80851 simulador de código abierto que puede ser fácilmente modificado para proporcionar también un callgraph completa de forma automática, simplemente haciendo una búsqueda rápida, encontré gsim51 , pero es evidente que hay varias otras opciones, varios las patentadas así.

Si yo estuviera en su situación, yo incluso considerar la externalización de los esfuerzos de modificar mis herramientas para simplificar el trabajo con este código fuente, es decir, muchos proyectos de SourceForge aceptan donaciones y tal vez se puede hablar de su empleador en el patrocinio de una modificación de este tipo.

Si no económicamente, tal vez por que le proporciona parches correspondientes a ella?

Si ya está utilizando un producto patentado, que incluso podría ser capaz de hablar con el fabricante de este software y detalle sus necesidades y les pregunta si están dispuestos a mejorar este producto de esa manera o si al menos pueden exponer una interfaz para permitir a los clientes realizar este tipo de personalizaciones (algún tipo de API interna o tal vez incluso scripts de cola simples).

Si ellos no responden, indican que su empleador ha pensado en utilizar un producto diferente desde hace algún tiempo y que fueron el único insistir en ese producto en concreto que se utilizará ...; -)

Si el software espera que el hardware determinado de E / S y periféricos, puede que incluso desee ver en escribir un bucle de simulación de hardware correspondiente a ejecutar el software en un emulador.

En última instancia, lo sé a ciencia cierta que personalmente me gustaría mucho más disfrutar del proceso de personalización de otros programas para ayudar a entender un monstruo código espagueti, que paso a paso de forma manual a través del código y jugar emulador de mí mismo, no importa cuántos galones de café que pueda conseguir.

Conseguir un callgraph utilizable a partir de una fuente abierta 8051 emulador no debe tomar mucho más tiempo que dicen que un fin de semana (como máximo), ya que significa sobre todo para buscar códigos de operación CALL y registrar sus direcciones (posición y destino), por lo que todo está vierten en un archivo para su posterior inspección.

Tener acceso a los componentes internos de un emulador sería en realidad también ser grande una manera de inspeccionar aún más el código, por ejemplo con el fin de encontrar patrones recurrentes de códigos de operación (por ejemplo 20-50 +), que puede ser un factor en funciones / procedimientos independientes, En realidad, esto podría ayudar a disminuir el tamaño y la complejidad de la base de código aún más.

El siguiente paso sería probablemente para examinar la pila y registrar su uso. Y para determinar el tipo / tamaño de los parámetros de función utilizado, así como su rango de valores -. Para que pueda concebir pruebas unitarias correspondientes

El uso de herramientas como puntos / graphviz para visualizar la estructura de la secuencia de inicialización y el bucle principal en sí, será una alegría pura en comparación con hacer todo esto de forma manual.

Además, en realidad, terminará con los datos y documentos útiles que pueden servir como base para una mejor documentación de la LOng de ejecución.

Otros consejos

Me temo que no hay una fórmula mágica para este tipo de problema. Me parece que la única solución es imprimir el archivo ASM luego ir a un lugar tranquilo y para simular la ejecución del programa línea a línea en su mente (al escribir los contenidos de los registros y las posiciones de memoria en un bloc de notas). Después de un tiempo a encontrar esto no toma tanto tiempo como era de esperar. Esté preparado para pasar muchas horas haciendo esto y beber litros de café. Después de un tiempo usted tendrá una comprensión de lo que está haciendo y se puede considerar cambios.

¿El 8051 tiene ningún puertos IO no utilizados? Si no lo hace y se puede no funcionar cuando ciertas rutinas están siendo llamados a continuación, agregar código para enviar estos puertos piezas de alta o baja. Entonces cuando el programa se está ejecutando ver estos puertos con un osciloscopio.

Buena suerte

Sé que esto suena loco... pero estoy desempleado (elegí el momento equivocado para decirle al socio mayoritario que se fuera al infierno) y tengo algo de tiempo libre.Estaría dispuesto a echarle un vistazo.Solía ​​​​escribir ensamblaje para Apple ][ y la PC original.Si pudiera jugar con su código en el simulador durante un par de horas, podría darle una idea si tengo la oportunidad de documentarlo (sin tener que ejecutar mis vacaciones no planificadas).Como no sé nada sobre 8051, esto podría no ser posible para alguien como yo, pero el simulador parecía prometedor.No quisiera dinero para hacer esto.Es suficiente con exponerse al desarrollo integrado 8051.Te dije que esto parecería una locura.

Encuentra otro trabajo- en serio! De no ser así el libro "trabajar eficazmente con el código heredado" podría ayudar- aunque creo que se refiere a código heredado como código sin pruebas unitarias.

he hecho este tipo de cosas un par de veces. Algunas recomendaciones:

  • Para comenzar, revisar el esquema, esto debería ayudar a entender lo puertos y pines los cambios deseados impacto.
  • Uso grep para encontrar todas las llamadas, ramas, saltos y devoluciones. Esto puede ayudar a entender el flujo e identificar los trozos de código.
  • Mira el vector de reset y interrumpir tabla para identificar el líneas principales.
  • Uso grep para crear una referencia cruzada para todas las etiquetas de código y datos referencias (si su ensamblador herramientas no pueden hacer esto para usted).

Tenga en cuenta la ley de Hofstadter: Siempre se tarda más tiempo del esperado, incluso cuando se tiene en cuenta la ley de Hofstadter .

Buena suerte.

¿Qué tan bien entiende la plataforma de hardware de este código se ejecuta en?

  • ¿Se ha puesto en modo de apagado (Pcon = 2) para ahorrar energía Si es así cómo se ha despertado. (Una interrupción de hardware de restablecimiento o sobre)

  • ¿Tiene que esperar un para el oscilador a los establos después de un encendido antes de realizar comunicaciones en serie

  • ¿Se ha puesto en modo de suspensión (Pcon = 1)

¿Hay diferentes versiones de hardware en el campo?

Asegúrese de que tiene todas las diferentes variaciones de hardware para probar sucesivamente.

No pierda su tiempo con un simulador - es muy difícil de trabajar y usted tiene que hacer muchas suposiciones sobre el hardware. Consígase un En Circuito emulador (ICE) y ejecutar en el hardware.

El software fue escrito en lenguaje ensamblador para una razón, tiene que averiguar por qué. es decir - restricciones de memoria - restricciones de velocidad

Puede haber una razón por la que este código es un desastre

Tener una mirada en el archivo de enlace para:

XDATA ESPACIO, IDATA SPACE y espacio de código:

Si no hay espacio de código libre o datos extendidos o Idata?

El autor original puede haber Optimizationed a encajar en el espacio de memoria disponible.

Si ese es el caso usted necesita hablar con el desarrollador original para averiguar lo que hizo .

No es necesario un presupuesto especial para la refactorización y pruebas - que le ahorrará dinero y le permiten trabajar más rápido - llegar a ella. Es la técnica que debe utilizar para añadir cambios a la herencia, código heredado, porque es la forma más barata de hacerlo sin "sin rotura".

La mayoría de las veces, creo que hay un trade-off donde se obtiene una mayor calidad a cambio de pasar más tiempo, pero con el código heredado que no está familiarizado con, creo que es más rápido para hacer pruebas - usted tiene que funcionar el código antes de enviar, ¿verdad?

Esta es una de las pocas veces que voy a recomendar a poner sus aptitudes para el trabajo, y presentar sus PM / Gerente / CXO con su razonamiento detrás de una re-escritura, y el ahorro de tiempo / coste implicado con tales una empresa

Cortar en trozos.

tuve algún problema muy similar con un software de 8052. Así que la compañía heredó un bestia, código ROM tales completa (64Kbytes), a unos 1,5 megas de módulos de espagueti de montaje más dos líneas 3000 módulos de PL / M compuestas esta monstruosidad de codificación. Los desarrolladores originales del software eran mucho tiempo muerto (esto no significa que no había nadie, pero de hecho nadie que entendería como un todo), los compiladores de la elaboración de estas eran de mediados de los 80 que se ejecutan en un emulador MDS-70, y varios críticos módulos estaban en los límites de estos compiladores. Al igual que añadir un símbolo más global, y el enlazador se estrellaría. Añadir un símbolo más de un archivo de ASM, y el compilador se estrellaría.

Entonces, ¿cómo se podría empezar a cortar esto?

En primer lugar tendrá que utilizar herramientas. Notepad ++, por ejemplo, es una cosa muy agradable, ya que puede ser utilizado para cruzar la búsqueda a lo largo de varios archivos a la vez, ideal para encontrar qué módulos se refieren en un símbolo global. Este es probablemente el elemento más importante.

Si es posible, obtener cualquier documento que puede encontrar en el software. El problema más inmediato para resolver con estas bestias es entender la forma en que se componen más o menos, ¿cuál es su arquitectura. Esto por lo general no está incluido en el software en sí, ni siquiera si es de otra manera adecuada comentó.

Para obtener la arquitectura de usted mismo, primero se puede tratar de construir un gráfico de llamadas . Es más sencillo hacer que un gráfico de flujo de datos, ya que por lo general hay menos llamadas entre archivos y saltos de variables globales. Para la presente convocatoria gráficos sólo tienen en cuenta los símbolos globales suponiendo que los archivos de origen se supone que son los módulos (que no es necesariamente cierto, pero por lo general debe ser).

Para ello, utilice la herramienta de búsqueda de archivos cruz, crear una lista grande (por ejemplo, en OpenOffice Calc) en el que recoger qué símbolo se define en qué archivo, y qué archivos se refieren a este símbolo llamándolo.

A continuación, robar algunos grandes (!) Hojas del trazador, y empezar a dibujar. Si está muy competentes en algún software gráfico, es posible que uso, pero a menos que sea así, es más probable que celebrar de nuevo. Así dibujar un gráfico de llamadas que muestra qué archivo tiene llamadas a las que otros archivos (que no muestran los símbolos mismos, con 50 o más archivos, no sería capaz de manejarlo).

Lo más probable es el resultado de esto será un espagueti. El objetivo es aclarar esto para conseguir que un árbol jerárquico con una raíz (que será el archivo que contiene el punto de entrada del programa) sin bucles. Usted puede devorar varias hojas durante este proceso de forma iterativa enderezar la bestia. También es posible encontrar ciertos archivos son mucho más interrelacionado enredado que no pueden ser representados sin bucles. Este caso lo más probable es que una sola "módulo" consiguió de alguna manera separada en dos archivos o módulos más conceptuales fueron enredados. Volver a la lista de llamadas, y agrupar los símbolos por lo que para cortar los archivos problemáticos en unidades independientes más pequeños (que tendrá que comprobar el archivo en sí también para los saltos locales aquí para ver su corte asumido es posible).

Para el final a menos que ya está trabajando en otro lugar para su propio bien, obtendrá un gráfico de llamadas jerárquica con módulos conceptuales. A partir de esto es posible deducir la arquitectura intencional del software y trabajar más.

El siguiente objetivo es el arquitectura . Por su mapa hecha previamente tendrá que navegar a lo largo del software, averiguar que de hilos (interrumpir y tareas principales del programa), y los efectos ásperos de cada uno de los módulos / archivos de origen. ¿Cómo se puede hacer esto y lo que se obtiene aquí depende más del dominio de aplicación.

Cuando estos dos se hace esto, el "resto" es bastante sencillo. Por estos que esencialmente debe saber lo que se supone que cada parte de lo que hay que hacer, y para que sepa lo que es probable que esté tratando con cuando se empieza a trabajar en un archivo de origen. Es importante sin embargo que cada vez que encuentre algo "sospechoso" en una fuente, queel programa parece hacer algo irrelevante, a volver a su arquitectura y el gráfico de llamadas, y hacer correcciones si es necesario.

Para el resto de los métodos de otros mencionados se aplican también. Me acabo de describir éstos para dar una idea de lo que puede hacerse en casos muy repugnantes. Me gustaría tener tan sólo 10 km de líneas de código para hacer frente a ese entonces ...

Yo diría que la respuesta de IanW (simplemente imprimirlo y mantener el seguimiento) es probablemente el mejor. Dicho esto, tengo un poco alejado de la idea de la pared:

Trate de ejecutar el código (probablemente el binario) a través de un simulador que puede reconstruir el código C (si se puede encontrar uno para el 8051). Tal vez pueda identificar algunas rutinas que no puede (fácilmente).

Tal vez que va a ayudar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top