Root > Solving bugs in your code > Bug reports > Call Stack section > How to read call stacks

How to read call stacks

Previous pageReturn to chapter overviewNext page   

This article is a part of working with bug reports.

 

Call stack is set of lines, which is usually read from top to bottom - meaning moving from current locations to callers. The bottom line was executed first. The top line is executed last and it is the current routine.

 

For example, if you have this call stack (short pseudo form):

 

DoSomething
DoWork
Run

 

This means that Run procedure was executed first. Run called DoWork, which in turn called DoSomething. DoSomething encountered an error - and this call stack was created. The code for such call stack may look like this:

 

procedure DoSomething;
begin
  PInteger(nil)^ := 0; // <- exception here, 

  // call stack was created from this point
end;
 
procedure Run;
 
  procedure DoWork;
  begin
    DoSomething;
  end;
 
begin
  DoWork;
end;

 

In other words, this call stack means that execution of your code goes through this way: Run -> DoWork -> DoSomething -> error.

 

Each line in call stack can contain this information (some parts are optional and may be missed in the specific call stack format):

 

Code address. Those are values like 004D316F or 76BCF6A5 (and also with '$' or '0x' prefix - like $004D316F or 0x004D316F). This is an absolute address in HEX-form of the code, which contains a routine's call. This value is present almost always, unless it's replaced with textual description (unit and routines names). Please note, that some stack tracing methods actually provide "return address" as code address. In other words, this value points to next instruction after call.
Stack address. Those are values like 0018F628 or 0228FF84. It is an address (in HEX format) inside thread's stack, where return address was found. This value is present very rarely. Usually it follows or precedes code address.
Executable module name. Those are values like 'Project1.exe' and 'ntdll.dll'. It's a file name of executable module, which contains code address. In rare cases can be '' (empty string) - that is, the code doesn't belong to any module (like run-time generated, self-modified code, etc). Such case is rare in typical application.
Code offset. Those are values like 000D316F or +D316F. It's a difference (usually in HEX format) between code address and base address of executable module name. For example, base address of exe is usually 00400000, which means that offset for code address 004D316F is D316F - because 00400000 + 000D316F = 004D316F. Sometimes this value represents offset from start of code section. Code section itself has offset of $1000, so in this case - code offset D216F means 00400000 + 00001000 + 000D316F = 004D316F.
Unit name. Those are values like 'Project1' or 'Project1.dpr', 'Unit1.pas' and so forth. It's the name of Delphi or C++ Builder unit, which contains code, associated with code address. Can be '' (empty string), if there is no debug information available to set "code address" <-> "pas source" correspondence.
Class name. Those are values like 'TForm1' or 'TMyClass'. It's name of class, which contains method with code address. Can be empty if there is no debug information available or if code address belongs to usual function or procedure (not to method). Sometimes can be combined with next item.
Method or routine name. Those are values like 'Button1Click', 'DoSomething', etc. It's the name of method, procedure or function, which contains code address. Can be empty, if there is no debug information.
Line number. Those are values like 39, 458, 31958, etc. It's # of line in .pas/.dpr/.cpp file, which compiles into code address. Can be 0, if there is no debug information.
Line number offset. Those values like +0, +1, +5, etc. It's difference (usually in DEC) between line number and first line in current method (in lines). For example, if code address points to third line in procedure DoSomething, which starts at line 89, then line number will be 92 and line number offset will be +3 (since 89 + 3 = 92). There can be +/-1 line difference, depending on how lines are calculated. A detailed explanation on offsets can be found in this article.
Code offset from procedure's start. Those values like +16, + $5 or +$0. Usually it's in HEX format. It's difference between code address and address of first line in current method (in bytes).

 

See next part to know how to extract these part of information from various formats of call stacks or skip to article about searching bug's location.

 

 

See also:




Send feedback... Build date: 2023-09-11
Last edited: 2023-08-09
PRIVACY STATEMENT
The documentation team uses the feedback submitted to improve the EurekaLog documentation. We do not use your e-mail address for any other purpose. We will remove your e-mail address from our system after the issue you are reporting has been resolved. While we are working to resolve this issue, we may send you an e-mail message to request more information about your feedback. After the issues have been addressed, we may send you an email message to let you know that your feedback has been addressed.


Permanent link to this article: https://www.eurekalog.com/help/eurekalog/how_to_read_call_stacks.php