File: symbols.py

package info (click to toggle)
firefox 142.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,591,884 kB
  • sloc: cpp: 7,451,570; javascript: 6,392,463; ansic: 3,712,584; python: 1,388,569; xml: 629,223; asm: 426,919; java: 184,857; sh: 63,439; makefile: 19,150; objc: 13,059; perl: 12,983; yacc: 4,583; cs: 3,846; pascal: 3,352; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (134 lines) | stat: -rw-r--r-- 3,797 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
#
# A GDB Python script to fetch debug symbols from the Mozilla symbol server.
#
# To use, run `source /path/to/symbols.py` in GDB 7.9 or newer, or
# put that in your ~/.gdbinit.


import gzip
import io
import itertools
import os
import shutil

try:
    from urllib.error import HTTPError, URLError
    from urllib.parse import quote, urljoin
    from urllib.request import urlopen
except ImportError:
    from urllib import quote

    from urllib2 import urlopen
    from urlparse import urljoin

SYMBOL_SERVER_URL = "https://symbols.mozilla.org/"

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
    try:
        d = os.path.dirname(debug_file)
        if not os.path.isdir(d):
            os.makedirs(d)
    except OSError:
        pass
    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(f"Fetching symbols from {url}")
        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 (URLError, HTTPError):
        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 == "/" or not 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.
        return
    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:
            objfile.add_separate_debug_file(debug_file)


def new_objfile(event):
    fetch_symbols_for(event.new_objfile)


def fetch_symbols():
    """
    Try to fetch symbols for all loaded modules.
    """
    for objfile in gdb.objfiles():
        fetch_symbols_for(objfile)


# Create our debug cache dir.
try:
    if not os.path.isdir(cache_dir):
        os.makedirs(cache_dir)
except OSError:
    pass

# Set it as a debug-file-directory.
try:
    dirs = gdb.parameter("debug-file-directory").split(":")
except gdb.error:
    dirs = []
if debug_dir not in dirs:
    dirs.append(debug_dir)
    gdb.execute("set debug-file-directory {}".format(":".join(dirs)))

gdb.events.new_objfile.connect(new_objfile)