forked from OSchip/llvm-project
Simplify Symbolizer::SymbolizePC() interface.
Return a linked list of AddressInfo objects, instead of using an array of these objects as an output parameter. This simplifies the code in callers of this function (especially TSan). Fix a few memory leaks from internal allocator, when the returned AddressInfo objects were not properly cleared. llvm-svn: 223145
This commit is contained in:
parent
ab256185da
commit
0e90668f14
|
@ -457,30 +457,27 @@ void DoLeakCheck() {
|
|||
}
|
||||
|
||||
static Suppression *GetSuppressionForAddr(uptr addr) {
|
||||
Suppression *s;
|
||||
Suppression *s = nullptr;
|
||||
|
||||
// Suppress by module name.
|
||||
const char *module_name;
|
||||
uptr module_offset;
|
||||
if (Symbolizer::GetOrInit()
|
||||
->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) &&
|
||||
if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name,
|
||||
&module_offset) &&
|
||||
SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s))
|
||||
return s;
|
||||
|
||||
// Suppress by file or function name.
|
||||
static const uptr kMaxAddrFrames = 16;
|
||||
InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
|
||||
for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
|
||||
uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
|
||||
addr, addr_frames.data(), kMaxAddrFrames);
|
||||
for (uptr i = 0; i < addr_frames_num; i++) {
|
||||
if (SuppressionContext::Get()->Match(addr_frames[i].function,
|
||||
SuppressionLeak, &s) ||
|
||||
SuppressionContext::Get()->Match(addr_frames[i].file, SuppressionLeak,
|
||||
&s))
|
||||
return s;
|
||||
SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
|
||||
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
|
||||
if (SuppressionContext::Get()->Match(cur->info.function, SuppressionLeak,
|
||||
&s) ||
|
||||
SuppressionContext::Get()->Match(cur->info.file, SuppressionLeak, &s)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
frames->ClearAll();
|
||||
return s;
|
||||
}
|
||||
|
||||
static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
|
||||
|
|
|
@ -52,16 +52,20 @@ void SetSandboxingCallback(void (*f)()) {
|
|||
void ReportErrorSummary(const char *error_type, StackTrace *stack) {
|
||||
if (!common_flags()->print_summary)
|
||||
return;
|
||||
AddressInfo ai;
|
||||
#if !SANITIZER_GO
|
||||
if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) {
|
||||
// Currently, we include the first stack frame into the report summary.
|
||||
// Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
|
||||
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
|
||||
Symbolizer::GetOrInit()->SymbolizePC(pc, &ai, 1);
|
||||
SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
|
||||
const AddressInfo &ai = frame->info;
|
||||
ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
|
||||
frame->ClearAll();
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
AddressInfo ai;
|
||||
ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -24,30 +24,21 @@ void StackTrace::Print() const {
|
|||
Printf(" <empty stack>\n\n");
|
||||
return;
|
||||
}
|
||||
const int kMaxAddrFrames = 64;
|
||||
InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
|
||||
for (uptr i = 0; i < kMaxAddrFrames; i++)
|
||||
new(&addr_frames[i]) AddressInfo();
|
||||
InternalScopedString frame_desc(GetPageSizeCached() * 2);
|
||||
uptr frame_num = 0;
|
||||
for (uptr i = 0; i < size && trace[i]; i++) {
|
||||
// PCs in stack traces are actually the return addresses, that is,
|
||||
// addresses of the next instructions after the call.
|
||||
uptr pc = GetPreviousInstructionPc(trace[i]);
|
||||
uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
|
||||
pc, addr_frames.data(), kMaxAddrFrames);
|
||||
if (addr_frames_num == 0) {
|
||||
addr_frames[0].address = pc;
|
||||
addr_frames_num = 1;
|
||||
}
|
||||
for (uptr j = 0; j < addr_frames_num; j++) {
|
||||
AddressInfo &info = addr_frames[j];
|
||||
SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
|
||||
CHECK(frames);
|
||||
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
|
||||
frame_desc.clear();
|
||||
RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
|
||||
info, common_flags()->strip_path_prefix);
|
||||
cur->info, common_flags()->strip_path_prefix);
|
||||
Printf("%s\n", frame_desc.data());
|
||||
info.Clear();
|
||||
}
|
||||
frames->ClearAll();
|
||||
}
|
||||
// Always print a trailing empty line after stack trace.
|
||||
Printf("\n");
|
||||
|
|
|
@ -11,13 +11,61 @@
|
|||
// run-time libraries.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_allocator_internal.h"
|
||||
#include "sanitizer_platform.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_placement_new.h"
|
||||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
AddressInfo::AddressInfo() {
|
||||
internal_memset(this, 0, sizeof(AddressInfo));
|
||||
function_offset = kUnknown;
|
||||
}
|
||||
|
||||
void AddressInfo::Clear() {
|
||||
InternalFree(module);
|
||||
InternalFree(function);
|
||||
InternalFree(file);
|
||||
internal_memset(this, 0, sizeof(AddressInfo));
|
||||
function_offset = kUnknown;
|
||||
}
|
||||
|
||||
void AddressInfo::FillAddressAndModuleInfo(uptr addr, const char *mod_name,
|
||||
uptr mod_offset) {
|
||||
address = addr;
|
||||
module = internal_strdup(mod_name);
|
||||
module_offset = mod_offset;
|
||||
}
|
||||
|
||||
SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
|
||||
|
||||
SymbolizedStack *SymbolizedStack::New(uptr addr) {
|
||||
void *mem = InternalAlloc(sizeof(SymbolizedStack));
|
||||
SymbolizedStack *res = new(mem) SymbolizedStack();
|
||||
res->info.address = addr;
|
||||
return res;
|
||||
}
|
||||
|
||||
void SymbolizedStack::ClearAll() {
|
||||
info.Clear();
|
||||
if (next)
|
||||
next->ClearAll();
|
||||
InternalFree(this);
|
||||
}
|
||||
|
||||
DataInfo::DataInfo() {
|
||||
internal_memset(this, 0, sizeof(DataInfo));
|
||||
}
|
||||
|
||||
void DataInfo::Clear() {
|
||||
InternalFree(module);
|
||||
InternalFree(name);
|
||||
internal_memset(this, 0, sizeof(DataInfo));
|
||||
}
|
||||
|
||||
Symbolizer *Symbolizer::symbolizer_;
|
||||
StaticSpinMutex Symbolizer::init_mu_;
|
||||
LowLevelAllocator Symbolizer::symbolizer_allocator_;
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
#ifndef SANITIZER_SYMBOLIZER_H
|
||||
#define SANITIZER_SYMBOLIZER_H
|
||||
|
||||
#include "sanitizer_allocator_internal.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_mutex.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
struct AddressInfo {
|
||||
// Owns all the string members. Storage for them is
|
||||
// (de)allocated using sanitizer internal allocator.
|
||||
uptr address;
|
||||
|
||||
char *module;
|
||||
|
@ -39,45 +40,38 @@ struct AddressInfo {
|
|||
int line;
|
||||
int column;
|
||||
|
||||
AddressInfo() {
|
||||
internal_memset(this, 0, sizeof(AddressInfo));
|
||||
function_offset = kUnknown;
|
||||
}
|
||||
|
||||
AddressInfo();
|
||||
// Deletes all strings and resets all fields.
|
||||
void Clear() {
|
||||
InternalFree(module);
|
||||
InternalFree(function);
|
||||
InternalFree(file);
|
||||
internal_memset(this, 0, sizeof(AddressInfo));
|
||||
function_offset = kUnknown;
|
||||
}
|
||||
|
||||
void Clear();
|
||||
void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
|
||||
uptr mod_offset) {
|
||||
address = addr;
|
||||
module = internal_strdup(mod_name);
|
||||
module_offset = mod_offset;
|
||||
}
|
||||
uptr mod_offset);
|
||||
};
|
||||
|
||||
// Linked list of symbolized frames (each frame is described by AddressInfo).
|
||||
struct SymbolizedStack {
|
||||
SymbolizedStack *next;
|
||||
AddressInfo info;
|
||||
static SymbolizedStack *New(uptr addr);
|
||||
// Deletes current, and all subsequent frames in the linked list.
|
||||
// The object cannot be accessed after the call to this function.
|
||||
void ClearAll();
|
||||
|
||||
private:
|
||||
SymbolizedStack();
|
||||
};
|
||||
|
||||
// For now, DataInfo is used to describe global variable.
|
||||
struct DataInfo {
|
||||
// Owns all the string members. Storage for them is
|
||||
// (de)allocated using sanitizer internal allocator.
|
||||
char *module;
|
||||
uptr module_offset;
|
||||
char *name;
|
||||
uptr start;
|
||||
uptr size;
|
||||
|
||||
DataInfo() {
|
||||
internal_memset(this, 0, sizeof(DataInfo));
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
InternalFree(module);
|
||||
InternalFree(name);
|
||||
internal_memset(this, 0, sizeof(DataInfo));
|
||||
}
|
||||
DataInfo();
|
||||
void Clear();
|
||||
};
|
||||
|
||||
class Symbolizer {
|
||||
|
@ -85,11 +79,10 @@ class Symbolizer {
|
|||
/// Initialize and return platform-specific implementation of symbolizer
|
||||
/// (if it wasn't already initialized).
|
||||
static Symbolizer *GetOrInit();
|
||||
// Fills at most "max_frames" elements of "frames" with descriptions
|
||||
// for a given address (in all inlined functions). Returns the number
|
||||
// of descriptions actually filled.
|
||||
virtual uptr SymbolizePC(uptr address, AddressInfo *frames, uptr max_frames) {
|
||||
return 0;
|
||||
// Returns a list of symbolized frames for a given address (containing
|
||||
// all inlined functions, if necessary).
|
||||
virtual SymbolizedStack *SymbolizePC(uptr address) {
|
||||
return SymbolizedStack::New(address);
|
||||
}
|
||||
virtual bool SymbolizeData(uptr address, DataInfo *info) {
|
||||
return false;
|
||||
|
|
|
@ -83,44 +83,52 @@ char *CplusV3Demangle(const char *name) {
|
|||
}
|
||||
# endif // SANITIZER_CP_DEMANGLE
|
||||
|
||||
struct SymbolizeCodeData {
|
||||
AddressInfo *frames;
|
||||
uptr n_frames;
|
||||
uptr max_frames;
|
||||
struct SymbolizeCodeCallbackArg {
|
||||
SymbolizedStack *first;
|
||||
SymbolizedStack *last;
|
||||
const char *module_name;
|
||||
uptr module_offset;
|
||||
|
||||
void append(SymbolizedStack *f) {
|
||||
if (last != nullptr) {
|
||||
last->next = f;
|
||||
last = f;
|
||||
} else {
|
||||
first = f;
|
||||
last = f;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
|
||||
const char *filename, int lineno,
|
||||
const char *function) {
|
||||
SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
|
||||
SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
|
||||
if (function) {
|
||||
AddressInfo *info = &cdata->frames[cdata->n_frames++];
|
||||
info->Clear();
|
||||
SymbolizedStack *cur = SymbolizedStack::New(addr);
|
||||
cdata->append(cur);
|
||||
AddressInfo *info = &cur->info;
|
||||
info->FillAddressAndModuleInfo(addr, cdata->module_name,
|
||||
cdata->module_offset);
|
||||
info->function = LibbacktraceSymbolizer::Demangle(function, true);
|
||||
if (filename)
|
||||
info->file = internal_strdup(filename);
|
||||
info->line = lineno;
|
||||
if (cdata->n_frames == cdata->max_frames)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
|
||||
const char *symname, uintptr_t, uintptr_t) {
|
||||
SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
|
||||
SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
|
||||
if (symname) {
|
||||
AddressInfo *info = &cdata->frames[0];
|
||||
info->Clear();
|
||||
SymbolizedStack *cur = SymbolizedStack::New(addr);
|
||||
cdata->append(cur);
|
||||
AddressInfo *info = &cur->info;
|
||||
info->FillAddressAndModuleInfo(addr, cdata->module_name,
|
||||
cdata->module_offset);
|
||||
info->function = LibbacktraceSymbolizer::Demangle(symname, true);
|
||||
cdata->n_frames = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,23 +156,21 @@ LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
|
|||
return new(*alloc) LibbacktraceSymbolizer(state);
|
||||
}
|
||||
|
||||
uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
|
||||
uptr max_frames,
|
||||
const char *module_name,
|
||||
uptr module_offset) {
|
||||
SymbolizeCodeData data;
|
||||
data.frames = frames;
|
||||
data.n_frames = 0;
|
||||
data.max_frames = max_frames;
|
||||
SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
|
||||
const char *module_name,
|
||||
uptr module_offset) {
|
||||
SymbolizeCodeCallbackArg data;
|
||||
data.first = nullptr;
|
||||
data.last = nullptr;
|
||||
data.module_name = module_name;
|
||||
data.module_offset = module_offset;
|
||||
backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
|
||||
ErrorCallback, &data);
|
||||
if (data.n_frames)
|
||||
return data.n_frames;
|
||||
if (data.first)
|
||||
return data.first;
|
||||
backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
|
||||
ErrorCallback, &data);
|
||||
return data.n_frames;
|
||||
return data.first;
|
||||
}
|
||||
|
||||
bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
|
||||
|
@ -179,12 +185,11 @@ LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
|
||||
uptr max_frames,
|
||||
const char *module_name,
|
||||
uptr module_offset) {
|
||||
SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
|
||||
const char *module_name,
|
||||
uptr module_offset) {
|
||||
(void)state_;
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
|
||||
|
|
|
@ -32,8 +32,8 @@ class LibbacktraceSymbolizer {
|
|||
public:
|
||||
static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
|
||||
|
||||
uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames,
|
||||
const char *module_name, uptr module_offset);
|
||||
SymbolizedStack *SymbolizeCode(uptr addr, const char *module_name,
|
||||
uptr module_offset);
|
||||
|
||||
bool SymbolizeData(DataInfo *info);
|
||||
|
||||
|
|
|
@ -514,34 +514,32 @@ class POSIXSymbolizer : public Symbolizer {
|
|||
internal_symbolizer_(internal_symbolizer),
|
||||
libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
|
||||
|
||||
uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) override {
|
||||
SymbolizedStack *SymbolizePC(uptr addr) override {
|
||||
BlockingMutexLock l(&mu_);
|
||||
if (max_frames == 0)
|
||||
return 0;
|
||||
const char *module_name;
|
||||
uptr module_offset;
|
||||
if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
|
||||
return 0;
|
||||
return SymbolizedStack::New(addr);
|
||||
// First, try to use libbacktrace symbolizer (if it's available).
|
||||
if (libbacktrace_symbolizer_ != 0) {
|
||||
mu_.CheckLocked();
|
||||
uptr res = libbacktrace_symbolizer_->SymbolizeCode(
|
||||
addr, frames, max_frames, module_name, module_offset);
|
||||
if (res > 0)
|
||||
if (SymbolizedStack *res = libbacktrace_symbolizer_->SymbolizeCode(
|
||||
addr, module_name, module_offset))
|
||||
return res;
|
||||
}
|
||||
// Always fill data about module name and offset.
|
||||
SymbolizedStack *res = SymbolizedStack::New(addr);
|
||||
res->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
|
||||
const char *str = SendCommand(false, module_name, module_offset);
|
||||
if (str == 0) {
|
||||
// Symbolizer was not initialized or failed. Fill only data
|
||||
// about module name and offset.
|
||||
AddressInfo *info = &frames[0];
|
||||
info->Clear();
|
||||
info->FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
return 1;
|
||||
// Symbolizer was not initialized or failed.
|
||||
return res;
|
||||
}
|
||||
uptr frame_id = 0;
|
||||
for (frame_id = 0; frame_id < max_frames; frame_id++) {
|
||||
AddressInfo *info = &frames[frame_id];
|
||||
|
||||
bool top_frame = true;
|
||||
SymbolizedStack *last = res;
|
||||
while (true) {
|
||||
char *function_name = 0;
|
||||
str = ExtractToken(str, "\n", &function_name);
|
||||
CHECK(function_name);
|
||||
|
@ -549,8 +547,18 @@ class POSIXSymbolizer : public Symbolizer {
|
|||
// There are no more frames.
|
||||
break;
|
||||
}
|
||||
info->Clear();
|
||||
info->FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
SymbolizedStack *cur;
|
||||
if (top_frame) {
|
||||
cur = res;
|
||||
top_frame = false;
|
||||
} else {
|
||||
cur = SymbolizedStack::New(addr);
|
||||
cur->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
last->next = cur;
|
||||
last = cur;
|
||||
}
|
||||
|
||||
AddressInfo *info = &cur->info;
|
||||
info->function = function_name;
|
||||
// Parse <file>:<line>:<column> buffer.
|
||||
char *file_line_info = 0;
|
||||
|
@ -572,14 +580,7 @@ class POSIXSymbolizer : public Symbolizer {
|
|||
info->file = 0;
|
||||
}
|
||||
}
|
||||
if (frame_id == 0) {
|
||||
// Make sure we return at least one frame.
|
||||
AddressInfo *info = &frames[0];
|
||||
info->Clear();
|
||||
info->FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
frame_id = 1;
|
||||
}
|
||||
return frame_id;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SymbolizeData(uptr addr, DataInfo *info) override {
|
||||
|
|
|
@ -26,9 +26,8 @@ class WinSymbolizer : public Symbolizer {
|
|||
public:
|
||||
WinSymbolizer() : initialized_(false) {}
|
||||
|
||||
uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) override {
|
||||
if (max_frames == 0)
|
||||
return 0;
|
||||
SymbolizedStack *SymbolizePC(uptr addr) override {
|
||||
SymbolizedStack *frame = SymbolizedStack::New(addr);
|
||||
|
||||
BlockingMutexLock l(&dbghelp_mu_);
|
||||
if (!initialized_) {
|
||||
|
@ -60,29 +59,27 @@ class WinSymbolizer : public Symbolizer {
|
|||
BOOL got_objname = SymFromAddr(GetCurrentProcess(),
|
||||
(DWORD64)addr, &offset, symbol);
|
||||
if (!got_objname)
|
||||
return 0;
|
||||
return frame;
|
||||
|
||||
DWORD unused;
|
||||
IMAGEHLP_LINE64 line_info;
|
||||
line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
|
||||
&unused, &line_info);
|
||||
AddressInfo *info = &frames[0];
|
||||
info->Clear();
|
||||
info->function = internal_strdup(symbol->Name);
|
||||
info->function_offset = (uptr)offset;
|
||||
frame->info.function = internal_strdup(symbol->Name);
|
||||
frame->info.function_offset = (uptr)offset;
|
||||
if (got_fileline) {
|
||||
info->file = internal_strdup(line_info.FileName);
|
||||
info->line = line_info.LineNumber;
|
||||
frame->info.file = internal_strdup(line_info.FileName);
|
||||
frame->info.line = line_info.LineNumber;
|
||||
}
|
||||
|
||||
IMAGEHLP_MODULE64 mod_info;
|
||||
internal_memset(&mod_info, 0, sizeof(mod_info));
|
||||
mod_info.SizeOfStruct = sizeof(mod_info);
|
||||
if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info))
|
||||
info->FillAddressAndModuleInfo(addr, mod_info.ImageName,
|
||||
addr - (uptr)mod_info.BaseOfImage);
|
||||
return 1;
|
||||
frame->info.FillAddressAndModuleInfo(addr, mod_info.ImageName,
|
||||
addr - (uptr)mod_info.BaseOfImage);
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool CanReturnFileLineInfo() override {
|
||||
|
|
|
@ -27,6 +27,7 @@ SRCS="
|
|||
../../sanitizer_common/sanitizer_thread_registry.cc
|
||||
../../sanitizer_common/sanitizer_stackdepot.cc
|
||||
../../sanitizer_common/sanitizer_stacktrace.cc
|
||||
../../sanitizer_common/sanitizer_symbolizer.cc
|
||||
"
|
||||
|
||||
if [ "`uname -a | grep Linux`" != "" ]; then
|
||||
|
|
|
@ -59,18 +59,19 @@ struct SymbolizeContext {
|
|||
// Callback into Go.
|
||||
static void (*symbolize_cb)(SymbolizeContext *ctx);
|
||||
|
||||
ReportStack *SymbolizeCode(uptr addr) {
|
||||
ReportStack *s = ReportStack::New(addr);
|
||||
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) {
|
||||
s->info.module_offset = ctx.off;
|
||||
s->info.function = internal_strdup(ctx.func ? ctx.func : "??");
|
||||
s->info.file = internal_strdup(ctx.file ? ctx.file : "-");
|
||||
s->info.line = ctx.line;
|
||||
s->info.column = 0;
|
||||
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.column = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -19,13 +19,11 @@
|
|||
|
||||
namespace __tsan {
|
||||
|
||||
ReportStack::ReportStack() : next(nullptr), info(), suppressable(false) {}
|
||||
ReportStack::ReportStack() : frames(nullptr), suppressable(false) {}
|
||||
|
||||
ReportStack *ReportStack::New(uptr addr) {
|
||||
ReportStack *ReportStack::New() {
|
||||
void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack));
|
||||
ReportStack *res = new(mem) ReportStack();
|
||||
res->info.address = addr;
|
||||
return res;
|
||||
return new(mem) ReportStack();
|
||||
}
|
||||
|
||||
ReportLocation::ReportLocation(ReportLocationType type)
|
||||
|
@ -114,13 +112,14 @@ static const char *ReportTypeString(ReportType typ) {
|
|||
}
|
||||
|
||||
void PrintStack(const ReportStack *ent) {
|
||||
if (ent == 0) {
|
||||
if (ent == 0 || ent->frames == 0) {
|
||||
Printf(" [failed to restore the stack]\n\n");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; ent && ent->info.address; ent = ent->next, i++) {
|
||||
SymbolizedStack *frame = ent->frames;
|
||||
for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
|
||||
InternalScopedString res(2 * GetPageSizeCached());
|
||||
RenderFrame(&res, common_flags()->stack_trace_format, i, ent->info,
|
||||
RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info,
|
||||
common_flags()->strip_path_prefix, "__interceptor_");
|
||||
Printf("%s\n", res.data());
|
||||
}
|
||||
|
@ -252,10 +251,20 @@ static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
|
||||
while (FrameIsInternal(ent) && ent->next)
|
||||
ent = ent->next;
|
||||
return ent;
|
||||
static bool FrameIsInternal(const SymbolizedStack *frame) {
|
||||
if (frame == 0)
|
||||
return false;
|
||||
const char *file = frame->info.file;
|
||||
return file != 0 &&
|
||||
(internal_strstr(file, "tsan_interceptors.cc") ||
|
||||
internal_strstr(file, "sanitizer_common_interceptors.inc") ||
|
||||
internal_strstr(file, "tsan_interface_"));
|
||||
}
|
||||
|
||||
static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
|
||||
while (FrameIsInternal(frames) && frames->next)
|
||||
frames = frames->next;
|
||||
return frames;
|
||||
}
|
||||
|
||||
void PrintReport(const ReportDesc *rep) {
|
||||
|
@ -325,9 +334,11 @@ void PrintReport(const ReportDesc *rep) {
|
|||
if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
|
||||
Printf(" And %d more similar thread leaks.\n\n", rep->count - 1);
|
||||
|
||||
if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep))) {
|
||||
const AddressInfo &info = ent->info;
|
||||
ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
|
||||
if (ReportStack *stack = ChooseSummaryStack(rep)) {
|
||||
if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) {
|
||||
const AddressInfo &info = frame->info;
|
||||
ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
|
||||
}
|
||||
}
|
||||
|
||||
Printf("==================\n");
|
||||
|
@ -338,12 +349,13 @@ void PrintReport(const ReportDesc *rep) {
|
|||
const int kMainThreadId = 1;
|
||||
|
||||
void PrintStack(const ReportStack *ent) {
|
||||
if (ent == 0) {
|
||||
if (ent == 0 || ent->frames == 0) {
|
||||
Printf(" [failed to restore the stack]\n");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; ent; ent = ent->next, i++) {
|
||||
const AddressInfo &info = ent->info;
|
||||
SymbolizedStack *frame = ent->frames;
|
||||
for (int i = 0; frame; frame = frame->next, i++) {
|
||||
const AddressInfo &info = frame->info;
|
||||
Printf(" %s()\n %s:%d +0x%zx\n", info.function, info.file, info.line,
|
||||
(void *)info.module_offset);
|
||||
}
|
||||
|
|
|
@ -36,10 +36,9 @@ enum ReportType {
|
|||
};
|
||||
|
||||
struct ReportStack {
|
||||
ReportStack *next;
|
||||
AddressInfo info;
|
||||
SymbolizedStack *frames;
|
||||
bool suppressable;
|
||||
static ReportStack *New(uptr addr);
|
||||
static ReportStack *New();
|
||||
|
||||
private:
|
||||
ReportStack();
|
||||
|
|
|
@ -568,8 +568,6 @@ bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
|
|||
StackTrace trace);
|
||||
bool IsExpectedReport(uptr addr, uptr size);
|
||||
void PrintMatchedBenignRaces();
|
||||
bool FrameIsInternal(const ReportStack *frame);
|
||||
ReportStack *SkipTsanInternalFrames(ReportStack *ent);
|
||||
|
||||
#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
|
||||
# define DPrintf Printf
|
||||
|
|
|
@ -56,40 +56,43 @@ bool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void StackStripMain(ReportStack *stack) {
|
||||
ReportStack *last_frame = 0;
|
||||
ReportStack *last_frame2 = 0;
|
||||
for (ReportStack *ent = stack; ent; ent = ent->next) {
|
||||
static void StackStripMain(SymbolizedStack *frames) {
|
||||
SymbolizedStack *last_frame = nullptr;
|
||||
SymbolizedStack *last_frame2 = nullptr;
|
||||
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
|
||||
last_frame2 = last_frame;
|
||||
last_frame = ent;
|
||||
last_frame = cur;
|
||||
}
|
||||
|
||||
if (last_frame2 == 0)
|
||||
return;
|
||||
const char *last = last_frame->info.function;
|
||||
#ifndef TSAN_GO
|
||||
const char *last = last_frame->info.function;
|
||||
const char *last2 = last_frame2->info.function;
|
||||
// Strip frame above 'main'
|
||||
if (last2 && 0 == internal_strcmp(last2, "main")) {
|
||||
last_frame2->next = 0;
|
||||
last_frame->ClearAll();
|
||||
last_frame2->next = nullptr;
|
||||
// Strip our internal thread start routine.
|
||||
} else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) {
|
||||
last_frame2->next = 0;
|
||||
last_frame->ClearAll();
|
||||
last_frame2->next = nullptr;
|
||||
// Strip global ctors init.
|
||||
} else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) {
|
||||
last_frame2->next = 0;
|
||||
last_frame->ClearAll();
|
||||
last_frame2->next = nullptr;
|
||||
// If both are 0, then we probably just failed to symbolize.
|
||||
} else if (last || last2) {
|
||||
// Ensure that we recovered stack completely. Trimmed stack
|
||||
// can actually happen if we do not instrument some code,
|
||||
// so it's only a debug print. However we must try hard to not miss it
|
||||
// due to our fault.
|
||||
DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
|
||||
DPrintf("Bottom stack frame of stack %zx is missed\n", stack->info.address);
|
||||
}
|
||||
#else
|
||||
// The last frame always point into runtime (gosched0, goexit0, runtime.main).
|
||||
last_frame2->next = 0;
|
||||
(void)last;
|
||||
last_frame->ClearAll();
|
||||
last_frame2->next = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -105,12 +108,12 @@ ReportStack *SymbolizeStackId(u32 stack_id) {
|
|||
static ReportStack *SymbolizeStack(StackTrace trace) {
|
||||
if (trace.size == 0)
|
||||
return 0;
|
||||
ReportStack *stack = 0;
|
||||
SymbolizedStack *top = nullptr;
|
||||
for (uptr si = 0; si < trace.size; si++) {
|
||||
const uptr pc = trace.trace[si];
|
||||
#ifndef TSAN_GO
|
||||
// We obtain the return address, that is, address of the next instruction,
|
||||
// so offset it by 1 byte.
|
||||
// We obtain the return address, but we're interested in the previous
|
||||
// instruction.
|
||||
const uptr pc1 = StackTrace::GetPreviousInstructionPc(pc);
|
||||
#else
|
||||
// FIXME(dvyukov): Go sometimes uses address of a function as top pc.
|
||||
|
@ -118,18 +121,21 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
|
|||
if (si != trace.size - 1)
|
||||
pc1 -= 1;
|
||||
#endif
|
||||
ReportStack *ent = SymbolizeCode(pc1);
|
||||
SymbolizedStack *ent = SymbolizeCode(pc1);
|
||||
CHECK_NE(ent, 0);
|
||||
ReportStack *last = ent;
|
||||
SymbolizedStack *last = ent;
|
||||
while (last->next) {
|
||||
last->info.address = pc; // restore original pc for report
|
||||
last = last->next;
|
||||
}
|
||||
last->info.address = pc; // restore original pc for report
|
||||
last->next = stack;
|
||||
stack = ent;
|
||||
last->next = top;
|
||||
top = ent;
|
||||
}
|
||||
StackStripMain(stack);
|
||||
StackStripMain(top);
|
||||
|
||||
ReportStack *stack = ReportStack::New();
|
||||
stack->frames = top;
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
@ -547,16 +553,6 @@ static bool IsFiredSuppression(Context *ctx,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool FrameIsInternal(const ReportStack *frame) {
|
||||
if (frame == 0)
|
||||
return false;
|
||||
const char *file = frame->info.file;
|
||||
return file != 0 &&
|
||||
(internal_strstr(file, "tsan_interceptors.cc") ||
|
||||
internal_strstr(file, "sanitizer_common_interceptors.inc") ||
|
||||
internal_strstr(file, "tsan_interface_"));
|
||||
}
|
||||
|
||||
static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
|
||||
Shadow s0(thr->racy_state[0]);
|
||||
Shadow s1(thr->racy_state[1]);
|
||||
|
|
|
@ -92,7 +92,8 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
|
|||
if (stype == SuppressionNone)
|
||||
return 0;
|
||||
Suppression *s;
|
||||
for (const ReportStack *frame = stack; frame; frame = frame->next) {
|
||||
for (const SymbolizedStack *frame = stack->frames; frame;
|
||||
frame = frame->next) {
|
||||
const AddressInfo &info = frame->info;
|
||||
if (SuppressionContext::Get()->Match(info.function, stype, &s) ||
|
||||
SuppressionContext::Get()->Match(info.file, stype, &s) ||
|
||||
|
|
|
@ -55,7 +55,7 @@ bool __tsan_symbolize_external(uptr pc,
|
|||
return false;
|
||||
}
|
||||
|
||||
ReportStack *SymbolizeCode(uptr addr) {
|
||||
SymbolizedStack *SymbolizeCode(uptr addr) {
|
||||
// Check if PC comes from non-native land.
|
||||
if (addr & kExternalPCBit) {
|
||||
// Declare static to not consume too much stack space.
|
||||
|
@ -63,36 +63,17 @@ ReportStack *SymbolizeCode(uptr addr) {
|
|||
static char func_buf[1024];
|
||||
static char file_buf[1024];
|
||||
int line, col;
|
||||
ReportStack *ent = ReportStack::New(addr);
|
||||
if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf),
|
||||
file_buf, sizeof(file_buf), &line, &col))
|
||||
return ent;
|
||||
ent->info.function = internal_strdup(func_buf);
|
||||
ent->info.file = internal_strdup(file_buf);
|
||||
ent->info.line = line;
|
||||
ent->info.column = col;
|
||||
return ent;
|
||||
SymbolizedStack *frame = SymbolizedStack::New(addr);
|
||||
if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf,
|
||||
sizeof(file_buf), &line, &col)) {
|
||||
frame->info.function = internal_strdup(func_buf);
|
||||
frame->info.file = internal_strdup(file_buf);
|
||||
frame->info.line = line;
|
||||
frame->info.column = col;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
static const uptr kMaxAddrFrames = 16;
|
||||
InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
|
||||
for (uptr i = 0; i < kMaxAddrFrames; i++)
|
||||
new(&addr_frames[i]) AddressInfo();
|
||||
uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
|
||||
addr, addr_frames.data(), kMaxAddrFrames);
|
||||
if (addr_frames_num == 0)
|
||||
return ReportStack::New(addr);
|
||||
ReportStack *top = 0;
|
||||
ReportStack *bottom = 0;
|
||||
for (uptr i = 0; i < addr_frames_num; i++) {
|
||||
ReportStack *cur_entry = ReportStack::New(addr);
|
||||
cur_entry->info = addr_frames[i];
|
||||
if (i == 0)
|
||||
top = cur_entry;
|
||||
else
|
||||
bottom->next = cur_entry;
|
||||
bottom = cur_entry;
|
||||
}
|
||||
return top;
|
||||
return Symbolizer::GetOrInit()->SymbolizePC(addr);
|
||||
}
|
||||
|
||||
ReportLocation *SymbolizeData(uptr addr) {
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace __tsan {
|
|||
|
||||
void EnterSymbolizer();
|
||||
void ExitSymbolizer();
|
||||
ReportStack *SymbolizeCode(uptr addr);
|
||||
SymbolizedStack *SymbolizeCode(uptr addr);
|
||||
ReportLocation *SymbolizeData(uptr addr);
|
||||
void SymbolizeFlush();
|
||||
|
||||
|
|
|
@ -79,18 +79,26 @@ Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
|
|||
return Location();
|
||||
InitIfNecessary();
|
||||
|
||||
AddressInfo Info;
|
||||
if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) || !Info.module ||
|
||||
!*Info.module)
|
||||
SymbolizedStack *Frames = Symbolizer::GetOrInit()->SymbolizePC(Loc);
|
||||
const AddressInfo &Info = Frames->info;
|
||||
|
||||
if (!Info.module) {
|
||||
Frames->ClearAll();
|
||||
return Location(Loc);
|
||||
}
|
||||
|
||||
if (FName && Info.function)
|
||||
*FName = Info.function;
|
||||
*FName = internal_strdup(Info.function);
|
||||
|
||||
if (!Info.file)
|
||||
return ModuleLocation(Info.module, Info.module_offset);
|
||||
if (!Info.file) {
|
||||
ModuleLocation MLoc(internal_strdup(Info.module), Info.module_offset);
|
||||
Frames->ClearAll();
|
||||
return MLoc;
|
||||
}
|
||||
|
||||
return SourceLocation(Info.file, Info.line, Info.column);
|
||||
SourceLocation SLoc(internal_strdup(Info.file), Info.line, Info.column);
|
||||
Frames->ClearAll();
|
||||
return SLoc;
|
||||
}
|
||||
|
||||
Diag &Diag::operator<<(const TypeDescriptor &V) {
|
||||
|
|
Loading…
Reference in New Issue