Create a gist now

Instantly share code, notes, and snippets.

@luser /
Last active Jan 13, 2017

GDB Mozilla symbol server
# Any copyright is dedicated to the Public Domain.
# A GDB Python script to fetch debug symbols from the Mozilla symbol server.
# To use, run `source /path/to/` in GDB 7.9 or newer, or
# put that in your ~/.gdbinit.
from __future__ import print_function
import gzip
import io
import itertools
import os
import shutil
import sys
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
debug_dir = os.path.join(os.environ['HOME'], '.cache', 'gdb')
cache_dir = os.path.join(debug_dir, '.build-id')
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 try_fetch_symbols(filename, build_id, destination):
debug_file = os.path.join(destination, build_id[:2], build_id[2:] + '.debug')
if os.path.exists(debug_file):
return debug_file
d = os.path.dirname(debug_file)
if not os.path.isdir(d):
except OSError:
path = os.path.join(filename, munge_build_id(build_id), filename + '.dbg.gz')
url = urljoin(SYMBOL_SERVER_URL, quote(path))
u = urlopen(url)
if u.getcode() != 200:
return None
print('Fetching symbols from {0}'.format(url))
with open(debug_file, 'wb') as f, gzip.GzipFile(fileobj=io.BytesIO(, mode='r') as z:
shutil.copyfileobj(z, f)
return debug_file
return None
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, '')):
return True
def fetch_symbols_for(objfile):
build_id = objfile.build_id if hasattr(objfile, 'build_id') else None
if getattr(objfile, 'owner', None) is not None or any(o.owner == objfile for o in gdb.objfiles()):
# This is either a separate debug file or this file already
# has symbols in a separate debug file.
if build_id and is_moz_binary(objfile.filename):
debug_file = try_fetch_symbols(os.path.basename(objfile.filename), build_id, cache_dir)
if debug_file:
def new_objfile(event):
def fetch_symbols():
Try to fetch symbols for all loaded modules.
for objfile in gdb.objfiles():
# Create our debug cache dir.
if not os.path.isdir(cache_dir):
except OSError:
# Set it as a debug-file-directory.
dirs = gdb.parameter('debug-file-directory').split(':')
except gdb.error:
dirs = []
if debug_dir not in dirs:
gdb.execute('set debug-file-directory %s' % ':'.join(dirs))
dequis commented Mar 15, 2016

I got an infinite loop in def is_moz_binary(filename): with an objfile.filename that is system-supplied DSO at 0x7fff4939b000. Stripping dirnames from that lead to an empty string.

I changed it like this:

-        if filename == '/':
+        if filename == '/' or not filename:
luser commented Mar 31, 2016

Thanks! That hang on startup had been driving me nuts but I never got around to investigating it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment