¿Cómo se extrae la información de la variable local (dirección y tipo) de un programa Delphi o la información de depuración generada por el compilador?

105

Mi meta es:

  • Dado un hilo suspendido en un programa de Windows de 32 o 64 bits compilado con Delphi, para recorrer la pila (factible)
  • Dadas las entradas de la pila, enumerar las variables locales en cada método y sus valores. Es decir, como mínimo, encuentre su dirección y tipo (integer32 / 64 /igned / unsigned, string, float, record, class ...) cuya combinación se puede usar para encontrar su valor.

La primera está bien y es la segunda de la que trata esta pregunta. En un nivel alto, ¿cómo se enumeran las variables locales dada una entrada de pila en Delphi?


En un nivel bajo, esto es lo que he estado investigando:

RTTI: no incluye este tipo de información sobre métodos. Esto no fue algo que en realidad alguna vez pensé que fuera una opción realista, pero enumerar aquí de todos modos.

Información de depuración: carga de la información de depuración producida para una compilación de depuración.

  • Archivos de mapa: incluso un archivo de mapa detallado (¡un archivo en formato de texto! Abra uno y eche un vistazo) no contiene información de variable local. Básicamente es una lista de direcciones y números de línea de archivos de origen. Excelente para la correlación de dirección a archivo y línea, por ejemplo, los puntos azules en el canalón; no es genial para obtener información más detallada
  • Información de depuración remota (archivo RSM): no se conoce información sobre su contenido o formato.
  • Archivos TD32 / TDS: mi línea de investigación actual. Contienen símbolos globales y locales entre mucha otra información.

Los problemas que encuentro aquí son:

  • No hay documentación del formato de archivo TD32 (que puedo encontrar).
  • La mayor parte de mi conocimiento de ellos proviene del código Jedi JCL que los usa (JclTD32.pas) y no estoy seguro de cómo usar ese código, o si las estructuras allí son lo suficientemente extensas como para mostrar vars locales. Estoy bastante seguro de que manejará símbolos globales, pero no estoy muy seguro de lo local. Hay una gran variedad de constantes definidas y sin documentación para el formato, para leer lo que significan, me quedo adivinando. Sin embargo, esas constantes y sus nombres deben provenir de alguna parte.
  • La fuente que puedo encontrar usando la información de TDS no carga ni maneja símbolos locales.

Si este es el enfoque correcto, entonces esta pregunta se convierte en '¿Existe documentación para el formato de archivo TDS / TD32 y hay ejemplos de código que cargan variables locales?'

Una muestra de código no es esencial, pero podría ser muy útil, incluso si es mínima.

David
fuente
2
En realidad, no he usado las unidades Jedi JCL para acceder a la información TD32; tengo mi propia biblioteca patentada para eso, pero parece que toda la plomería básica que necesitará está en JclTD32.pas. Sin embargo, no hay un código de demostración que pueda encontrar para acceder a la información de la variable, pero la muestra que está allí (en .. \ jcl \ examples \ windows \ debug \ sourceloc) muestra cómo obtener la información del número de línea de los datos TD32, entonces debería poder aprovechar eso para obtener lo que necesita. Informe aquí lo que descubrió :)
500 - Error interno del servidor
2
@ 500-InternalServerError Gracias. La información del número de línea es fácil (incluso en archivos de mapa), pero ¿puede proporcionar información sobre lo que ve en el código JCL que se relacione específicamente con los símbolos locales? Además, por curiosidad, ¿cuál es su biblioteca patentada TD32? ¿Se publica / se puede utilizar públicamente o solo internamente?
David
3
Cada símbolo de procedimiento / función / método debajo de él a su vez contiene una lista de símbolos que le son locales. La mayoría de las definiciones parecen estar ahí en la unidad Jedi, pero algunas están comentadas. Mi sugerencia sería crear pequeñas aplicaciones de prueba y ver qué devuelve una enumeración de símbolos. El código que tengo es propietario y no puedo publicarlo. De todos modos, no cubre el tema de las variables locales. Pero la información en la que se basa es semipública, por lo que es posible que pueda ayudar si se encuentra con paredes específicas.
500 - Error interno del servidor
4
tds2pdb ( code.google.com/p/map2dbg ) parece tener un analizador de archivos tds. Sin embargo, es código C #.
Graymatter
4
Solía ​​haber un documento informal, sí, pero luego Borland (en ese momento) decidió lanzar un dll en su lugar para acceder a la información de depuración para que pudieran cambiar el formato interno y no tener que actualizar la documentación. Desafortunadamente, no puedo localizar ni el documento original ni el dll en este momento. Le sugiero que se comunique con el soporte técnico de Embarcadero y pregunte al respecto.
500 - Error interno del servidor

Respuestas:

2

Compruebe si algún símbolo de depuración no estaba en binario. También es posible usar GDB (en Windows, un puerto del mismo). Sería genial si encontrara un archivo .dbg o .dSYM. Contienen código fuente, por ejemplo.

gdb> list foo
56 void foo()
57 {
58  bar();
59  sighandler_t fnc = signal(SIGHUP, SIG_IGN);
60  raise(SIGHUP);
61  signal(SIGHUP, fnc);
62  baz(fnc);
63 }

Si no tiene ningún archivo de depuración, puede intentar obtener MinGW o Cygwin y usar nm (1) ( página de manual ). Leerá los nombres de los símbolos del binario. Pueden contener algunos tipos, como los de C ++:

int abc::def::Ghi::jkl(const std::string, int, const void*)

No olvide agregar la --demangleopción entonces o obtendrá algo como:

__ZN11MRasterFont21getRasterForCharacterEh

en vez de:

MRasterFont::getRasterForCharacter(unsigned char)
Top Sekret
fuente
2
Jakub, gracias por la respuesta. Desafortunadamente, probablemente necesite leer un formato de depuración específico: TDS. Las aplicaciones Delphi no se compilan con información de depuración compatible con GDB en Windows. Tampoco estoy seguro de cómo ayudará nm, ya que dependerá de un formato de archivo de depuración específico que probablemente no sea el que genera Delphi. ¿O he entendido mal su respuesta? ¿Puede GDB leer los símbolos de Delphi, por ejemplo?
David
@DavidM, tu comentario es muy importante. Intente encontrar el puerto de GNU Binutils o GNU Debugger en Windows (solo conozco el puerto de Binutils). Hay una biblioteca BFD para GDB. También se usa en Binutils. Permite leer múltiples formatos de archivo y reconocerlos por sus números mágicos. Si todo falla, use la herramienta llamada strings. Extraerá cadenas de cualquier archivo binario. Consulte la página de manual . Esto imprimirá cadenas que pueden, pero no tienen que ser útiles
Top Sekret
0

Eche un vistazo al http://download.xskernel.org/docs/file%20formats/omf/borland.txt Open Architecture Handbook. Es antiguo, pero tal vez encuentre información relevante sobre el formato de archivo.

Muetze1
fuente
¿Puede agregar algo de contexto? Es posible que el enlace se rompa en el futuro.
Hintham
El enlace contiene el documento oficial de borland sobre el formato de archivo OMF utilizado por el compilador de Borland y otros formatos de archivo binarios utilizados por Borland. Hace algunos años, eché un vistazo al formato de archivo TDS y parecía que algunas partes eran compatibles con los formatos de archivo documentados. Al intentar recopilar información sobre las variables locales del archivo TDS, se debe utilizar o hacer referencia a la documentación vinculada. Si el enlace se rompe, mi respuesta será inútil y se perderá la información necesaria. El "Manual de arquitectura abierta" vinculado era parte de las versiones anteriores de Turbo Pascal y C.
Muetze1