Files
clang-p2996/libunwind/src/Unwind_AIXExtras.cpp
Xing Xue 2366c6adfc [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
2022-08-12 18:07:56 -04:00

64 lines
1.8 KiB
C++

//===--------------------- Unwind_AIXExtras.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
//===----------------------------------------------------------------------===//
// This file is only used for AIX.
#if defined(_AIX)
#include "config.h"
#include "libunwind_ext.h"
#include <sys/debug.h>
namespace libunwind {
// getFuncNameFromTBTable
// Get the function name from its traceback table.
char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
unw_word_t *Offset) {
uint32_t *p = reinterpret_cast<uint32_t *>(Pc);
*Offset = 0;
// Keep looking forward until a word of 0 is found. The traceback
// table starts at the following word.
while (*p)
p++;
tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
if (!TBTable->tb.name_present)
return NULL;
// Get to the name of the function.
p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
// Skip field parminfo if it exists.
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
p++;
// 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 =
reinterpret_cast<uintptr_t>(TBTable) - *p - sizeof(uint32_t);
*Offset = Pc - StartIp;
p++;
}
// Skip field hand_mask if it exists.
if (TBTable->tb.int_hndl)
p++;
// Skip fields ctl_info and ctl_info_disp if they exist.
if (TBTable->tb.has_ctl) {
p += 1 + *p;
}
NameLen = *(reinterpret_cast<uint16_t *>(p));
return reinterpret_cast<char *>(p) + sizeof(uint16_t);
}
} // namespace libunwind
#endif // defined(_AIX)