mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-04 03:44:59 +00:00
Support inline functions symbolization in Addr2Line symbolizer.
Patch by Maxim Ostapenko! Summary: Right now, Addr2Line symbolizer in asan_symbolize.py doesn't support inline functions symbolization. This might be a useful feature for using ASan on embedded systems. Test results: $ cat test.c static inline void FooBarBaz() { __sanitizer_print_stack_trace(); } int main() { FooBarBaz(); return 0; } $ clang test.c -fsanitize=address -g -O2 -o test.x && ./test.x &> /tmp/test.log $ ./projects/compiler-rt/lib/asan/scripts/asan_symbolize.py -l /tmp/test.log #0 0x42095e in __sanitizer_print_stack_trace _asan_rtl_ #1 0x4cec07 in FooBarBaz /home/max/build/llvm/asan/test.c:4 #2 0x4cec07 in main /home/max/build/llvm/asan/test.c:8 #3 0x7f89f0891ec4 in __libc_start_main /build/buildd/eglibc-2.19/csu/libc-start.c:287 Reviewers: glider, samsonov Subscribers: jevinskie, llvm-commits, ygribov Differential Revision: http://reviews.llvm.org/D12153 llvm-svn: 247642
This commit is contained in:
parent
6c6eab162a
commit
1b76da6a6c
@ -135,12 +135,13 @@ class Addr2LineSymbolizer(Symbolizer):
|
||||
super(Addr2LineSymbolizer, self).__init__()
|
||||
self.binary = binary
|
||||
self.pipe = self.open_addr2line()
|
||||
self.output_terminator = -1
|
||||
|
||||
def open_addr2line(self):
|
||||
addr2line_tool = 'addr2line'
|
||||
if binutils_prefix:
|
||||
addr2line_tool = binutils_prefix + addr2line_tool
|
||||
cmd = [addr2line_tool, '-f']
|
||||
cmd = [addr2line_tool, '-fi']
|
||||
if demangle:
|
||||
cmd += ['--demangle']
|
||||
cmd += ['-e', self.binary]
|
||||
@ -153,16 +154,23 @@ class Addr2LineSymbolizer(Symbolizer):
|
||||
"""Overrides Symbolizer.symbolize."""
|
||||
if self.binary != binary:
|
||||
return None
|
||||
lines = []
|
||||
try:
|
||||
print >> self.pipe.stdin, offset
|
||||
function_name = self.pipe.stdout.readline().rstrip()
|
||||
file_name = self.pipe.stdout.readline().rstrip()
|
||||
print >> self.pipe.stdin, self.output_terminator
|
||||
is_first_frame = True
|
||||
while True:
|
||||
function_name = self.pipe.stdout.readline().rstrip()
|
||||
file_name = self.pipe.stdout.readline().rstrip()
|
||||
if is_first_frame:
|
||||
is_first_frame = False
|
||||
elif function_name == '??':
|
||||
assert file_name == '??:0'
|
||||
break
|
||||
lines.append((function_name, file_name));
|
||||
except Exception:
|
||||
function_name = ''
|
||||
file_name = ''
|
||||
file_name = fix_filename(file_name)
|
||||
return ['%s in %s %s' % (addr, function_name, file_name)]
|
||||
|
||||
lines.append(('??', '??:0'))
|
||||
return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines]
|
||||
|
||||
class UnbufferedLineConverter(object):
|
||||
"""
|
||||
|
@ -88,10 +88,11 @@ class SymbolizerProcess {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
|
||||
|
||||
private:
|
||||
bool Restart();
|
||||
const char *SendCommandImpl(const char *command);
|
||||
bool ReadFromSymbolizer(char *buffer, uptr max_length);
|
||||
bool WriteToSymbolizer(const char *buffer, uptr length);
|
||||
bool StartSymbolizerSubprocess();
|
||||
|
||||
|
@ -194,30 +194,54 @@ class Addr2LineProcess : public SymbolizerProcess {
|
||||
const char *module_name() const { return module_name_; }
|
||||
|
||||
private:
|
||||
bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
|
||||
// Output should consist of two lines.
|
||||
int num_lines = 0;
|
||||
for (uptr i = 0; i < length; ++i) {
|
||||
if (buffer[i] == '\n')
|
||||
num_lines++;
|
||||
if (num_lines >= 2)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetArgV(const char *path_to_binary,
|
||||
const char *(&argv)[kArgVMax]) const override {
|
||||
int i = 0;
|
||||
argv[i++] = path_to_binary;
|
||||
argv[i++] = "-Cfe";
|
||||
argv[i++] = "-iCfe";
|
||||
argv[i++] = module_name_;
|
||||
argv[i++] = nullptr;
|
||||
}
|
||||
|
||||
bool ReachedEndOfOutput(const char *buffer, uptr length) const override;
|
||||
|
||||
bool ReadFromSymbolizer(char *buffer, uptr max_length) override {
|
||||
if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length))
|
||||
return false;
|
||||
// We should cut out output_terminator_ at the end of given buffer,
|
||||
// appended by addr2line to mark the end of its meaningful output.
|
||||
// We cannot scan buffer from it's beginning, because it is legal for it
|
||||
// to start with output_terminator_ in case given offset is invalid. So,
|
||||
// scanning from second character.
|
||||
char *garbage = internal_strstr(buffer + 1, output_terminator_);
|
||||
// This should never be NULL since buffer must end up with
|
||||
// output_terminator_.
|
||||
CHECK(garbage);
|
||||
// Trim the buffer.
|
||||
garbage[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *module_name_; // Owned, leaked.
|
||||
static const char output_terminator_[];
|
||||
};
|
||||
|
||||
const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n";
|
||||
|
||||
bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
|
||||
uptr length) const {
|
||||
const size_t kTerminatorLen = sizeof(output_terminator_) - 1;
|
||||
// Skip, if we read just kTerminatorLen bytes, because Addr2Line output
|
||||
// should consist at least of two pairs of lines:
|
||||
// 1. First one, corresponding to given offset to be symbolized
|
||||
// (may be equal to output_terminator_, if offset is not valid).
|
||||
// 2. Second one for output_terminator_, itself to mark the end of output.
|
||||
if (length <= kTerminatorLen) return false;
|
||||
// Addr2Line output should end up with output_terminator_.
|
||||
return !internal_memcmp(buffer + length - kTerminatorLen,
|
||||
output_terminator_, kTerminatorLen);
|
||||
}
|
||||
|
||||
class Addr2LinePool : public SymbolizerTool {
|
||||
public:
|
||||
explicit Addr2LinePool(const char *addr2line_path,
|
||||
@ -254,15 +278,18 @@ class Addr2LinePool : public SymbolizerTool {
|
||||
addr2line_pool_.push_back(addr2line);
|
||||
}
|
||||
CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
|
||||
char buffer_[kBufferSize];
|
||||
internal_snprintf(buffer_, kBufferSize, "0x%zx\n", module_offset);
|
||||
return addr2line->SendCommand(buffer_);
|
||||
char buffer[kBufferSize];
|
||||
internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n",
|
||||
module_offset, dummy_address_);
|
||||
return addr2line->SendCommand(buffer);
|
||||
}
|
||||
|
||||
static const uptr kBufferSize = 32;
|
||||
static const uptr kBufferSize = 64;
|
||||
const char *addr2line_path_;
|
||||
LowLevelAllocator *allocator_;
|
||||
InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
|
||||
static const uptr dummy_address_ =
|
||||
FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
|
||||
};
|
||||
|
||||
#if SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
|
Loading…
Reference in New Issue
Block a user