Skip to content

Instantly share code, notes, and snippets.

@legnaleurc
Last active May 17, 2016 07:35
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 legnaleurc/27cb0e1a015c2d5590ca843fe7c2b715 to your computer and use it in GitHub Desktop.
Save legnaleurc/27cb0e1a015c2d5590ca843fe7c2b715 to your computer and use it in GitHub Desktop.
Translate C++ stack frame address to source address
#! /usr/bin/env python3
import re
import shutil
import sys
import asyncio
class BaseParser(object):
def __init__(self):
self._pattern = r'#(\d+): [^\[]+\[(.+) (.+)\]'
self._translators = {}
async def __call__(self, path):
with open(path, 'r') as fin:
for line in fin:
m = re.match(self._pattern, line)
if not m:
print(line.rstrip())
continue
frame_number = m.group(1)
binary_path = m.group(2)
address = m.group(3)
await self._fork(binary_path)
function, position = await self._feed(address, binary_path)
print('#{0} {1} [{2}]'.format(frame_number, function, position))
async def _fork(self, binary_path):
if binary_path in self._translators:
# already have one
return
cmd = self._create_resolver_command(binary_path)
p = asyncio.create_subprocess_exec(*cmd, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE)
self._translators[binary_path] = p
async def _feed(self, address, binary_path):
child = self._translators[binary_path]
line = (address + '\n').encode('utf-8')
await child.stdin.write(line)
line = await child.stdout.read_until(b'\n')
function = line.decode('utf-8').rstrip()
line = await child.stdout.read_until(b'\n')
position = line.decode('utf-8').rstrip()
return function, position
class LinuxParser(BaseParser):
def __init__(self):
super(LinuxParser, self).__init__()
def _create_resolver_command(self, binary_path):
return [
'addr2line',
'-f',
'-C',
'-e', binary_path,
]
class MacOSParser(BaseParser):
def __init__(self):
super(MacOSParser, self).__init__()
def _create_resolver_command(self, binary_path):
return [
'atos',
'-o', binary_path,
]
def create_parser(*args, **kwargs):
if shutil.which('addr2line'):
return LinuxParser(*args, **kwargs)
elif shutil.which('atos'):
return MacOSParser(*args, **kwargs)
else:
return None
async def main(args=None):
if args is None:
args = sys.argv
parser = create_parser()
await parser(args[1])
return 0
if __name__ == '__main__':
with asyncio.get_event_loop() as loop:
exit_code = loop.run_until_complete(main())
sys.exit(exit_code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment