Доступ к отладочной информации JCL, содержащейся в исполняемом файле? - PullRequest
3 голосов
/ 16 мая 2011

Есть ли способ получить доступ к информации отладки джедая (JDBG), содержащейся в исполняемом файле?

Инструменты отладки Microsoft указали мне на цепочку стеков в моем двоичном файле, и я хочу знать, каким методам / процедурам / функциям соответствуют эти смещения:

user32.dll!SendMessageA+0x4c
StackOverflow.exe+0x179263
StackOverflow.exe+0x2315b5
StackOverflow.exe+0x1fc82
StackOverflow.exe+0x50388
StackOverflow.exe+0x541fe
user32.dll!gapfnScSendMessage+0x332

Очевидно, я звоню SendMessage, но я не знаю откуда. Исполняемый файл был собран с информацией отладки Jcl, встроенной в исполняемый файл; но я не могу понять, как это читать.

Глядя на некоторые функции и классы в JclDebug.pas, кажется, что все ориентировано на получение отладочной информации внутри текущего процесса, например ::

function GetLocationInfo(const Addr: Pointer; var Info: TJclLocationInfo): Boolean;

принимает адрес в адресном пространстве моего текущего процесса. Это определяет, в каком HMODULE адресе находится, например ::

  • Stackoverflow.exe
  • GDI32.dll
  • USER32.dll
  • KERNELBASE.dll
  • dwmapi.dll
  • UXTheme.dll

я думал, что мог бы использовать LoadLibrary (который возвращает HMODULE), чтобы вручную загрузить модуль, а затем передать его некоторым классам, которые копают образы модулей для отладочной информации:

module := LoadLibrary('C:\Users\Ian\Desktop\StackOverflow.exe');

и

TJclDebugInfoList = class(TObjectList)
private
   function GetItemFromModule(const Module: HMODULE): TJclDebugInfoSource;
   ...
protected
   function CreateDebugInfo(const Module: HMODULE): TJclDebugInfoSource;
   ...
end;

кроме случаев, когда он защищен.

Я пытаюсь (надеюсь), я могу написать инструмент, где я выбираю двоичный файл (* .exe), введите адрес и получить

  • функция
  • метод
  • файл
  • номер строки

смещения.

например.

[002315B5] FMain.TfrmMain.lvQuestions (Line 158, "FMain.pas" + 1) + $11

возможно?


Редактировать: Моим первым грубым и готовым подходом было просто извлечь сжатый файл map, чтобы я мог посмотреть на него. Но он не сохраняется как ресурс (? ):

enter image description here

Хотя общий инструмент был бы более полезен:

enter image description here


Update :

я пытался использовать TJclDebugInfoList; я понял, что свойство массива ItemFromModule будет обращаться к защищенному методу:

function GetModuleLocationInfo(filename: string; Addr: Pointer): TJclLocationInfo;
var
   module: HMODULE;
   infoList: TJclDebugInfoList;
   infoSource: TJclDebugInfoSource;

   Address: Pointer;
   locationInfo: TJclLocationInfo;
   AddressOffset: Integer;
begin
   module := LoadLibrary(filename);
   if module = 0 then
      RaiseLastWin32Error;
   try
      infoList := TJclDebugInfoList.Create;
      try
         infoSource := infoList.ItemFromModule[module];
         if source = nil then
            raise Exception.Create('Could not find debug info source for module '+IntToStr(module));
         if not source.GetLocationInfo(Addr, {var}locationInfo) then
            raise Exception.Create('Could not get location info for address $'+IntToHex(Integer(Address), 8));

         Result := locationInfo;
      finally
         infoList.Free;
      end;
   finally
      FreeLibrary(module);
   end;
end;

За исключением того, что код в одном из классов-потомков TJclDebugInfoSource получает недостаточное значение, когда пытается преобразовать виртуальный адрес в адрес смещения.

Ответы [ 3 ]

2 голосов
/ 17 мая 2011

Создайте объект TJclDebugInfoBinary, используя дескриптор HModule, полученный из LoadLibrary. Затем назовите GetLocationInfo. Это все, что TJclDebugInfoList сделал бы в любом случае, за исключением того, что у него есть несколько вспомогательных методов для сопоставления адресов из текущего адресного пространства с модулями, которым они соответствуют, тогда как, когда вы делаете это вручную, вы уже должны знать, какому модулю принадлежат адреса к. (Но аварийный дамп уже говорил вам об этой части, поэтому вам не нужна помощь класса list.)

Возможно, вам придется помассировать адреса, потому что базовый адрес модуля во время сбоя не будет таким же, как при загрузке его с помощью LoadLibrary.

Информация об отладке JCL не сохраняется в ресурсе. Он хранится в разделе PE с именем JCLDEBUG. См. Использование PeMapImgFindSection32 и PeMapImgFindSectionFromModule в JclDebug.pas .

1 голос
/ 27 октября 2011

Вот код, который может дать отладочную информацию об адресе в модуле

function GetModuleLocationInfo(filename: string; AddressOffset: Pointer; AssumeOffsetIsRelativeToStartOfCodeSection: Boolean=False): TJclLocationInfo;
var
    module: HMODULE;
    infoList: TJclDebugInfoList;
    infoSource: TJclDebugInfoSource;

    Address: Pointer;
    locationInfo: TJclLocationInfo;
begin
    //Code is public domain. No attribution required.
    module := LoadLibrary(PChar(filename));
    if module = 0 then
        RaiseLastWin32Error;
    try
        infoList := TJclDebugInfoList.Create;
        try
            infoSource := infoList.ItemFromModule[module];
            if infoSource = nil then
                raise Exception.Create('Could not find debug info source for module '+IntToStr(module));

            DWORD(Address) := DWORD(AddressOffset) + DWORD(module) + DWORD(ModuleCodeOffset);
            if not infoSource.GetLocationInfo(Address, {var}locationInfo) then
                raise Exception.Create('Could not get location info for address $'+IntToHex(Integer(Address), 8));

            Result := locationInfo;
        finally
            infoList.Free;
        end;
    finally
        FreeLibrary(module);
    end;
end;

И на практическом примере смещение из Process Explorer:

enter image description here

GetModuleLocationInfo('C:\Program Files (x86)\Avatar\HelpDesk.exe', 0xdcb17);

возвращает:

TJclLocationInfo
   Address: $266CB17
   UnitName: 'BalloonHint'
   ProcedureName: 'TBalloonHint.SetVisible'
   OffsetFromProcName: 83
   LineNumber: 281
   OffsetFromLineNumber: 0
   SourceName: 'BalloonHint.pas'
   DebugInfo: $1F25C74

Или в стиле JclDebug:

[0266CB17] BalloonHint.TBalloonHint.SetVisible (строка 281, «BalloonHint.pas») +0

1 голос
/ 18 мая 2011

Я сделал такой инструмент некоторое время назад, не знаю, смогу ли я найти его снова, но, по крайней мере, это возможно: -)

С другой стороны, я создал несколько инструментов, используя jclDebug.pas, и теперь я помню: я внес в него некоторые изменения, чтобы сделать возможной автономную трассировку стека. Вы можете взглянуть на это:

Просмотр процесса в реальном времени: http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

Считыватель мини-дампов (с использованием автономного чтения .map или встроенной информации jdbg из exe): http://code.google.com/p/asmprofiler/source/browse/#svn%2Ftrunk%2FMiniDumpReader

...