Skip to content

Instantly share code, notes, and snippets.

Last active September 9, 2023 04:54
Show Gist options
  • Save luser/193572147c401c8a965c to your computer and use it in GitHub Desktop.
Save luser/193572147c401c8a965c to your computer and use it in GitHub Desktop.
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, 'application.ini')):
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))
Copy link

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:

Copy link

luser commented Mar 31, 2016

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

Copy link

willkg commented May 15, 2019 is switching to GCP soon. One of the consequences of that is that it'll no longer be saving uploaded symbols to that S3 bucket.

I suggest switching to as the SYMBOL_SERVER_URL. I'm pretty sure that'll work fine.

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