Skip to content

Commit 2366c6a

Browse files
committed
[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
1 parent 3329cec commit 2366c6a

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

libunwind/src/UnwindLevel1-gcc-ext.c

+31
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
#include "Unwind-EHABI.h"
2323
#include "unwind.h"
2424

25+
#if defined(_AIX)
26+
#include <sys/debug.h>
27+
#endif
28+
2529
#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
2630

2731
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
@@ -82,6 +86,32 @@ _Unwind_GetTextRelBase(struct _Unwind_Context *context) {
8286
/// specified code address "pc".
8387
_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
8488
_LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
89+
#if defined(_AIX)
90+
if (pc == NULL)
91+
return NULL;
92+
93+
// Get the start address of the enclosing function from the function's
94+
// traceback table.
95+
uint32_t *p = (uint32_t *)pc;
96+
97+
// Keep looking forward until a word of 0 is found. The traceback
98+
// table starts at the following word.
99+
while (*p)
100+
++p;
101+
struct tbtable *TBTable = (struct tbtable *)(p + 1);
102+
103+
// Get the address of the traceback table extension.
104+
p = (uint32_t *)&TBTable->tb_ext;
105+
106+
// Skip field parminfo if it exists.
107+
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
108+
++p;
109+
110+
if (TBTable->tb.has_tboff)
111+
// *p contains the offset from the function start to traceback table.
112+
return (void *)((uintptr_t)TBTable - *p - sizeof(uint32_t));
113+
return NULL;
114+
#else
85115
// This is slow, but works.
86116
// We create an unwind cursor then alter the IP to be pc
87117
unw_cursor_t cursor;
@@ -94,6 +124,7 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
94124
return (void *)(intptr_t) info.start_ip;
95125
else
96126
return NULL;
127+
#endif
97128
}
98129

99130
/// Walk every frame and call trace function at each one. If trace function

libunwind/src/Unwind_AIXExtras.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
3838
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
3939
p++;
4040

41-
// If the tb_offset field exisits, get the offset from the start of
41+
// If the tb_offset field exists, get the offset from the start of
4242
// the function to pc. Skip the field.
4343
if (TBTable->tb.has_tboff) {
4444
unw_word_t StartIp =

0 commit comments

Comments
 (0)