Access JCL Debug information contained in executable?

情到浓时终转凉″ 提交于 2019-12-01 09:34:09

Create a TJclDebugInfoBinary object, using the HModule handle you get from LoadLibrary. Then call GetLocationInfo on it. That's all TJclDebugInfoList would have done anyway, except it has some helper methods to map addresses from the current address space to the modules they correspond to, whereas when you do it manually, you'll have to already know which module the addresses belong to. (But the crash dump already told you that part, so you don't need the help of the list class.)

You'll probably have to massage the addresses because the base address of the module at the time of the crash is not going to be the same as when you've loaded it with LoadLibrary.

The JCL debug information is not stored in a resource. It's stored in a PE section named JCLDEBUG. See the uses of PeMapImgFindSection32 and PeMapImgFindSectionFromModule in JclDebug.pas.

I made such a tool a while ago, don't know if I can find it back again, but at least it is possible :-)

On the other hand, I made several tools using jclDebug.pas, and now I remember: I made some changes to it to make "offline" stack tracing possible. You can take a look at these:

Live Process Stack Viewer: http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

Minidump reader (using offline reading .map or embedded jdbg info from exe): http://code.google.com/p/asmprofiler/source/browse/#svn%2Ftrunk%2FMiniDumpReader

Here's the code can give debug information about an address in a module

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;

And a practical example, an offset from Process Explorer:

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

returns:

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

Or in the style of JclDebug:

[0266CB17] BalloonHint.TBalloonHint.SetVisible (Line 281, "BalloonHint.pas") + $0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!