about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-09-23 11:42:20 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-09-23 11:42:20 -0700
commit61afef29a186513570bcbe4f6dfa635e31d8a610 (patch)
tree7fc02dfa6a72410392a04717098186455c72eb9f
parentdbdeff659fb30fd845490cf215b5733e1e064d46 (diff)
downloadrust-61afef29a186513570bcbe4f6dfa635e31d8a610.tar.gz
rust-61afef29a186513570bcbe4f6dfa635e31d8a610.zip
rt: Add a RUST_TRACK_ORIGINS debug flag to help track down memory corruption
-rw-r--r--mk/rt.mk1
-rw-r--r--src/rt/rust_debug.cpp70
-rw-r--r--src/rt/rust_debug.h17
-rw-r--r--src/rt/rust_internal.h6
-rw-r--r--src/rt/rust_kernel.h5
-rw-r--r--src/rt/rust_shape.h15
-rw-r--r--src/rt/rust_task.h11
-rw-r--r--src/rt/rust_upcall.cpp5
8 files changed, 120 insertions, 10 deletions
diff --git a/mk/rt.mk b/mk/rt.mk
index 5e5fd8dc986..f2ed226b266 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -28,6 +28,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
               rt/rust_gc.cpp \
               rt/rust_abi.cpp \
               rt/rust_cc.cpp \
+              rt/rust_debug.cpp \
               rt/memory_region.cpp \
               rt/test/rust_test_harness.cpp \
               rt/test/rust_test_runtime.cpp \
diff --git a/src/rt/rust_debug.cpp b/src/rt/rust_debug.cpp
new file mode 100644
index 00000000000..697f9f13bbc
--- /dev/null
+++ b/src/rt/rust_debug.cpp
@@ -0,0 +1,70 @@
+// Routines useful when debugging the Rust runtime.
+
+#include "rust_debug.h"
+#include "rust_internal.h"
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <stdint.h>
+
+#if defined(__APPLE__) || defined(__linux__)
+#define HAVE_BACKTRACE
+#include <execinfo.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+namespace {
+
+debug::flag track_origins("RUST_TRACK_ORIGINS");
+
+}   // end anonymous namespace
+
+namespace debug {
+
+std::string
+backtrace() {
+    void *call_stack[256];
+    int n_frames = ::backtrace(call_stack, 256);
+    char **syms = backtrace_symbols(call_stack, n_frames);
+
+    std::stringstream ss;
+    for (int i = 0; i < n_frames; i++)
+        ss << syms[i] << std::endl;
+
+    free(syms);
+
+    return ss.str();
+}
+
+void
+maybe_track_origin(rust_task *task, void *ptr) {
+    if (!*track_origins)
+        return;
+    task->debug.origins[ptr] = backtrace();
+}
+
+void
+maybe_untrack_origin(rust_task *task, void *ptr) {
+    if (!*track_origins)
+        return;
+    task->debug.origins.erase(ptr);
+}
+
+// This function is intended to be called by the debugger.
+void
+dump_origin(rust_task *task, void *ptr) {
+    if (!*track_origins) {
+        std::cerr << "Try again with RUST_TRACK_ORIGINS=1." << std::endl;
+    } else if (task->debug.origins.find(ptr) == task->debug.origins.end()) {
+        std::cerr << "Pointer " << std::hex << (uintptr_t)ptr <<
+                     " does not have a tracked origin.";
+    } else {
+        std::cerr << "Origin of pointer " << std::hex << ":" << std::endl <<
+                     task->debug.origins[ptr];
+    }
+}
+
+}   // end namespace debug
+
diff --git a/src/rt/rust_debug.h b/src/rt/rust_debug.h
index f7c444324f7..da9838ba341 100644
--- a/src/rt/rust_debug.h
+++ b/src/rt/rust_debug.h
@@ -3,8 +3,12 @@
 #ifndef RUST_DEBUG_H
 #define RUST_DEBUG_H
 
+#include <map>
+#include <string>
 #include <cstdlib>
 
+struct rust_task;
+
 namespace debug {
 
 class flag {
@@ -27,6 +31,19 @@ public:
     }
 };
 
+class task_debug_info {
+public:
+    std::map<void *,std::string> origins;
+};
+
+std::string backtrace();
+
+void maybe_track_origin(rust_task *task, void *ptr);
+void maybe_untrack_origin(rust_task *task, void *ptr);
+
+// This function is intended to be called by the debugger.
+void dump_origin(rust_task *task, void *ptr);
+
 }   // end namespace debug
 
 #endif
diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h
index b53e0bfd2a9..8688cedc857 100644
--- a/src/rt/rust_internal.h
+++ b/src/rt/rust_internal.h
@@ -67,12 +67,6 @@ struct frame_glue_fns;
 typedef intptr_t rust_task_id;
 typedef intptr_t rust_port_id;
 
-// Corresponds to the rust chan (currently _chan) type.
-struct chan_handle {
-    rust_task_id task;
-    rust_port_id port;
-};
-
 #ifndef __i386__
 #error "Target CPU not supported."
 #endif
diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h
index 774f7f4d0a4..8d59dabdcb9 100644
--- a/src/rt/rust_kernel.h
+++ b/src/rt/rust_kernel.h
@@ -2,6 +2,11 @@
 #ifndef RUST_KERNEL_H
 #define RUST_KERNEL_H
 
+#include "memory_region.h"
+#include "rust_log.h"
+
+struct rust_scheduler;
+
 /**
  * A global object shared by all thread domains. Most of the data structures
  * in this class are synchronized since they are accessed from multiple
diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index 357786ae2ce..06e8571f589 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -16,11 +16,11 @@
 
 #define ARENA_SIZE          256
 
-//#define DPRINT(fmt,...)     fprintf(stderr, fmt, ##__VA_ARGS__)
-//#define DPRINTCX(cx)        shape::print::print_cx(cx)
+#define DPRINT(fmt,...)     fprintf(stderr, fmt, ##__VA_ARGS__)
+#define DPRINTCX(cx)        shape::print::print_cx(cx)
 
-#define DPRINT(fmt,...)
-#define DPRINTCX(cx)
+//#define DPRINT(fmt,...)
+//#define DPRINTCX(cx)
 
 
 namespace shape {
@@ -526,6 +526,13 @@ public:
           const rust_shape_tables *in_tables = NULL)
     : ctxt<print>(other, in_sp, in_params, in_tables) {}
 
+    print(rust_task *in_task,
+          bool in_align,
+          const uint8_t *in_sp,
+          const type_param *in_params,
+          const rust_shape_tables *in_tables)
+    : ctxt<print>(in_task, in_align, in_sp, in_params, in_tables) {}
+
     void walk_tag(tag_info &tinfo);
     void walk_struct(const uint8_t *end_sp);
     void walk_res(const rust_fn *dtor, unsigned n_params,
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index 047fbd2b58f..76b828af58f 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -10,8 +10,17 @@
 #include "util/array_list.h"
 
 #include "context.h"
+#include "rust_debug.h"
+#include "rust_internal.h"
+#include "rust_kernel.h"
 #include "rust_obstack.h"
 
+// Corresponds to the rust chan (currently _chan) type.
+struct chan_handle {
+    rust_task_id task;
+    rust_port_id port;
+};
+
 struct rust_box;
 
 struct stk_seg {
@@ -117,6 +126,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
 
     std::map<void *,const type_desc *> local_allocs;
 
+    debug::task_debug_info debug;
+
     // Only a pointer to 'name' is kept, so it must live as long as this task.
     rust_task(rust_scheduler *sched,
               rust_task_list *state,
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 758d5622b10..7a96a5ef7cb 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -67,10 +67,13 @@ upcall_malloc(rust_task *task, size_t nbytes, type_desc *td) {
     // TODO: Maybe use dladdr here to find a more useful name for the
     // type_desc.
 
+    // TODO: Implement RUST_TRACK_ORIGINS
+
     void *p = task->malloc(nbytes, "tdesc", td);
     memset(p, '\0', nbytes);
 
     task->local_allocs[p] = td;
+    debug::maybe_track_origin(task, p);
 
     LOG(task, mem,
         "upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ") = 0x%" PRIxPTR,
@@ -91,6 +94,8 @@ upcall_free(rust_task *task, void* ptr, uintptr_t is_gc) {
              (uintptr_t)ptr, is_gc);
 
     task->local_allocs.erase(ptr);
+    debug::maybe_untrack_origin(task, ptr);
+
     task->free(ptr, (bool) is_gc);
 }