rt: Add a RUST_TRACK_ORIGINS debug flag to help track down memory corruption
This commit is contained in:
parent
dbdeff659f
commit
61afef29a1
1
mk/rt.mk
1
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 \
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue