is it possible to get source line number at runtime in Delphi? I know JCL debug, but I want to avoid to use it. Also Assert is not exactly what I want. I would like to get s
For our logging and exception tracing classes, we made a .map parser and reader.
A .map can be parsed into a binary compressed version (.mab proprietary format), which is much smaller than the original .map. For instance, a 900 KB .map file is compressed into a 70 KB .mab file - this is a much higher compression than zip.
This .mab content can be appended to the .exe, without any difference at execution, or for the end-user.
Then you can use our logging classes, or directly the .map/.mab reader class, TSynMapFile
.
You have the following methods at hand:
/// retrieve a .map file content, to be used e.g. with TSynLog to provide
// additional debugging information
// - original .map content can be saved as .mab file in a more optimized format
TSynMapFile = class
public
/// get the available debugging information
// - will first search for a .map file in the .exe directory: if found,
// will be read to retrieve all necessary debugging information - a .mab
// file will be also created in the same directory (if MabCreate is TRUE)
// - if .map is not not available, will search for the .mab file in the
// .exe directory
// - if no .mab is available, will search for a .mab appended to the exe
// - if nothing is available, will log as hexadecimal pointers, without
// debugging information
// - if aExeName is not specified, will use the current process executable
constructor Create(const aExeName: TFileName=''; MabCreate: boolean=true);
/// save all debugging information in the .mab custom binary format
// - if no file name is specified, it will be saved as ExeName.mab
// - this file content can be appended to the executable via SaveToExe method
// - this function returns the created file name
function SaveToFile(const aFileName: TFileName=''): TFileName;
/// save all debugging informat in our custom binary format
procedure SaveToStream(aStream: TStream);
/// append all debugging information to an executable
// - the executable name must be specified, because it's impossible to
// write to the executable of a running process
procedure SaveToExe(const aExeName: TFileName);
/// add some debugging information according to the specified memory address
// - will create a global TSynMapFile instance for the current process, if
// necessary
// - if no debugging information is available (.map or .mab), will write
// the address as hexadecimal
class procedure Log(W: TTextWriter; Addr: PtrUInt);
/// retrieve a symbol according to an absolute code address
function FindSymbol(aAddr: cardinal): integer;
/// retrieve an unit and source line, according to an absolute code address
function FindUnit(aAddr: cardinal; out LineNumber: integer): integer;
/// return the symbol location according to the supplied absolute address
// - i.e. unit name, symbol name and line number (if any), as plain text
// - returns '' if no match found
function FindLocation(aAddr: Cardinal): RawUTF8;
/// all symbols associated to the executable
property Symbols: TSynMapSymbolDynArray read fSymbol;
/// all units, including line numbers, associated to the executable
property Units: TSynMapUnitDynArray read fUnit;
published
/// the associated file name
property FileName: TFileName read fMapFile;
/// equals true if a .map or .mab debugging information has been loaded
property HasDebugInfo: boolean read fHasDebugInfo;
end;
Thanks to this class, in just one unit, you'll have all the source code line of any location.
Open source, and working with Delphi 5 up to XE (note that the .map format changed a little bit from old to newer versions - our class try to handle it).