Fix calculation in threadStackOverflow
[ghc.git] / rts / Libdw.c
index 53c2cde..33a40a1 100644 (file)
@@ -6,15 +6,17 @@
  *
  * --------------------------------------------------------------------------*/
 
-#ifdef USE_LIBDW
+#include "Rts.h"
+#include "RtsUtils.h"
+#include "Libdw.h"
+
+#if USE_LIBDW
 
 #include <elfutils/libdwfl.h>
 #include <dwarf.h>
 #include <unistd.h>
 
-#include "Rts.h"
-#include "Libdw.h"
-#include "RtsUtils.h"
+const int max_backtrace_depth = 5000;
 
 static BacktraceChunk *backtraceAllocChunk(BacktraceChunk *next) {
     BacktraceChunk *chunk = stgMallocBytes(sizeof(BacktraceChunk),
@@ -57,7 +59,10 @@ void backtraceFree(Backtrace *bt) {
 
 struct LibdwSession_ {
     Dwfl *dwfl;
-    Backtrace *cur_bt; // The current backtrace we are collecting (if any)
+
+    // The current backtrace we are collecting (if any)
+    Backtrace *cur_bt;
+    int max_depth;
 };
 
 static const Dwfl_Thread_Callbacks thread_cbs;
@@ -123,18 +128,19 @@ LibdwSession *libdwInit() {
 
 int libdwLookupLocation(LibdwSession *session, Location *frame,
                         StgPtr pc) {
+    Dwarf_Addr addr = (Dwarf_Addr) (uintptr_t) pc;
     // Find the module containing PC
-    Dwfl_Module *mod = dwfl_addrmodule(session->dwfl, (Dwarf_Addr) pc);
+    Dwfl_Module *mod = dwfl_addrmodule(session->dwfl, addr);
     if (mod == NULL)
         return 1;
     dwfl_module_info(mod, NULL, NULL, NULL, NULL, NULL,
                      &frame->object_file, NULL);
 
     // Find function name
-    frame->function = dwfl_module_addrname(mod, (Dwarf_Addr) pc);
+    frame->function = dwfl_module_addrname(mod, addr);
 
     // Try looking up source location
-    Dwfl_Line *line = dwfl_module_getsrc(mod, (Dwarf_Addr) pc);
+    Dwfl_Line *line = dwfl_module_getsrc(mod, addr);
     if (line != NULL) {
         Dwarf_Addr addr;
         int lineno, colno;
@@ -227,10 +233,14 @@ static int getBacktraceFrameCb(Dwfl_Frame *frame, void *arg) {
     } else {
         if (is_activation)
             pc -= 1; // TODO: is this right?
-        backtracePush(session->cur_bt, (StgPtr) pc);
+        backtracePush(session->cur_bt, (StgPtr) (uintptr_t) pc);
+    }
+    session->max_depth--;
+    if (session->max_depth == 0) {
+        return DWARF_CB_ABORT;
+    } else {
+        return DWARF_CB_OK;
     }
-
-    return DWARF_CB_OK;
 }
 
 Backtrace *libdwGetBacktrace(LibdwSession *session) {
@@ -241,6 +251,7 @@ Backtrace *libdwGetBacktrace(LibdwSession *session) {
 
     Backtrace *bt = backtraceAlloc();
     session->cur_bt = bt;
+    session->max_depth = max_backtrace_depth;
 
     int pid = getpid();
     int ret = dwfl_getthread_frames(session->dwfl, pid,
@@ -264,13 +275,13 @@ static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp) {
 
 static bool memory_read(Dwfl *dwfl STG_UNUSED, Dwarf_Addr addr,
                         Dwarf_Word *result, void *arg STG_UNUSED) {
-    *result = *(Dwarf_Word *) addr;
+    *result = *(Dwarf_Word *) (uintptr_t) addr;
     return true;
 }
 
 static bool set_initial_registers(Dwfl_Thread *thread, void *arg);
 
-#ifdef x86_64_HOST_ARCH
+#if defined(x86_64_HOST_ARCH)
 static bool set_initial_registers(Dwfl_Thread *thread,
                                   void *arg STG_UNUSED) {
     Dwarf_Word regs[17];
@@ -298,8 +309,7 @@ static bool set_initial_registers(Dwfl_Thread *thread,
         );
     return dwfl_thread_state_registers(thread, 0, 17, regs);
 }
-#endif
-#ifdef i386_HOST_ARCH
+#elif defined(i386_HOST_ARCH)
 static bool set_initial_registers(Dwfl_Thread *thread,
                                   void *arg STG_UNUSED) {
     Dwarf_Word regs[9];
@@ -311,7 +321,8 @@ static bool set_initial_registers(Dwfl_Thread *thread,
              "movl %%ebp, 0x14(%0)\n\t"
              "movl %%esp, 0x18(%0)\n\t"
              "movl %%edi, 0x1c(%0)\n\t"
-             "lea 0(%%eip), %%eax\n\t"
+             "here:\n\t"
+             "movl here,  %%eax\n\t"
              "movl %%eax, 0x20(%0)\n\t"
              :                            /* no output */
              :"r" (&regs[0])              /* input */
@@ -319,6 +330,8 @@ static bool set_initial_registers(Dwfl_Thread *thread,
         );
     return dwfl_thread_state_registers(thread, 0, 9, regs);
 }
+#else
+#    error "Please implement set_initial_registers() for your arch"
 #endif
 
 static const Dwfl_Thread_Callbacks thread_cbs = {
@@ -327,4 +340,18 @@ static const Dwfl_Thread_Callbacks thread_cbs = {
     .set_initial_registers = set_initial_registers,
 };
 
+#else /* !USE_LIBDW */
+
+void backtraceFree(Backtrace *bt STG_UNUSED) { }
+
+Backtrace *libdwGetBacktrace(LibdwSession *session STG_UNUSED) {
+    return NULL;
+}
+
+int libdwLookupLocation(LibdwSession *session STG_UNUSED,
+                        Location *loc STG_UNUSED,
+                        StgPtr pc STG_UNUSED) {
+    return 1;
+}
+
 #endif /* USE_LIBDW */