Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Sanitizer] Introduce generic stack frame rendering machinery
Summary: This commit introduces function __sanitizer::RenderFrame() that allows to render the contents of AddressInfo (essentially, symbolized stack frame) using the custom format string. This function can be used to implement stack frame formatting for both ThreadSanitizer and generic StackTrace::Print(), used in another places. This paves the way towards allowing user to control the format of stack frames, obtaining them in any format he desires, and/or enforcing the consistent output from all sanitizers. Test Plan: compiler-rt test suite Reviewers: kcc Reviewed By: kcc Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D6140 llvm-svn: 221409
- Loading branch information
Showing
11 changed files
with
343 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
//===-- sanitizer_common.cc -----------------------------------------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file is shared between sanitizers' run-time libraries. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
#include "sanitizer_stacktrace_printer.h" | ||
|
||
namespace __sanitizer { | ||
|
||
static const char *StripFunctionName(const char *function, const char *prefix) { | ||
if (function == 0) return 0; | ||
if (prefix == 0) return function; | ||
uptr prefix_len = internal_strlen(prefix); | ||
if (0 == internal_strncmp(function, prefix, prefix_len)) | ||
return function + prefix_len; | ||
return function; | ||
} | ||
|
||
static const char kDefaultFormat[] = " #%n %p %F %L"; | ||
|
||
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, | ||
const AddressInfo &info, const char *strip_path_prefix, | ||
const char *strip_func_prefix) { | ||
if (0 == internal_strcmp(format, "DEFAULT")) | ||
format = kDefaultFormat; | ||
for (const char *p = format; *p != '\0'; p++) { | ||
if (*p != '%') { | ||
buffer->append("%c", *p); | ||
continue; | ||
} | ||
p++; | ||
switch (*p) { | ||
case '%': | ||
buffer->append("%%"); | ||
break; | ||
// Frame number and all fields of AddressInfo structure. | ||
case 'n': | ||
buffer->append("%zu", frame_no); | ||
break; | ||
case 'p': | ||
buffer->append("0x%zx", info.address); | ||
break; | ||
case 'm': | ||
buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); | ||
break; | ||
case 'o': | ||
buffer->append("0x%zx", info.module_offset); | ||
break; | ||
case 'f': | ||
buffer->append("%s", StripFunctionName(info.function, strip_func_prefix)); | ||
break; | ||
case 'q': | ||
buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown | ||
? info.function_offset | ||
: 0x0); | ||
break; | ||
case 's': | ||
buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); | ||
break; | ||
case 'l': | ||
buffer->append("%d", info.line); | ||
break; | ||
case 'c': | ||
buffer->append("%d", info.column); | ||
break; | ||
// Smarter special cases. | ||
case 'F': | ||
// Function name and offset, if file is unknown. | ||
if (info.function) { | ||
buffer->append("in %s", | ||
StripFunctionName(info.function, strip_func_prefix)); | ||
if (!info.file && info.function_offset != AddressInfo::kUnknown) | ||
buffer->append("+0x%zx", info.function_offset); | ||
} | ||
break; | ||
case 'S': | ||
// File/line information. | ||
RenderSourceLocation(buffer, info.file, info.line, info.column, | ||
strip_path_prefix); | ||
break; | ||
case 'L': | ||
// Source location, or module location. | ||
if (info.file) { | ||
RenderSourceLocation(buffer, info.file, info.line, info.column, | ||
strip_path_prefix); | ||
} else if (info.module) { | ||
RenderModuleLocation(buffer, info.module, info.module_offset, | ||
strip_path_prefix); | ||
} else { | ||
buffer->append("(<unknown module>)"); | ||
} | ||
break; | ||
case 'M': | ||
// Module basename and offset, or PC. | ||
if (info.module) | ||
buffer->append("(%s+%p)", StripModuleName(info.module), | ||
(void *)info.module_offset); | ||
else | ||
buffer->append("(%p)", (void *)info.address); | ||
break; | ||
default: | ||
Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", | ||
*p, *p); | ||
Die(); | ||
} | ||
} | ||
} | ||
|
||
void RenderSourceLocation(InternalScopedString *buffer, const char *file, | ||
int line, int column, const char *strip_path_prefix) { | ||
buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); | ||
if (line > 0) { | ||
buffer->append(":%d", line); | ||
if (column > 0) | ||
buffer->append(":%d", column); | ||
} | ||
} | ||
|
||
void RenderModuleLocation(InternalScopedString *buffer, const char *module, | ||
uptr offset, const char *strip_path_prefix) { | ||
buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix), | ||
offset); | ||
} | ||
|
||
} // namespace __sanitizer |
62 changes: 62 additions & 0 deletions
62
compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
//===-- sanitizer_stacktrace_printer.h --------------------------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file is shared between sanitizers' run-time libraries. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
#ifndef SANITIZER_STACKTRACE_PRINTER_H | ||
#define SANITIZER_STACKTRACE_PRINTER_H | ||
|
||
#include "sanitizer_common.h" | ||
#include "sanitizer_symbolizer.h" | ||
|
||
namespace __sanitizer { | ||
|
||
// Render the contents of "info" structure, which represents the contents of | ||
// stack frame "frame_no" and appends it to the "buffer". "format" is a | ||
// string with placeholders, which is copied to the output with | ||
// placeholders substituted with the contents of "info". For example, | ||
// format string | ||
// " frame %n: function %F at %S" | ||
// will be turned into | ||
// " frame 10: function foo::bar() at my/file.cc:10" | ||
// You may additionally pass "strip_path_prefix" to strip prefixes of paths to | ||
// source files and modules, and "strip_func_prefix" to strip prefixes of | ||
// function names. | ||
// Here's the full list of available placeholders: | ||
// %% - represents a '%' character; | ||
// %n - frame number (copy of frame_no); | ||
// %p - PC in hex format; | ||
// %m - path to module (binary or shared object); | ||
// %o - offset in the module in hex format; | ||
// %f - function name; | ||
// %q - offset in the function in hex format (*if available*); | ||
// %s - path to source file; | ||
// %l - line in the source file; | ||
// %c - column in the source file; | ||
// %F - if function is known to be <foo>, prints "in <foo>", possibly | ||
// followed by the offset in this function, but only if source file | ||
// is unknown; | ||
// %S - prints file/line/column information; | ||
// %L - prints location information: file/line/column, if it is known, or | ||
// module+offset if it is known, or (<unknown module>) string. | ||
// %M - prints module basename and offset, if it is known, or PC. | ||
void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, | ||
const AddressInfo &info, const char *strip_path_prefix = "", | ||
const char *strip_func_prefix = ""); | ||
|
||
void RenderSourceLocation(InternalScopedString *buffer, const char *file, | ||
int line, int column, const char *strip_path_prefix); | ||
|
||
void RenderModuleLocation(InternalScopedString *buffer, const char *module, | ||
uptr offset, const char *strip_path_prefix); | ||
|
||
} // namespace __sanitizer | ||
|
||
#endif // SANITIZER_STACKTRACE_PRINTER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.