Created
February 6, 2019 20:43
-
-
Save luser/330f27023a20137f87b9fbd0c680bd6d to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/bin/env python | |
# Any copyright is dedicated to the Public Domain. | |
# http://creativecommons.org/publicdomain/zero/1.0/ | |
import lldb | |
import gzip | |
import io | |
import itertools | |
import os | |
import shutil | |
import tarfile | |
try: | |
from urllib.request import urlopen | |
from urllib.parse import urljoin, quote | |
except ImportError: | |
from urllib2 import urlopen | |
from urllib import quote | |
from urlparse import urljoin | |
SYMBOL_SERVER_URL = 'https://symbols.mozilla.org/' | |
cache_dir = os.path.join(os.environ['HOME'], 'Library', 'SymbolCache', 'dsyms') | |
uuid_dir = os.path.join(cache_dir, 'uuids') | |
def munge_build_id(build_id): | |
''' | |
Breakpad stuffs the build id into a GUID struct so the bytes are | |
flipped from the standard presentation. | |
''' | |
b = list(map(''.join, list(zip(*[iter(build_id.upper())]*2)))) | |
return ''.join(itertools.chain(reversed(b[:4]), reversed(b[4:6]), | |
reversed(b[6:8]), b[8:16])) + '0' | |
def is_moz_binary(filename): | |
''' | |
Try to determine if a file lives in a Firefox install dir, to save | |
HTTP requests for things that aren't going to work. | |
''' | |
# The linux-gate VDSO doesn't have a real filename. | |
if not os.path.isfile(filename): | |
return False | |
while True: | |
filename = os.path.dirname(filename) | |
if filename == '/': | |
return False | |
if os.path.isfile(os.path.join(filename, 'application.ini')): | |
return True | |
def try_fetch_symbols(filename, build_id, destination, is_mac): | |
if is_mac: | |
debug_file = os.path.join(destination, filename + '.dSYM', 'Contents', | |
'Resources', 'DWARF', filename) | |
else: | |
debug_file = os.path.join(destination, build_id[:2], build_id[2:] + '.debug') | |
if os.path.exists(debug_file): | |
return debug_file | |
try: | |
d = os.path.dirname(debug_file) | |
if not os.path.isdir(d): | |
os.makedirs(d) | |
except OSError: | |
pass | |
if is_mac: | |
path = os.path.join(filename, build_id + '0', | |
filename + '.dSYM.tar.bz2') | |
else: | |
path = os.path.join(filename, munge_build_id(build_id), | |
filename + '.dbg.gz') | |
url = urljoin(SYMBOL_SERVER_URL, quote(path)) | |
try: | |
u = urlopen(url) | |
if u.getcode() != 200: | |
return None | |
print('Fetching symbols from {0}'.format(url)) | |
if is_mac: | |
with tarfile.open(fileobj=io.BytesIO(u.read()), mode='r:bz2') as t: | |
t.extractall(destination) | |
return debug_file | |
else: | |
with open(debug_file, 'wb') as f, gzip.GzipFile(fileobj=io.BytesIO(u.read()), mode='r') as z: | |
shutil.copyfileobj(z, f) | |
return debug_file | |
except Exception as e: | |
print 'Error: %s' % e | |
return None | |
def fetch_symbols(debugger, command, exe_ctx, result, internal_dict): | |
'''Attempt to fetch symbols from Mozilla's symbol server''' | |
target = exe_ctx.target | |
is_mac = target.triple.endswith('-apple-macosx') | |
for m in target.module_iter(): | |
path = m.file.fullpath | |
if m.file == m.GetSymbolFileSpec() and is_moz_binary(path): | |
uuid = m.uuid.hex | |
debug_file = try_fetch_symbols(os.path.basename(path), uuid, | |
cache_dir, is_mac) | |
if debug_file is not None: | |
print 'Downloaded: %s' % debug_file | |
lldb.debugger.HandleCommand('target symbols add ' + debug_file) | |
def __lldb_init_module(debugger, internal_dict): | |
print 'Loaded lldb-symbols. target: %s' % debugger.GetSelectedTarget() | |
try: | |
if not os.path.isdir(cache_dir): | |
os.makedirs(cache_dir) | |
except OSError: | |
pass | |
lldb.debugger.HandleCommand('command script add -f lldb_symbols.fetch_symbols fetch-symbols') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment