summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/base/elfcore.h19
-rw-r--r--src/base/linux_syscall_support.h199
-rw-r--r--src/base/linuxthreads.cc10
-rw-r--r--src/heap-checker.cc14
-rw-r--r--src/stacktrace_powerpc-inl.h139
-rw-r--r--src/tests/heap-checker_unittest.cc25
6 files changed, 234 insertions, 172 deletions
diff --git a/src/base/elfcore.h b/src/base/elfcore.h
index 34a96de..122fbb1 100644
--- a/src/base/elfcore.h
+++ b/src/base/elfcore.h
@@ -37,11 +37,11 @@
extern "C" {
#endif
-/* We currently only support x86-32, x86-64, ARM, and MIPS on Linux.
+/* We currently only support x86-32, x86-64, ARM, MIPS, PPC on Linux.
* Porting to other related platforms should not be difficult.
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \
- defined(__mips__)) && defined(__linux)
+ defined(__mips__) || defined(__PPC__)) && defined(__linux)
#include <stdarg.h>
#include <stdint.h>
@@ -108,6 +108,21 @@ extern "C" {
unsigned long cp0_cause;
unsigned long unused;
} mips_regs;
+#elif defined (__PPC__)
+ typedef struct ppc_regs {
+ #define SP uregs[1] /* Stack pointer */
+ #define IP rip /* Program counter */
+ #define LR lr /* Link register */
+ unsigned long uregs[32]; /* General Purpose Registers - r0-r31. */
+ double fpr[32]; /* Floating-Point Registers - f0-f31. */
+ unsigned long rip; /* Program counter. */
+ unsigned long msr;
+ unsigned long ccr;
+ unsigned long lr;
+ unsigned long ctr;
+ unsigned long xeq;
+ unsigned long mq;
+ } ppc_regs;
#endif
#if defined(__i386__) && defined(__GNUC__)
diff --git a/src/base/linux_syscall_support.h b/src/base/linux_syscall_support.h
index d768471..b3fc8a3 100644
--- a/src/base/linux_syscall_support.h
+++ b/src/base/linux_syscall_support.h
@@ -130,7 +130,7 @@
#ifndef SYS_LINUX_SYSCALL_SUPPORT_H
#define SYS_LINUX_SYSCALL_SUPPORT_H
-/* We currently only support x86-32, x86-64, ARM, MIPS, and PPC on Linux.
+/* We currently only support x86-32, x86-64, ARM, MIPS, and PPC/PPC64 on Linux.
* Porting to other related platforms should not be difficult.
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
@@ -333,23 +333,21 @@ struct kernel_stat64 {
struct kernel_stat64 {
unsigned long long st_dev;
unsigned long long st_ino;
- unsigned st_mode;
unsigned st_nlink;
+ unsigned st_mode;
unsigned st_uid;
unsigned st_gid;
+ int __pad2;
unsigned long long st_rdev;
- unsigned short int __pad2;
long long st_size;
- long st_blksize;
+ long long st_blksize;
long long st_blocks;
- long st_atime_;
- unsigned long st_atime_nsec_;
- long st_mtime_;
- unsigned long st_mtime_nsec_;
- long st_ctime_;
- unsigned long st_ctime_nsec_;
+ kernel_timespec st_atim;
+ kernel_timespec st_mtim;
+ kernel_timespec st_ctim;
unsigned long __unused4;
unsigned long __unused5;
+ unsigned long __unused6;
};
#else
struct kernel_stat64 {
@@ -427,24 +425,23 @@ struct kernel_stat {
};
#elif defined(__PPC__)
struct kernel_stat {
- unsigned st_dev;
- unsigned long st_ino; // ino_t
- unsigned long st_mode; // mode_t
- unsigned short st_nlink; // nlink_t
- unsigned st_uid; // uid_t
- unsigned st_gid; // gid_t
- unsigned st_rdev;
- long st_size; // off_t
+ unsigned long long st_dev;
+ unsigned long st_ino;
+ unsigned long st_nlink;
+ unsigned long st_mode;
+ unsigned st_uid;
+ unsigned st_gid;
+ int __pad2;
+ unsigned long long st_rdev;
+ long st_size;
unsigned long st_blksize;
unsigned long st_blocks;
- unsigned long st_atime_;
- unsigned long st_atime_nsec_;
- unsigned long st_mtime_;
- unsigned long st_mtime_nsec_;
- unsigned long st_ctime_;
- unsigned long st_ctime_nsec_;
+ kernel_timespec st_atim;
+ kernel_timespec st_mtim;
+ kernel_timespec st_ctim;
unsigned long __unused4;
unsigned long __unused5;
+ unsigned long __unused6;
};
#elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64)
struct kernel_stat {
@@ -659,6 +656,9 @@ struct kernel_stat {
#ifndef __NR_fstat64
#define __NR_fstat64 197
#endif
+#ifndef __NR_socket
+#define __NR_socket 198
+#endif
#ifndef __NR_getdents64
#define __NR_getdents64 202
#endif
@@ -1710,13 +1710,13 @@ struct kernel_stat {
#define LSS_BODY(nr, type, name, args...) \
long __sc_ret, __sc_err; \
{ \
- register unsigned long __sc_0 __asm__ ("r0"); \
- register unsigned long __sc_3 __asm__ ("r3"); \
- register unsigned long __sc_4 __asm__ ("r4"); \
- register unsigned long __sc_5 __asm__ ("r5"); \
- register unsigned long __sc_6 __asm__ ("r6"); \
- register unsigned long __sc_7 __asm__ ("r7"); \
- register unsigned long __sc_8 __asm__ ("r8"); \
+ register unsigned long __sc_0 __asm__ ("r0"); \
+ register unsigned long __sc_3 __asm__ ("r3"); \
+ register unsigned long __sc_4 __asm__ ("r4"); \
+ register unsigned long __sc_5 __asm__ ("r5"); \
+ register unsigned long __sc_6 __asm__ ("r6"); \
+ register unsigned long __sc_7 __asm__ ("r7"); \
+ register unsigned long __sc_8 __asm__ ("r8"); \
\
LSS_LOADARGS_##nr(name, args); \
__asm__ __volatile__ \
@@ -1773,15 +1773,82 @@ struct kernel_stat {
type5 arg5, type6 arg6) { \
LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \
}
- /* clone function adapted from glibc 2.3.6 clone.S */
- /* TODO(csilvers): consider wrapping some args up in a struct, like we
- * do for i386's _syscall6, so we can compile successfully on gcc 2.95
- */
+ /* clone function adapted from glibc 2.18 clone.S */
LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
int flags, void *arg, int *parent_tidptr,
void *newtls, int *child_tidptr) {
long __ret, __err;
{
+#if defined(__PPC64__)
+ register int (*__fn)(void *) __asm__ ("r3") = fn;
+ register void *__cstack __asm__ ("r4") = child_stack;
+ register int __flags __asm__ ("r5") = flags;
+ register void * __arg __asm__ ("r6") = arg;
+ register int * __ptidptr __asm__ ("r7") = parent_tidptr;
+ register void * __newtls __asm__ ("r8") = newtls;
+ register int * __ctidptr __asm__ ("r9") = child_tidptr;
+ __asm__ __volatile__(
+ /* check for fn == NULL
+ * and child_stack == NULL
+ */
+ "cmpdi cr0, %6, 0\n\t"
+ "cmpdi cr1, %7, 0\n\t"
+ "cror cr0*4+eq, cr1*4+eq, cr0*4+eq\n\t"
+ "beq- cr0, 1f\n\t"
+
+ /* set up stack frame for child */
+ "clrrdi %7, %7, 4\n\t"
+ "li 0, 0\n\t"
+ "stdu 0, -112(%7)\n\t"
+
+ /* fn, arg, child_stack are saved acrVoss the syscall */
+ "mr 28, %6\n\t"
+ "mr 29, %7\n\t"
+ "mr 27, %9\n\t"
+
+ /* syscall
+ r3 == flags
+ r4 == child_stack
+ r5 == parent_tidptr
+ r6 == newtls
+ r7 == child_tidptr */
+ "mr 3, %8\n\t"
+ "mr 5, %10\n\t"
+ "mr 6, %11\n\t"
+ "mr 7, %12\n\t"
+ "li 0, %4\n\t"
+ "sc\n\t"
+
+ /* Test if syscall was successful */
+ "cmpdi cr1, 3, 0\n\t"
+ "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
+ "bne- cr1, 1f\n\t"
+
+ /* Do the function call */
+ "std 2, 40(1)\n\t"
+ "ld 0, 0(28)\n\t"
+ "ld 2, 8(28)\n\t"
+ "mtctr 0\n\t"
+ "mr 3, 27\n\t"
+ "bctrl\n\t"
+ "ld 2, 40(1)\n\t"
+
+ /* Call _exit(r3) */
+ "li 0, %5\n\t"
+ "sc\n\t"
+
+ /* Return to parent */
+ "1:\n\t"
+ "mr %0, 3\n\t"
+ : "=r" (__ret), "=r" (__err)
+ : "0" (-1), "i" (EINVAL),
+ "i" (__NR_clone), "i" (__NR_exit),
+ "r" (__fn), "r" (__cstack), "r" (__flags),
+ "r" (__arg), "r" (__ptidptr), "r" (__newtls),
+ "r" (__ctidptr)
+ : "cr0", "cr1", "memory", "ctr",
+ "r0", "r29", "r27", "r28");
+#else
register int (*__fn)(void *) __asm__ ("r8") = fn;
register void *__cstack __asm__ ("r4") = child_stack;
register int __flags __asm__ ("r3") = flags;
@@ -1844,6 +1911,8 @@ struct kernel_stat {
"r" (__ctidptr)
: "cr0", "cr1", "memory", "ctr",
"r0", "r29", "r27", "r28");
+
+#endif
}
LSS_RETURN(int, __ret, __err);
}
@@ -2110,66 +2179,8 @@ struct kernel_stat {
return rc;
}
#endif
- #if defined(__PPC__)
- #undef LSS_SC_LOADARGS_0
- #define LSS_SC_LOADARGS_0(dummy...)
- #undef LSS_SC_LOADARGS_1
- #define LSS_SC_LOADARGS_1(arg1) \
- __sc_4 = (unsigned long) (arg1)
- #undef LSS_SC_LOADARGS_2
- #define LSS_SC_LOADARGS_2(arg1, arg2) \
- LSS_SC_LOADARGS_1(arg1); \
- __sc_5 = (unsigned long) (arg2)
- #undef LSS_SC_LOADARGS_3
- #define LSS_SC_LOADARGS_3(arg1, arg2, arg3) \
- LSS_SC_LOADARGS_2(arg1, arg2); \
- __sc_6 = (unsigned long) (arg3)
- #undef LSS_SC_LOADARGS_4
- #define LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4) \
- LSS_SC_LOADARGS_3(arg1, arg2, arg3); \
- __sc_7 = (unsigned long) (arg4)
- #undef LSS_SC_LOADARGS_5
- #define LSS_SC_LOADARGS_5(arg1, arg2, arg3, arg4, arg5) \
- LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4); \
- __sc_8 = (unsigned long) (arg5)
- #undef LSS_SC_BODY
- #define LSS_SC_BODY(nr, type, opt, args...) \
- long __sc_ret, __sc_err; \
- { \
- register unsigned long __sc_0 __asm__ ("r0") = __NR_socketcall; \
- register unsigned long __sc_3 __asm__ ("r3") = opt; \
- register unsigned long __sc_4 __asm__ ("r4"); \
- register unsigned long __sc_5 __asm__ ("r5"); \
- register unsigned long __sc_6 __asm__ ("r6"); \
- register unsigned long __sc_7 __asm__ ("r7"); \
- register unsigned long __sc_8 __asm__ ("r8"); \
- LSS_SC_LOADARGS_##nr(args); \
- __asm__ __volatile__ \
- ("stwu 1, -48(1)\n\t" \
- "stw 4, 20(1)\n\t" \
- "stw 5, 24(1)\n\t" \
- "stw 6, 28(1)\n\t" \
- "stw 7, 32(1)\n\t" \
- "stw 8, 36(1)\n\t" \
- "addi 4, 1, 20\n\t" \
- "sc\n\t" \
- "mfcr %0" \
- : "=&r" (__sc_0), \
- "=&r" (__sc_3), "=&r" (__sc_4), \
- "=&r" (__sc_5), "=&r" (__sc_6), \
- "=&r" (__sc_7), "=&r" (__sc_8) \
- : LSS_ASMINPUT_##nr \
- : "cr0", "ctr", "memory"); \
- __sc_ret = __sc_3; \
- __sc_err = __sc_0; \
- } \
- LSS_RETURN(type, __sc_ret, __sc_err)
-
- LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) {
- LSS_SC_BODY(3, int, 1, domain, type, protocol);
- }
- #endif
#if defined(__i386__) || \
+ defined(__PPC__) || \
(defined(__arm__) && !defined(__ARM_EABI__)) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
diff --git a/src/base/linuxthreads.cc b/src/base/linuxthreads.cc
index 73eef04..ba4d1c8 100644
--- a/src/base/linuxthreads.cc
+++ b/src/base/linuxthreads.cc
@@ -96,6 +96,14 @@ static int local_clone (int (*fn)(void *), void *arg, ...)
#endif
#endif
+/* To avoid the gap cross page boundaries, increase by the large parge
+ * size mostly PowerPC system uses. */
+#ifdef __PPC64__
+#define CLONE_STACK_SIZE 65536
+#else
+#define CLONE_STACK_SIZE 4096
+#endif
+
static int local_clone (int (*fn)(void *), void *arg, ...) {
/* Leave 4kB of gap between the callers stack and the new clone. This
* should be more than sufficient for the caller to call waitpid() until
@@ -111,7 +119,7 @@ static int local_clone (int (*fn)(void *), void *arg, ...) {
* is being debugged. This is OK and the error code will be reported
* correctly.
*/
- return sys_clone(fn, (char *)&arg - 4096,
+ return sys_clone(fn, (char *)&arg - CLONE_STACK_SIZE,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_UNTRACED, arg, 0, 0, 0);
}
diff --git a/src/heap-checker.cc b/src/heap-checker.cc
index bc9e490..c050866 100644
--- a/src/heap-checker.cc
+++ b/src/heap-checker.cc
@@ -1008,6 +1008,15 @@ static enum {
// due to reliance on locale functions (these are called through RAW_LOG
// and in other ways).
//
+
+#if defined(HAVE_LINUX_PTRACE_H) && defined(HAVE_SYS_SYSCALL_H) && defined(DUMPER)
+# if (defined(__i386__) || defined(__x86_64))
+# define THREAD_REGS i386_regs
+# elif defined(__PPC__)
+# define THREAD_REGS ppc_regs
+# endif
+#endif
+
/*static*/ int HeapLeakChecker::IgnoreLiveThreadsLocked(void* parameter,
int num_threads,
pid_t* thread_pids,
@@ -1030,9 +1039,8 @@ static enum {
// specially via self_thread_stack, not here:
if (thread_pids[i] == self_thread_pid) continue;
RAW_VLOG(11, "Handling thread with pid %d", thread_pids[i]);
-#if (defined(__i386__) || defined(__x86_64)) && \
- defined(HAVE_LINUX_PTRACE_H) && defined(HAVE_SYS_SYSCALL_H) && defined(DUMPER)
- i386_regs thread_regs;
+#ifdef THREAD_REGS
+ THREAD_REGS thread_regs;
#define sys_ptrace(r, p, a, d) syscall(SYS_ptrace, (r), (p), (a), (d))
// We use sys_ptrace to avoid thread locking
// because this is called from ListAllProcessThreads
diff --git a/src/stacktrace_powerpc-inl.h b/src/stacktrace_powerpc-inl.h
index acf2884..e1bf0bd 100644
--- a/src/stacktrace_powerpc-inl.h
+++ b/src/stacktrace_powerpc-inl.h
@@ -45,32 +45,45 @@
#include <stdlib.h> // for NULL
#include <gperftools/stacktrace.h>
+struct layout_ppc {
+ struct layout_ppc *next;
+#if defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
+ long condition_register;
+#endif
+ void *return_addr;
+};
+
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING>
-static void **NextStackFrame(void **old_sp) {
- void **new_sp = (void **) *old_sp;
+static layout_ppc *NextStackFrame(layout_ppc *current) {
+ uintptr_t old_sp = (uintptr_t)(current);
+ uintptr_t new_sp = (uintptr_t)(current->next);
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) {
// With the stack growing downwards, older stack frame must be
// at a greater address that the current one.
- if (new_sp <= old_sp) return NULL;
+ if (new_sp <= old_sp)
+ return NULL;
// Assume stack frames larger than 100,000 bytes are bogus.
- if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
+ if (new_sp - old_sp > 100000)
+ return NULL;
} else {
// In the non-strict mode, allow discontiguous stack frames.
// (alternate-signal-stacks for example).
- if (new_sp == old_sp) return NULL;
+ if (new_sp == old_sp)
+ return NULL;
// And allow frames upto about 1MB.
- if ((new_sp > old_sp)
- && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
+ if ((new_sp > old_sp) && (new_sp - old_sp > 1000000))
+ return NULL;
}
- if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
- return new_sp;
+ if (new_sp & (sizeof(void *) - 1))
+ return NULL;
+ return current->next;
}
// This ensures that GetStackTrace stes up the Link Register properly.
@@ -81,6 +94,26 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
// Note: this part of the file is included several times.
// Do not put globals below.
+// Load instruction used on top-of-stack get.
+#if defined(__PPC64__) || defined(__LP64__)
+# define LOAD "ld"
+#else
+# define LOAD "lwz"
+#endif
+
+#if defined(__linux__) && defined(__PPC__)
+# define TOP_STACK "%0,0(1)"
+#elif defined(__MACH__) && defined(__APPLE__)
+// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
+// different asm syntax. I don't know quite the best way to discriminate
+// systems using the old as from the new one; I've gone with __APPLE__.
+// TODO(csilvers): use autoconf instead, to look for 'as --version' == 1 or 2
+# define TOP_STACK "%0,0(r1)"
+#endif
+
+
+
// The following 4 functions are generated from the code below:
// GetStack{Trace,Frames}()
// GetStack{Trace,Frames}WithContext()
@@ -93,78 +126,44 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
// int skip_count: how many stack pointers to skip before storing in result
// void* ucp: a ucontext_t* (GetStack{Trace,Frames}WithContext only)
int GET_STACK_TRACE_OR_FRAMES {
- void **sp;
- // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
- // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
- // different asm syntax. I don't know quite the best way to discriminate
- // systems using the old as from the new one; I've gone with __APPLE__.
- // TODO(csilvers): use autoconf instead, to look for 'as --version' == 1 or 2
-#ifdef __APPLE__
- __asm__ volatile ("mr %0,r1" : "=r" (sp));
-#else
- __asm__ volatile ("mr %0,1" : "=r" (sp));
-#endif
+ layout_ppc *current;
+ int n;
+
+ // Force GCC to spill LR.
+ asm volatile ("" : "=l"(current));
+
+ // Get the address on top-of-stack
+ asm volatile (LOAD " " TOP_STACK : "=r"(current));
- // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
- // entry that holds the return address of the subroutine call (what
- // instruction we run after our function finishes). This is the
- // same as the stack-pointer of our parent routine, which is what we
- // want here. While the compiler will always(?) set up LR for
- // subroutine calls, it may not for leaf functions (such as this one).
- // This routine forces the compiler (at least gcc) to push it anyway.
StacktracePowerPCDummyFunction();
-#if IS_STACK_FRAMES
- // Note we do *not* increment skip_count here for the SYSV ABI. If
- // we did, the list of stack frames wouldn't properly match up with
- // the list of return addresses. Note this means the top pc entry
- // is probably bogus for linux/ppc (and other SYSV-ABI systems).
-#else
- // The LR save area is used by the callee, so the top entry is bogus.
- skip_count++;
-#endif
+ n = 0;
+ while (current && n < max_depth) {
+ result[n] = current->return_addr;
- int n = 0;
- while (sp && n < max_depth) {
// The GetStackFrames routine is called when we are in some
// informational context (the failure signal handler for example).
// Use the non-strict unwinding rules to produce a stack trace
// that is as complete as possible (even if it contains a few
// bogus entries in some rare cases).
- void **next_sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
-
- if (skip_count > 0) {
- skip_count--;
- } else {
- // PowerPC has 3 main ABIs, which say where in the stack the
- // Link Register is. For DARWIN and AIX (used by apple and
- // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
- // it's in sp[1].
-#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
- result[n] = *(sp+2);
-#elif defined(_CALL_SYSV)
- result[n] = *(sp+1);
-#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
- // This check is in case the compiler doesn't define _CALL_AIX/etc.
- result[n] = *(sp+2);
-#elif defined(__linux)
- // This check is in case the compiler doesn't define _CALL_SYSV.
- result[n] = *(sp+1);
-#else
-#error Need to specify the PPC ABI for your archiecture.
-#endif
-
+ layout_ppc *next = NextStackFrame<!IS_STACK_FRAMES>(current);
#if IS_STACK_FRAMES
- if (next_sp > sp) {
- sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
- } else {
- // A frame-size of 0 is used to indicate unknown frame size.
- sizes[n] = 0;
- }
-#endif
- n++;
+ if (next > current) {
+ sizes[n] = (uintptr_t)next - (uintptr_t)current;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
}
- sp = next_sp;
+#endif
+ current = next;
+ n++;
}
+
+ // It's possible the second-last stack frame can't return
+ // (that is, it's __libc_start_main), in which case
+ // the CRT startup code will have set its LR to 'NULL'.
+ if (n > 0 && result[n-1] == NULL)
+ n--;
+
return n;
}
diff --git a/src/tests/heap-checker_unittest.cc b/src/tests/heap-checker_unittest.cc
index 75c05f8..482f51f 100644
--- a/src/tests/heap-checker_unittest.cc
+++ b/src/tests/heap-checker_unittest.cc
@@ -1263,6 +1263,27 @@ static void* Mmapper(uintptr_t* addr_after_mmap_call) {
return r;
}
+// On PPC64 the stacktrace returned by GetStatcTrace contains the function
+// address from .text segment while function pointers points to ODP entries.
+// The following code decodes the ODP to get the actual symbol address.
+#if defined(__linux) && defined(__PPC64__)
+static inline uintptr_t GetFunctionAddress (void* (*func)(uintptr_t*))
+{
+ struct odp_entry_t {
+ unsigned long int symbol;
+ unsigned long int toc;
+ unsigned long int env;
+ } *odp_entry = reinterpret_cast<odp_entry_t*>(func);
+
+ return static_cast<uintptr_t>(odp_entry->symbol);
+}
+#else
+static inline uintptr_t GetFunctionAddress (void* (*func)(uintptr_t*))
+{
+ return reinterpret_cast<uintptr_t>(func);
+}
+#endif
+
// to trick complier into preventing inlining
static void* (*mmapper_addr)(uintptr_t* addr) = &Mmapper;
@@ -1283,7 +1304,7 @@ static void VerifyMemoryRegionMapStackGet() {
}
}
// caller must point into Mmapper function:
- if (!(reinterpret_cast<uintptr_t>(mmapper_addr) <= caller &&
+ if (!(GetFunctionAddress(mmapper_addr) <= caller &&
caller < caller_addr_limit)) {
LOGF << std::hex << "0x" << caller
<< " does not seem to point into code of function Mmapper at "
@@ -1316,7 +1337,7 @@ extern void VerifyHeapProfileTableStackGet() {
uintptr_t caller =
reinterpret_cast<uintptr_t>(HeapLeakChecker::GetAllocCaller(addr));
// caller must point into Mallocer function:
- if (!(reinterpret_cast<uintptr_t>(mallocer_addr) <= caller &&
+ if (!(GetFunctionAddress(mallocer_addr) <= caller &&
caller < caller_addr_limit)) {
LOGF << std::hex << "0x" << caller
<< " does not seem to point into code of function Mallocer at "