[libunwind] 2366c6a - [libunwind][AIX] Implement _Unwind_FindEnclosingFunction() using traceback table on AIX

Xing Xue via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 12 15:09:23 PDT 2022


Author: Xing Xue
Date: 2022-08-12T18:07:56-04:00
New Revision: 2366c6adfc95e1aca9afbbbf5251a61552865b55

URL: https://github.com/llvm/llvm-project/commit/2366c6adfc95e1aca9afbbbf5251a61552865b55
DIFF: https://github.com/llvm/llvm-project/commit/2366c6adfc95e1aca9afbbbf5251a61552865b55.diff

LOG: [libunwind][AIX] Implement _Unwind_FindEnclosingFunction() using traceback table on AIX

Summary:
The implementation of  _Unwind_FindEnclosingFunction(void *ip) takes the context of itself and then uses the context to get the info of the function enclosing ip. This approach does not work for AIX because on AIX, the TOC base in GPR2 is used as the base for calculating relative addresses. Since  _Unwind_FindEnclosingFunction() may be in a different shared lib than the function containing ip, their TOC bases can be different. Therefore, using the value of GPR2 in the context from  _Unwind_FindEnclosingFunction() as the base results in incorrect addresses. On the other hand, the start address of a function is available in the traceback table following the instructions of each function on AIX. To get to the traceback table, search a word of 0 starting from ip and the traceback table is located after the word 0. This patch implements _Unwind_FindEnclosingFunction() for AIX by obtaining the function start address from its traceback table.

Reviewed by: compnerd, MaskRay, libunwind

Differential Revision: https://reviews.llvm.org/D131709

Added: 
    

Modified: 
    libunwind/src/UnwindLevel1-gcc-ext.c
    libunwind/src/Unwind_AIXExtras.cpp

Removed: 
    


################################################################################
diff  --git a/libunwind/src/UnwindLevel1-gcc-ext.c b/libunwind/src/UnwindLevel1-gcc-ext.c
index 0250664bbc7e..e24fcc3caddf 100644
--- a/libunwind/src/UnwindLevel1-gcc-ext.c
+++ b/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -22,6 +22,10 @@
 #include "Unwind-EHABI.h"
 #include "unwind.h"
 
+#if defined(_AIX)
+#include <sys/debug.h>
+#endif
+
 #if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
@@ -82,6 +86,32 @@ _Unwind_GetTextRelBase(struct _Unwind_Context *context) {
 /// specified code address "pc".
 _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
   _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
+#if defined(_AIX)
+  if (pc == NULL)
+    return NULL;
+
+  // Get the start address of the enclosing function from the function's
+  // traceback table.
+  uint32_t *p = (uint32_t *)pc;
+
+  // Keep looking forward until a word of 0 is found. The traceback
+  // table starts at the following word.
+  while (*p)
+    ++p;
+  struct tbtable *TBTable = (struct tbtable *)(p + 1);
+
+  // Get the address of the traceback table extension.
+  p = (uint32_t *)&TBTable->tb_ext;
+
+  // Skip field parminfo if it exists.
+  if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+    ++p;
+
+  if (TBTable->tb.has_tboff)
+    // *p contains the offset from the function start to traceback table.
+    return (void *)((uintptr_t)TBTable - *p - sizeof(uint32_t));
+  return NULL;
+#else
   // This is slow, but works.
   // We create an unwind cursor then alter the IP to be pc
   unw_cursor_t cursor;
@@ -94,6 +124,7 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
     return (void *)(intptr_t) info.start_ip;
   else
     return NULL;
+#endif
 }
 
 /// Walk every frame and call trace function at each one.  If trace function

diff  --git a/libunwind/src/Unwind_AIXExtras.cpp b/libunwind/src/Unwind_AIXExtras.cpp
index 7e47f70186e7..66194ab4a16b 100644
--- a/libunwind/src/Unwind_AIXExtras.cpp
+++ b/libunwind/src/Unwind_AIXExtras.cpp
@@ -38,7 +38,7 @@ char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
   if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
     p++;
 
-  // If the tb_offset field exisits, get the offset from the start of
+  // If the tb_offset field exists, get the offset from the start of
   // the function to pc. Skip the field.
   if (TBTable->tb.has_tboff) {
     unw_word_t StartIp =


        


More information about the cfe-commits mailing list