Good hint, thanks. For the module with the run-time error (I only consider run-time error exceptions here, not hardware fault exceptions), the compiler/linker embeds the source line number right in the code at the return address, so that case is covered. The modules in the stack trace need another approach -- here the formula that works for hardware fault exceptions should work.
Here's the relevant code for the stack trace:
Code: Select all
TYPE
ModuleName* = ARRAY 16 OF CHAR;
TracePoint* = RECORD
moduleName*: ModuleName;
address*: INTEGER
END;
Trace* = RECORD
tp*: ARRAY TraceDepth + 1 OF TracePoint;
count*: INTEGER
END;
PROCEDURE stackTrace(fpAddr: INTEGER; VAR trace: Trace);
(* called from the run-time error handler *)
VAR
lr: INTEGER;
BEGIN
trace.count := 0;
SYSTEM.GET(fpAddr, fpAddr);
REPEAT
SYSTEM.GET(fpAddr + 4, lr);
GetModuleName(lr - 4, trace.tp[trace.count].moduleName);
trace.tp[trace.count].address := lr - 4;
INC(trace.count);
SYSTEM.GET(fpAddr, fpAddr);
UNTIL (fpAddr >= LinkOptions.StackStart - 8) OR (trace.count = TraceDepth);
(* handling of the case when the stack trace would be deeper than TraceDepth *)
END stackTrace;
PROCEDURE runtimeErrorHandler[0];
(* called via SVC *)
BEGIN
(* getting info on the offending module, similar to Traps.mod *)
stackTrace(SYSTEM.FP + 56, errorDesc.trace);
errorHandler(errorDesc)
END runtimeErrorHandler;
I retrieve the link register values on the stack and subtract 4 to find the calling procedure. For a test case, I get the following, using 'ASSERT(FALSE, Error.Trace)', with Error.Trace defined as 100 and the message below message (the annotations as comments are not part of the real output):
Code: Select all
code: 100
message: stack trace
module: DisplayTask
line: 43
address: 08005298H
trace: (* format: 'module name': 'address' from link register minus 4 *)
Task1: 08005AE5H (* test task *)
Tasks: 080046B1H (* task scheduler *)
M: 08005C35H (* main module *)
Applying the formula to find the calling procedure, without the '-8' correction, I get these offsets:
Now, let's check.
Code: Select all
(* case 1: from Task1.mod *)
DisplayTask.SetNumItem(0, r);
. 28 F2400B00H mov r11,0
. 32 F85CAC04H ldr r10,[fp,-4]
. 36 04010000H bl Proc #1
37 looks fine, even though I don't fully understand yet why it's not 36.
Code: Select all
(* case 2: from Tasks.mod *)
ct.taskState;
. 1856 F8DFB000H ldr r11,[pc+offset] <Global:4>
. 1860 F8DBB000H ldr r11,[r11]
. 1864 F8DBB000H ldr r11,[r11]
. 1868 EA4F000BH mov r0,r11
. 1872 3001H add r0,1
. 1874 4780H blx r0
1873 looks off in this case. 'ct.taskState' refers to a procedure variable. I realise that subtracting 4 from the link register value causes this.
Code: Select all
(* case 3: from M.mod *)
Tasks.Go
. 196 040F0027H bl Proc #15
Same as with case 1, Task1.mod.
Apologies for going on that long, but I thought I'd present the details to finally ask my questions.
1) Do you see any flaws or hidden issues in creating the stack trace as above?
2) Why exactly is the offset off by 1 for cases 1 and 3?
3) Can I detect case 2, and subtract only 2 from the link register value?
Depending on the structure and contents of an extended ".ref" ResData, I probably do not even need to do the subtractions from the link registers if the goal is to identify the procedure name in the source code.
Thanks!