View Issue Details

IDProjectCategoryView StatusLast Update
0037583FPCRTLpublic2020-08-17 18:34
ReporterChristo Crause Assigned ToFlorian  
PrioritynormalSeverityminorReproducibilityN/A
Status closedResolutionfixed 
Product Version3.3.1 
Fixed in Version3.3.1 
Summary0037583: Xtensa [patch] Add support for windowed ABI stack dump
DescriptionAdd support for ESP32 stack dump functionality so that stack trace can be generated on error.

Modifications:
Consoleio.pp - fix call signature for dump_stack so that correct overloaded function gets called.
System.pp - wrap function StackTop in ifdef so that alternative StackTop can be provided for xtensa. dump_stack checks frame pointer against StackTop for validity so it needs to be realistic. Probably temporary until freertos is integrated with RTL.
xtensa.inc - added code to extract frame and caller addresses from stack for windowed ABI.

Note: the current stack trace starts one level above where e.g. RunError() is called because the caller's frame pointer is stored in the current frame, but the caller's return address is stored in a live register.
TagsNo tags attached.
Fixed in Revision46463
FPCOldBugId
FPCTarget-
Attached Files

Activities

Christo Crause

2020-08-16 21:05

reporter  

stackdump.patch (5,034 bytes)   
Index: rtl/freertos/consoleio.pp
===================================================================
--- rtl/freertos/consoleio.pp	(revision 46462)
+++ rtl/freertos/consoleio.pp	(working copy)
@@ -169,7 +169,7 @@
      Writeln(pstdout^,'Runtime error ',Errorcode,' at $',hexstr(erroraddr));
      { to get a nice symify }
      Writeln(pstdout^,BackTraceStrFunc(Erroraddr));
-     dump_stack(pstdout^,ErrorBase);
+     dump_stack(pstdout^,ErrorBase,erroraddr);
      Writeln(pstdout^,'');
    End;
   SysFlushStdIO;
Index: rtl/freertos/system.pp
===================================================================
--- rtl/freertos/system.pp	(revision 46462)
+++ rtl/freertos/system.pp	(working copy)
@@ -208,6 +208,7 @@
 {*****************************************************************************
                        Misc. System Dependent Functions
 *****************************************************************************}
+{$ifndef FPC_SYSTEM_HAS_STACKTOP}
 var
  _stack_top: record end; external name '_stack_top';
 
@@ -215,6 +216,7 @@
 begin
   StackTop:=@_stack_top;
 end;
+{$endif FPC_SYSTEM_HAS_STACKTOP}
 
 
 procedure haltproc;cdecl;external name '_haltproc';
Index: rtl/xtensa/xtensa.inc
===================================================================
--- rtl/xtensa/xtensa.inc	(revision 46462)
+++ rtl/xtensa/xtensa.inc	(working copy)
@@ -31,27 +31,114 @@
     SysInitFPU;
 end;
 
+{$ifdef fpc_abi_windowed}
+const
+  // Minimum call8 calls to force register spilling to stack for caller of forceSpilledRegs
+  spillcount = 6;
 
-{$IFNDEF INTERNAL_BACKTRACE}
-{$define FPC_SYSTEM_HAS_GET_FRAME}
-function get_frame:pointer;assembler;nostackframe;
+procedure forceSpilledRegs(n: uint32); assembler; public name 'forcespilledregs';
+  label
+    done, fin;
   asm
+    beqz a2, done
+    addi a10, a2, -1
+    call8 forcespilledregs
+    done:
+    bnez a2, fin
+    movi a15, 0
+    fin:
   end;
+
+procedure fixCodeAddress(var addr: pointer);
+  begin
+    // Check if valid code address
+    if ptruint(addr) and $C0000000 >= $40000000 then
+      begin
+        // Replace windowed call prefix
+        addr:=codepointer((ptruint(addr)and$00FFFFFF) or $40000000);
+        // Rewind to call instruction address
+        dec(addr,3);
+      end
+    else
+      addr:=nil;
+  end;
+{$endif fpc_abi_windowed}
+
+{$IFNDEF INTERNAL_BACKTRACE}
+  {$define FPC_SYSTEM_HAS_GET_FRAME}
+  function get_frame:pointer;assembler;
+    label
+      done;
+    asm
+      {$ifdef fpc_abi_windowed}
+        // Force registers to spill onto stack
+        movi a10, spillcount
+        call8 forcespilledregs
+        // now get frame pointer of caller
+        addi a2, a1, -12
+        l32i a2, a2, 0
+        done:
+      {$else}
+        mov a2, a1
+      {$endif}
+    end;
 {$ENDIF not INTERNAL_BACKTRACE}
 
 
 {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
-function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;assembler;nostackframe;
-  asm
+function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;
+  begin
+    {$ifdef fpc_abi_windowed}
+      forceSpilledRegs(spillcount);
+      if (ptruint(framebp)>$3ff00000)and(ptruint(framebp)<$40000000) then
+        begin
+          get_caller_addr:=pointer((framebp-16)^);
+          fixCodeAddress(get_caller_addr);
+        end
+      else
+        get_caller_addr:=nil;
+    {$else}
+      get_caller_addr:=nil;
+    {$endif}
   end;
 
-
 {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
-function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler;nostackframe;
-  asm
+function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;
+  begin
+    {$ifdef fpc_abi_windowed}
+      if (ptruint(framebp)>$3ff00000)and(ptruint(framebp)<$40000000) then
+        begin
+          forceSpilledRegs(spillcount);
+          get_caller_frame:=pointer((framebp-12)^);
+        end
+      else
+        get_caller_frame:=nil;
+    {$else}
+      get_caller_frame:=nil;
+    {$endif}
   end;
 
 
+{$ifdef fpc_abi_windowed}
+  {$define FPC_SYSTEM_HAS_GET_CALLER_STACKINFO}
+  procedure get_caller_stackinfo(var framebp : pointer; var addr : codepointer);
+    begin
+      if (ptruint(framebp)>$3ff00000)and(ptruint(framebp)<$40000000) then
+        begin
+          forceSpilledRegs(spillcount);
+          addr:=codepointer((framebp-16)^);
+          framebp := pointer((framebp-12)^);
+          fixCodeAddress(addr);
+        end
+      else
+        begin
+          addr:=nil;
+          framebp:=nil;
+        end;
+    end;
+{$endif fpc_abi_windowed}
+
+
 {$define FPC_SYSTEM_HAS_SPTR}
 Function Sptr : pointer;assembler;
   asm
@@ -59,6 +146,16 @@
   end;
 
 
+{$define FPC_SYSTEM_HAS_STACKTOP}
+// Interim fix for now, set to large address
+// TODO: provide more realistic value, possibly by inspecting stack pointer
+// when main or task is started
+function StackTop: pointer;
+  begin
+    StackTop:=pointer($3fffffff);
+  end;
+
+
 function InterLockedDecrement (var Target: longint) : longint;
   var
     temp_sreg : byte;
stackdump.patch (5,034 bytes)   

Florian

2020-08-16 23:05

administrator   ~0124935

Thanks, applied.

Christo Crause

2020-08-17 18:33

reporter   ~0124952

Thanks!

Issue History

Date Modified Username Field Change
2020-08-16 21:05 Christo Crause New Issue
2020-08-16 21:05 Christo Crause File Added: stackdump.patch
2020-08-16 23:05 Florian Assigned To => Florian
2020-08-16 23:05 Florian Status new => resolved
2020-08-16 23:05 Florian Resolution open => fixed
2020-08-16 23:05 Florian Fixed in Version => 3.3.1
2020-08-16 23:05 Florian Fixed in Revision => 46463
2020-08-16 23:05 Florian FPCTarget => -
2020-08-16 23:05 Florian Note Added: 0124935
2020-08-17 18:33 Christo Crause Note Added: 0124952
2020-08-17 18:34 Christo Crause Status resolved => closed