Borland's linker optionally creates a *.map file every time it links a
project (a little example map file can be found
here). Such a map file contains a lot of
useful information. The unit "madMapFile" features functionality to parse
those map files, search through the information and export the most
important bits of information to (and import from) a compressed and encrypted
string stream. A full list of what is contained in this unit can be found
in the madMapFile Reference.
The class "TMapFile" handles the most important pieces of information of a
map file:
|
type TMapFile = class;
|
|
There are several ways to get a TMapFile instance. The function
"FindMapFile" lets you find the map file that belongs to a specific address.
This address can be a code address, a data address or a HInstance value. If
you just want to get the map file of the current module (application or
dll), simply don't enter anything.
"FindMapFile" first checks in which module the specified address is located.
Then it checks whether that module file has an appended map file. If not, it
looks for a seperate map file with the same name as the module file. The
seperate file can either be a compressed and encrypted ".mad" file or the
uncompressed plain text ".map" file.
|
function FindMapFile (addr: pointer = nil) : TMapFile;
mf := FindMapFile;
mf := FindMapFile(pointer(GetModuleHandle('your.dll' )));
mf := FindMapFile(pointer(GetModuleHandle('user32.dll')));
|
|
The function "LoadMapFile" loads and parses the specified external map
file. The map file can either be a compressed and encrypted ".mad" file or
the uncompressed plain text ".map" file.
|
function LoadMapFile (mapFile: string) : TMapFile;
|
|
The functions FindMapFile and LoadMapFile can succeed or fail,
of course. If they succeed, you get a valid TMapFile instance back. Please
do *not* destroy it, it's internally cached to speed things up. madMapFile
automatically frees it when your module (exe/dll) is unloaded. If the
functions mentioned above fail, you nevertheless get a map file instance
back, but this time it's invalid and you are supposed to free it again. You
can check the following property to find out whether the returned TMapFile
instance is valid or not:
|
property TMapFile.IsValid : boolean;
var mf : TMapFile;
begin
mf := FindMapFile;
if mf.IsValid then
ShowMessage('map file found, do not free it!')
else
mf.Free;
|
|
Given a specific address, you can search for all the information that is
available for this address. First we have "segments". Each unit can have one
or more segments. A segment is either a code segment or a data segment. Then
we have "publics", which are variable and function names. Finally we have
line number information and the entry point.
|
type
TMfSegment = record
IsValid : boolean;
Code : boolean;
StartAddress : pointer;
Length : dword;
Unit_ : string;
LineNumbers : boolean;
end;
type
TMfPublic = record
IsValid : boolean;
Code : boolean;
Name : string;
Address : pointer;
end;
function TMapFile.FindSegment (code: boolean; address: pointer) : TMfSegment;
function TMapFile.FindPublic ( address: pointer) : TMfPublic;
function TMapFile.FindLine ( address: pointer) : integer;
property TMapFile.EntryPoint : pointer;
|
|
If you need to save the map file in a compressed version to save space, you
can use the method "Export". The map file stream coming from the "Export"
function is zipped and encrypted. Beginning with madExcept 2.7h you can
choose between exporting the map file in a "new" or in an "old" format. The
old format is that which was and still is used in all madExcept 2.x builds.
The new format is used by madExcept 3.x. If you export with the new format,
you can optionally decide to only export minimal debug information. That
means, no function names are exported and no line numbers, either.
The parameter "hideUglyItems" lets you specify whether you want
functions/methods to be stored even if there's no line number information
available for them. Set the parameter to "true" to exclude such
functions/methods from being exported.
|
function TMapFile.Export (newFormat : boolean;
minDebugInfoOnly : boolean;
hideUglyItems : boolean = false) : string;
|
|
Some properties to get more informations about the map file, respectively
about the module, to which the map file belongs:
|
property TMapFile.BaseOfCode : dword;
property TMapFile.TopOfCode : dword;
property TMapFile.ModuleFileName : string;
property TMapFile.MapFileName : string;
|
|
In order to make your life a bit easier, I've added the function
"GetMapFileInfos", which will return all important pieces of information
about a specific code address. You could collect the same information by
using the TMapFile class, but it would be quite a bit more work.
|
function GetMapFileInfos (address : pointer;
var moduleName : string;
var unitName : string;
var publicName : string;
var publicAddr : pointer;
var line : integer) : boolean;
|
|
If you want to get information about the current function, simply call
"GetMyProcName":
|
function GetMyProcName (includeLineNumber : boolean = false) : string;
GetMyProcName -> 'yourUnit.yourFunction (105)'
|
|