forked from OSchip/llvm-project
tsan: describe heap/data locations in Go
llvm-svn: 262343
This commit is contained in:
parent
f5fcdd268f
commit
a029b79e1a
|
@ -60,6 +60,7 @@ DataInfo::DataInfo() {
|
|||
|
||||
void DataInfo::Clear() {
|
||||
InternalFree(module);
|
||||
InternalFree(file);
|
||||
InternalFree(name);
|
||||
internal_memset(this, 0, sizeof(DataInfo));
|
||||
}
|
||||
|
|
|
@ -65,6 +65,8 @@ struct DataInfo {
|
|||
// (de)allocated using sanitizer internal allocator.
|
||||
char *module;
|
||||
uptr module_offset;
|
||||
char *file;
|
||||
uptr line;
|
||||
char *name;
|
||||
uptr start;
|
||||
uptr size;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
void __tsan_init(void **thr, void (*cb)(void*));
|
||||
void __tsan_init(void **thr, void (*cb)(long, void*));
|
||||
void __tsan_fini();
|
||||
void __tsan_map_shadow(void *addr, unsigned long size);
|
||||
void __tsan_go_start(void *thr, void **chthr, void *pc);
|
||||
|
@ -22,12 +22,12 @@ void __tsan_read(void *thr, void *addr, void *pc);
|
|||
void __tsan_write(void *thr, void *addr, void *pc);
|
||||
void __tsan_func_enter(void *thr, void *pc);
|
||||
void __tsan_func_exit(void *thr);
|
||||
void __tsan_malloc(void *p, unsigned long sz);
|
||||
void __tsan_malloc(void *thr, void *pc, void *p, unsigned long sz);
|
||||
void __tsan_acquire(void *thr, void *addr);
|
||||
void __tsan_release(void *thr, void *addr);
|
||||
void __tsan_release_merge(void *thr, void *addr);
|
||||
|
||||
void symbolize_cb(void *ctx) {}
|
||||
void symbolize_cb(long cmd, void *ctx) {}
|
||||
|
||||
char buf0[100<<10];
|
||||
|
||||
|
@ -36,12 +36,13 @@ void barfoo() {}
|
|||
|
||||
int main(void) {
|
||||
void *thr0 = 0;
|
||||
char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1));
|
||||
__tsan_malloc(buf, 10);
|
||||
__tsan_init(&thr0, symbolize_cb);
|
||||
char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1));
|
||||
__tsan_map_shadow(buf, 4096);
|
||||
__tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10);
|
||||
__tsan_free(thr0, buf, 10);
|
||||
__tsan_func_enter(thr0, (char*)&main + 1);
|
||||
__tsan_malloc(buf, 10);
|
||||
__tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10);
|
||||
__tsan_release(thr0, buf);
|
||||
__tsan_release_merge(thr0, buf);
|
||||
void *thr1 = 0;
|
||||
|
|
|
@ -28,10 +28,6 @@ bool IsExpectedReport(uptr addr, uptr size) {
|
|||
return false;
|
||||
}
|
||||
|
||||
ReportLocation *SymbolizeData(uptr addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *internal_alloc(MBlockType typ, uptr sz) {
|
||||
return InternalAlloc(sz);
|
||||
}
|
||||
|
@ -40,7 +36,15 @@ void internal_free(void *p) {
|
|||
InternalFree(p);
|
||||
}
|
||||
|
||||
struct SymbolizeContext {
|
||||
// Callback into Go.
|
||||
static void (*go_runtime_cb)(uptr cmd, void *ctx);
|
||||
|
||||
enum {
|
||||
CallbackSymbolizeCode = 0,
|
||||
CallbackSymbolizeData = 1,
|
||||
};
|
||||
|
||||
struct SymbolizeCodeContext {
|
||||
uptr pc;
|
||||
char *func;
|
||||
char *file;
|
||||
|
@ -49,26 +53,62 @@ struct SymbolizeContext {
|
|||
uptr res;
|
||||
};
|
||||
|
||||
// Callback into Go.
|
||||
static void (*symbolize_cb)(SymbolizeContext *ctx);
|
||||
|
||||
SymbolizedStack *SymbolizeCode(uptr addr) {
|
||||
SymbolizedStack *s = SymbolizedStack::New(addr);
|
||||
SymbolizeContext ctx;
|
||||
internal_memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.pc = addr;
|
||||
symbolize_cb(&ctx);
|
||||
if (ctx.res) {
|
||||
SymbolizeCodeContext cbctx;
|
||||
internal_memset(&cbctx, 0, sizeof(cbctx));
|
||||
cbctx.pc = addr;
|
||||
go_runtime_cb(CallbackSymbolizeCode, &cbctx);
|
||||
if (cbctx.res) {
|
||||
AddressInfo &info = s->info;
|
||||
info.module_offset = ctx.off;
|
||||
info.function = internal_strdup(ctx.func ? ctx.func : "??");
|
||||
info.file = internal_strdup(ctx.file ? ctx.file : "-");
|
||||
info.line = ctx.line;
|
||||
info.module_offset = cbctx.off;
|
||||
info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
|
||||
info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
|
||||
info.line = cbctx.line;
|
||||
info.column = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
struct SymbolizeDataContext {
|
||||
uptr addr;
|
||||
uptr heap;
|
||||
uptr start;
|
||||
uptr size;
|
||||
char *name;
|
||||
char *file;
|
||||
uptr line;
|
||||
uptr res;
|
||||
};
|
||||
|
||||
ReportLocation *SymbolizeData(uptr addr) {
|
||||
SymbolizeDataContext cbctx;
|
||||
internal_memset(&cbctx, 0, sizeof(cbctx));
|
||||
cbctx.addr = addr;
|
||||
go_runtime_cb(CallbackSymbolizeData, &cbctx);
|
||||
if (!cbctx.res)
|
||||
return 0;
|
||||
if (cbctx.heap) {
|
||||
MBlock *b = ctx->metamap.GetBlock(cbctx.start);
|
||||
if (!b)
|
||||
return 0;
|
||||
ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
|
||||
loc->heap_chunk_start = cbctx.start;
|
||||
loc->heap_chunk_size = b->siz;
|
||||
loc->tid = b->tid;
|
||||
loc->stack = SymbolizeStackId(b->stk);
|
||||
return loc;
|
||||
} else {
|
||||
ReportLocation *loc = ReportLocation::New(ReportLocationGlobal);
|
||||
loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
|
||||
loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
|
||||
loc->global.line = cbctx.line;
|
||||
loc->global.start = cbctx.start;
|
||||
loc->global.size = cbctx.size;
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static ThreadState *main_thr;
|
||||
|
@ -81,8 +121,8 @@ static ThreadState *AllocGoroutine() {
|
|||
return thr;
|
||||
}
|
||||
|
||||
void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) {
|
||||
symbolize_cb = cb;
|
||||
void __tsan_init(ThreadState **thrp, void (*cb)(uptr cmd, void *cb)) {
|
||||
go_runtime_cb = cb;
|
||||
ThreadState *thr = AllocGoroutine();
|
||||
main_thr = *thrp = thr;
|
||||
Initialize(thr);
|
||||
|
@ -140,12 +180,18 @@ void __tsan_func_exit(ThreadState *thr) {
|
|||
FuncExit(thr);
|
||||
}
|
||||
|
||||
void __tsan_malloc(void *p, uptr sz) {
|
||||
if (!inited)
|
||||
return;
|
||||
void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
|
||||
CHECK(inited);
|
||||
if (thr && pc)
|
||||
ctx->metamap.AllocBlock(thr, pc, p, sz);
|
||||
MemoryResetRange(0, 0, (uptr)p, sz);
|
||||
}
|
||||
|
||||
void __tsan_free(ThreadState *thr, uptr p, uptr sz) {
|
||||
if (thr)
|
||||
ctx->metamap.FreeRange(thr, 0, p, sz);
|
||||
}
|
||||
|
||||
void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
|
||||
ThreadState *thr = AllocGoroutine();
|
||||
*pthr = thr;
|
||||
|
|
|
@ -379,9 +379,9 @@ void PrintStack(const ReportStack *ent) {
|
|||
|
||||
static void PrintMop(const ReportMop *mop, bool first) {
|
||||
Printf("\n");
|
||||
Printf("%s by ",
|
||||
Printf("%s at %p by ",
|
||||
(first ? (mop->write ? "Write" : "Read")
|
||||
: (mop->write ? "Previous write" : "Previous read")));
|
||||
: (mop->write ? "Previous write" : "Previous read")), mop->addr);
|
||||
if (mop->tid == kMainThreadId)
|
||||
Printf("main goroutine:\n");
|
||||
else
|
||||
|
@ -389,6 +389,31 @@ static void PrintMop(const ReportMop *mop, bool first) {
|
|||
PrintStack(mop->stack);
|
||||
}
|
||||
|
||||
static void PrintLocation(const ReportLocation *loc) {
|
||||
switch (loc->type) {
|
||||
case ReportLocationHeap: {
|
||||
Printf("\n");
|
||||
Printf("Heap block of size %zu at %p allocated by ",
|
||||
loc->heap_chunk_size, loc->heap_chunk_start);
|
||||
if (loc->tid == kMainThreadId)
|
||||
Printf("main goroutine:\n");
|
||||
else
|
||||
Printf("goroutine %d:\n", loc->tid);
|
||||
PrintStack(loc->stack);
|
||||
break;
|
||||
}
|
||||
case ReportLocationGlobal: {
|
||||
Printf("\n");
|
||||
Printf("Global var %s of size %zu at %p declared at %s:%zu\n",
|
||||
loc->global.name, loc->global.size, loc->global.start,
|
||||
loc->global.file, loc->global.line);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintThread(const ReportThread *rt) {
|
||||
if (rt->id == kMainThreadId)
|
||||
return;
|
||||
|
@ -404,6 +429,8 @@ void PrintReport(const ReportDesc *rep) {
|
|||
Printf("WARNING: DATA RACE");
|
||||
for (uptr i = 0; i < rep->mops.Size(); i++)
|
||||
PrintMop(rep->mops[i], i == 0);
|
||||
for (uptr i = 0; i < rep->locs.Size(); i++)
|
||||
PrintLocation(rep->locs[i]);
|
||||
for (uptr i = 0; i < rep->threads.Size(); i++)
|
||||
PrintThread(rep->threads[i]);
|
||||
} else if (rep->typ == ReportTypeDeadlock) {
|
||||
|
|
|
@ -342,12 +342,12 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
|
|||
rep_->locs.PushBack(loc);
|
||||
AddThread(tctx);
|
||||
}
|
||||
#endif
|
||||
if (ReportLocation *loc = SymbolizeData(addr)) {
|
||||
loc->suppressable = true;
|
||||
rep_->locs.PushBack(loc);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
|
|
Loading…
Reference in New Issue