Skip to content

Instantly share code, notes, and snippets.

@wancw
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wancw/5919507003871603a6a9 to your computer and use it in GitHub Desktop.
Save wancw/5919507003871603a6a9 to your computer and use it in GitHub Desktop.
Dump stack traces
A helper function to dump backtrace in more accurate information
with helper script to translate dumped address to source code line.
#!/usr/bin/env python
import os
import re
import sys
from subprocess import PIPE, Popen
from Queue import Queue
def line_wrapper(line):
def _wrapper():
return line
return _wrapper
def one_line_reader(out, prefix=''):
def _reader():
return prefix + out.readline().strip(os.linesep)
return _reader
def create_atos_pipe(image_name):
args = ["xcrun", "atos", "-o", image_name, "-l", "0x100000000"]
return Popen(args, stdin=PIPE, stdout=PIPE)
trace_pattern = re.compile("^(\s+)(.+)\(.+\) \[(0x1[0-9a-f]+)\]$")
trace_address_not_found_pattern = re.compile("(\s+)(\?+) \[(0x[0-9a-f]+)\]$")
def translate(f):
pipes = {}
output_queue = Queue()
for line in f:
line = line.strip(os.linesep)
match = trace_pattern.match(line)
if not match:
unknown_match = trace_address_not_found_pattern.match(line)
output_queue.put(line_wrapper(
''.join(unknown_match.groups()[0:2]) if unknown_match
else line
))
else:
prefix, image_name, address = match.groups()
if image_name not in pipes:
pipes[image_name] = create_atos_pipe(image_name)
atos_pipe = pipes[image_name]
atos_pipe.stdin.write('%s\n' % address)
output_queue.put(one_line_reader(atos_pipe.stdout, prefix))
for atos_pipe in pipes.itervalues():
atos_pipe.stdin.close()
while not output_queue.empty():
print output_queue.get()()
if __name__ == '__main__':
if sys.platform != 'darwin':
print '%s: This script is only for Mac' % (sys.argv[0])
exit(1)
translate(sys.stdin)
#ifndef STACK_TRACE_H
#define STACK_TRACE_H
#include <stdio.h>
/**
* dump_stack_trace() prints stack trace to `fp` as all binary image are loaded
* at 0x100000000.
*
* Add "-g" or "-gline-tables-only" to comipling options to dump more accurate
* stack trace.
*/
void dump_stack_trace(FILE *fp = stderr, const unsigned short size = 64);
#endif // STACK_TRACE_H
#include <stdio.h>
#include <execinfo.h>
#include <dlfcn.h>
namespace {
Dl_info info;
}
void dump_stack_trace(FILE *fp, const unsigned short size) {
void *traces[size];
int trace_count = backtrace(traces, size);
for (int i=1; i<trace_count; ++i) {
void *call_addr = traces[i];
if (call_addr == 0 || dladdr(call_addr, &info) == 0) {
fprintf(fp, " ??? [0x%09lx]\n", reinterpret_cast<unsigned long>(call_addr));
continue;
}
auto img_offset = reinterpret_cast<unsigned long>(call_addr) - reinterpret_cast<unsigned long>(info.dli_fbase);
auto sym_offset = reinterpret_cast<unsigned long>(call_addr) - reinterpret_cast<unsigned long>(info.dli_saddr);
fprintf(fp, " %s(%s+0x%02lx) [0x1%08lx]\n", info.dli_fname, info.dli_sname, sym_offset, img_offset);
}
fflush(fp);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment