Bug 1619840 - Remove `fix_{linux,macosx}_stack.py` and `fix_stack_using_bpsyms.py`. r=erahm
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 08 Apr 2020 06:55:54 +0000
changeset 523730 94eb0aee220a6d072e1617d98f6d358a24928ed7
parent 523729 8e4298e59e6cd8a92255e4b04938d5725c11cd66
child 523731 d500625b5ac1c19b908f8c6588d21312607ad228
push id37309
push useropoprus@mozilla.com
push dateTue, 14 Apr 2020 04:09:24 +0000
treeherdermozilla-central@dc5251d30a38 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1619840
milestone77.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1619840 - Remove `fix_{linux,macosx}_stack.py` and `fix_stack_using_bpsyms.py`. r=erahm This commit removes `test_fix_stack_using_bpsyms.py`. That test can't easily be modified to work with `fix_stacks.py` because it relies on internal implementation details of `fix_stack_using_bpsym.py`. The unit testing done in the `fix-stacks` repo provides test coverage that is as good or better. Differential Revision: https://phabricator.services.mozilla.com/D66924
browser/installer/package-manifest.in
build/moz.build
memory/replace/dmd/DMD.h
mozglue/misc/StackWalk.cpp
python/mozbuild/mozbuild/action/test_archive.py
tools/moz.build
tools/rb/README
tools/rb/fix_linux_stack.py
tools/rb/fix_macosx_stack.py
tools/rb/fix_stack_using_bpsyms.py
tools/rb/python.ini
tools/rb/test_fix_stack_using_bpsyms.py
xpcom/threads/nsTimerImpl.cpp
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -454,23 +454,16 @@ bin/libfreebl_64int_3.so
 ; media
 @RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
 @RESPATH@/gmp-clearkey/0.1/manifest.json
 
 #ifdef MOZ_DMD
 ; DMD
 @RESPATH@/dmd.py
 @RESPATH@/fix_stacks.py
-@RESPATH@/fix_stack_using_bpsyms.py
-#ifdef XP_MACOSX
-@RESPATH@/fix_macosx_stack.py
-#endif
-#ifdef XP_LINUX
-@RESPATH@/fix_linux_stack.py
-#endif
 #endif
 
 #ifdef PKG_LOCALE_MANIFEST
 #include @PKG_LOCALE_MANIFEST@
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_DEFAULT_BROWSER_AGENT)
 @BINPATH@/default-browser-agent@BIN_SUFFIX@
--- a/build/moz.build
+++ b/build/moz.build
@@ -25,24 +25,17 @@ CRAMTEST_MANIFESTS += [
 DEFINES['ACCEPTED_MAR_CHANNEL_IDS'] = CONFIG['ACCEPTED_MAR_CHANNEL_IDS']
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     PYTHON_UNITTEST_MANIFESTS += [
         'compare-mozconfig/python.ini',
     ]
 
 if CONFIG['ENABLE_TESTS'] or CONFIG['MOZ_DMD']:
-    FINAL_TARGET_FILES += [
-        '/tools/rb/fix_stack_using_bpsyms.py',
-        '/tools/rb/fix_stacks.py',
-    ]
-    if CONFIG['OS_ARCH'] == 'Darwin':
-        FINAL_TARGET_FILES += ['/tools/rb/fix_macosx_stack.py']
-    if CONFIG['OS_ARCH'] == 'Linux':
-        FINAL_TARGET_FILES += ['/tools/rb/fix_linux_stack.py']
+    FINAL_TARGET_FILES += ['/tools/rb/fix_stacks.py']
 
 if CONFIG['MOZ_DMD']:
     FINAL_TARGET_FILES += ['/memory/replace/dmd/dmd.py']
 
 # Put a useful .gdbinit in the bin directory, to be picked up automatically
 # by GDB when we debug executables there.
 FINAL_TARGET_FILES += ['/.gdbinit']
 FINAL_TARGET_PP_FILES += ['.gdbinit_python.in']
--- a/memory/replace/dmd/DMD.h
+++ b/memory/replace/dmd/DMD.h
@@ -217,22 +217,22 @@ inline void ClearReports() {
 //   // descriptions can be quite long, so they are stored separately from the
 //   // "traceTable" object so that each one only has to be written once.
 //   // This could also be an array, but again, making it an object makes it
 //   // easier to see which frames correspond to which references in the
 //   // "traceTable" object.
 //   "frameTable": {
 //     // Each property key is a frame key mentioned in the "traceTable" object.
 //     // Each property value is a string containing a frame description. Each
-//     // frame description must be in a format recognized by the stack-fixing
-//     // scripts (e.g. fix_linux_stack.py), which require a frame number at
-//     // the start. Because each stack frame description in this table can
-//     // be shared between multiple stack traces, we use a dummy value of
-//     // #00. The proper frame number can be reconstructed later by scripts
-//     // that output stack traces in a conventional non-shared format.
+//     // frame description must be in a format recognized by `fix_stacks.py`,
+//     // which requires a frame number at the start. Because each stack frame
+//     // description in this table can be shared between multiple stack
+//     // traces, we use a dummy value of #00. The proper frame number can be
+//     // reconstructed later by scripts that output stack traces in a
+//     // conventional non-shared format.
 //     "D": "#00: foo (Foo.cpp:123)",
 //     "E": "#00: bar (Bar.cpp:234)",
 //     "F": "#00: baz (Baz.cpp:345)",
 //     "G": "#00: quux (Quux.cpp:456)"
 //   }
 // }
 //
 // Implementation note: normally, this function wouldn't be templated, but in
--- a/mozglue/misc/StackWalk.cpp
+++ b/mozglue/misc/StackWalk.cpp
@@ -901,18 +901,18 @@ MFBT_API void MozFormatCodeAddress(char*
                                    uint32_t aLineNo) {
   const char* function = aFunction && aFunction[0] ? aFunction : "???";
   if (aFileName && aFileName[0]) {
     // We have a filename and (presumably) a line number. Use them.
     snprintf(aBuffer, aBufferSize, "#%02u: %s (%s:%u)", aFrameNumber, function,
              aFileName, aLineNo);
   } else if (aLibrary && aLibrary[0]) {
     // We have no filename, but we do have a library name. Use it and the
-    // library offset, and print them in a way that scripts like
-    // fix_{linux,macosx}_stacks.py can easily post-process.
+    // library offset, and print them in a way that `fix_stacks.py` can
+    // post-process.
     snprintf(aBuffer, aBufferSize, "#%02u: %s[%s +0x%" PRIxPTR "]",
              aFrameNumber, function, aLibrary,
              static_cast<uintptr_t>(aLOffset));
   } else {
     // We have nothing useful to go on. (The format string is split because
     // '??)' is a trigraph and causes a warning, sigh.)
     snprintf(aBuffer, aBufferSize,
              "#%02u: ??? (???:???"
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -291,19 +291,16 @@ ARCHIVE_FILES = {
             'dest': 'bin/plugins',
         },
         {
             'source': buildconfig.topobjdir,
             'base': 'dist/bin',
             'patterns': [
                 'dmd.py',
                 'fix_stacks.py',
-                'fix_linux_stack.py',
-                'fix_macosx_stack.py',
-                'fix_stack_using_bpsyms.py',
             ],
             'dest': 'bin',
         },
         {
             'source': buildconfig.topobjdir,
             'base': 'dist/bin/components',
             'patterns': [
                 'httpd.js',
--- a/tools/moz.build
+++ b/tools/moz.build
@@ -70,11 +70,10 @@ with Files('tryselect/docs/**'):
     SCHEDULES.exclusive = ['docs']
 
 CRAMTEST_MANIFESTS += [
     'tryselect/test/cram.ini',
 ]
 
 PYTHON_UNITTEST_MANIFESTS += [
     'lint/test/python.ini',
-    'rb/python.ini',
     'tryselect/test/python.ini',
 ]
--- a/tools/rb/README
+++ b/tools/rb/README
@@ -1,7 +1,10 @@
 This is the Refcount Balancer.  See
 https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Refcount_tracing_and_balancing
 for documentation.
 
+Note that the `fix_stacks.py` script is used in several other places in the
+repository.
+
 Previous CVS history for the perl scripts is available at:
 http://www.mozilla.org/webtools/bonsai/cvslog.cgi?file=mozilla-org/html/performance/find-leakers.pl&rev=&root=/cvsroot/
 http://www.mozilla.org/webtools/bonsai/cvslog.cgi?file=mozilla-org/html/performance/make-tree.pl&rev=&root=/cvsroot/
deleted file mode 100755
--- a/tools/rb/fix_linux_stack.py
+++ /dev/null
@@ -1,319 +0,0 @@
-#!/usr/bin/python
-# vim:sw=4:ts=4:et:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# This script uses addr2line (part of binutils) to post-process the entries
-# produced by NS_FormatCodeAddress(), which on Linux often lack a function
-# name, a file name and a line number.
-
-from __future__ import absolute_import
-
-import json
-import os
-import re
-import subprocess
-import sys
-from StringIO import StringIO
-
-objdump_section_re = re.compile(
-    "^ [0-9a-f]* ([0-9a-f ]{8}) ([0-9a-f ]{8}) ([0-9a-f ]{8}) ([0-9a-f ]{8}).*")
-
-
-def elf_section(file, section):
-    """
-    Return the requested ELF section of the file as a str, representing
-    a sequence of bytes.
-    """
-    # We can read the .gnu_debuglink section using either of:
-    #   objdump -s --section=.gnu_debuglink $file
-    #   readelf -x .gnu_debuglink $file
-    # Since readelf prints things backwards on little-endian platforms
-    # for some versions only (backwards on Fedora Core 6, forwards on
-    # Fedora 7), use objdump.
-    objdump = subprocess.Popen(['objdump', '-s', '--section=' + section, file],
-                               stdout=subprocess.PIPE,
-                               # redirect stderr so errors don't get printed
-                               stderr=subprocess.PIPE)
-    (objdump_stdout, objdump_stderr) = objdump.communicate()
-    if objdump.returncode != 0:
-        return None
-    result = ""
-    # Turn hexadecimal dump into the bytes it represents
-    for line in StringIO(objdump_stdout).readlines():
-        m = objdump_section_re.match(line)
-        if m:
-            for gnum in [0, 1, 2, 3]:
-                word = m.groups()[gnum]
-                if word != "        ":
-                    for idx in [0, 2, 4, 6]:
-                        result += chr(int(word[idx:idx + 2], 16))
-    return result
-
-
-# FIXME: Hard-coded to gdb defaults (works on Fedora and Ubuntu).
-global_debug_dir = '/usr/lib/debug'
-
-endian_re = re.compile("\s*Data:\s+.*(little|big) endian.*$")
-
-# Table of 256 values, per documentation of .gnu_debuglink sections.
-gnu_debuglink_crc32_table = [
-    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
-    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
-    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
-    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
-    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
-    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
-    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
-    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
-    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
-    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
-    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
-    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
-    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
-    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
-    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
-    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
-    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
-    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
-    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
-    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
-    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
-    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
-    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
-    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
-    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
-    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
-    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
-    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
-    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
-    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
-    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
-    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
-    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
-    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
-    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
-    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
-    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
-    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
-    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
-    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
-    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
-    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
-    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
-    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
-    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
-    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
-    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
-    0x2d02ef8d
-]
-
-
-def gnu_debuglink_crc32(stream):
-    # Note that python treats bitwise operators as though integers have
-    # an infinite number of bits (and thus such that negative integers
-    # 1-pad out to infinity).
-    crc = 0xffffffff
-    while True:
-        # Choose to read in 4096 byte chunks.
-        bytes = stream.read(4096)
-        if len(bytes) == 0:
-            break
-        for byte in bytes:
-            crc = gnu_debuglink_crc32_table[(crc ^ ord(byte)) & 0xff] ^ (crc >> 8)
-    return ~crc & 0xffffffff
-
-
-def separate_debug_file_for(file):
-    """
-    Finds a separated file with the debug sections for a binary.  Such
-    files are commonly installed by debug packages on linux distros.
-    Rules for finding them are documented in:
-    https://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html
-    """
-    def have_debug_file(debugfile):
-        return os.path.isfile(debugfile)
-
-    endian = None
-    readelf = subprocess.Popen(['readelf', '-h', file],
-                               stdout=subprocess.PIPE)
-    for line in readelf.stdout.readlines():
-        m = endian_re.match(line)
-        if m:
-            endian = m.groups()[0]
-            break
-    readelf.terminate()
-    if endian is None:
-        sys.stderr.write("Could not determine endianness of " + file + "\n")
-        return None
-
-    def word32(s):
-        if type(s) != str or len(s) != 4:
-            raise Exception("expected 4 byte string input")
-        s = list(s)
-        if endian == "big":
-            s.reverse()
-        return sum(map(lambda idx: ord(s[idx]) * (256 ** idx), range(0, 4)))
-
-    buildid = elf_section(file, ".note.gnu.build-id")
-    if buildid is not None:
-        # The build ID is an ELF note section, so it begins with a
-        # name size (4), a description size (size of contents), a
-        # type (3), and the name "GNU\0".
-        note_header = buildid[0:16]
-        buildid = buildid[16:]
-        if word32(note_header[0:4]) != 4 or \
-           word32(note_header[4:8]) != len(buildid) or \
-           word32(note_header[8:12]) != 3 or \
-           note_header[12:16] != "GNU\0":
-            sys.stderr.write("malformed .note.gnu.build_id in " + file + "\n")
-        else:
-            buildid = "".join(map(lambda ch: "%02X" % ord(ch), buildid)).lower()
-            f = os.path.join(global_debug_dir, ".build-id", buildid[0:2], buildid[2:] + ".debug")
-            if have_debug_file(f):
-                return f
-
-    debuglink = elf_section(file, ".gnu_debuglink")
-    if debuglink is not None:
-        # The debuglink section contains a string, ending with a
-        # null-terminator and then 0 to three bytes of padding to fill the
-        # current 32-bit unit.  (This padding is usually null bytes, but
-        # I've seen null-null-H, on Ubuntu x86_64.)  This is followed by
-        # a 4-byte CRC.
-        debuglink_name = debuglink[:-4]
-        null_idx = debuglink_name.find("\0")
-        if null_idx == -1 or null_idx + 4 < len(debuglink_name):
-            sys.stderr.write("Malformed .gnu_debuglink in " + file + "\n")
-            return None
-        debuglink_name = debuglink_name[0:null_idx]
-
-        debuglink_crc = word32(debuglink[-4:])
-
-        dirname = os.path.dirname(file)
-        possible_files = [
-            os.path.join(dirname, debuglink_name),
-            os.path.join(dirname, ".debug", debuglink_name),
-            os.path.join(global_debug_dir, dirname.lstrip("/"), debuglink_name)
-        ]
-        for f in possible_files:
-            if have_debug_file(f):
-                fio = open(f, mode="r")
-                file_crc = gnu_debuglink_crc32(fio)
-                fio.close()
-                if file_crc == debuglink_crc:
-                    return f
-    return None
-
-
-elf_type_re = re.compile("^\s*Type:\s+(\S+)")
-elf_text_section_re = re.compile("^\s*\[\s*\d+\]\s+\.text\s+\w+\s+(\w+)\s+(\w+)\s+")
-
-
-def address_adjustment_for(file):
-    """
-    Return the address adjustment to use for a file.
-
-    addr2line wants offsets relative to the base address for shared
-    libraries, but it wants addresses including the base address offset
-    for executables.  This returns the appropriate address adjustment to
-    add to an offset within file.  See bug 230336.
-    """
-    readelf = subprocess.Popen(['readelf', '-h', file],
-                               stdout=subprocess.PIPE)
-    elftype = None
-    for line in readelf.stdout.readlines():
-        m = elf_type_re.match(line)
-        if m:
-            elftype = m.groups()[0]
-            break
-    readelf.terminate()
-
-    if elftype != "EXEC":
-        # If we're not dealing with an executable, return 0.
-        return 0
-
-    adjustment = 0
-    readelf = subprocess.Popen(['readelf', '-S', file],
-                               stdout=subprocess.PIPE)
-    for line in readelf.stdout.readlines():
-        m = elf_text_section_re.match(line)
-        if m:
-            # Subtract the .text section's offset within the
-            # file from its base address.
-            adjustment = int(m.groups()[0], 16) - int(m.groups()[1], 16)
-            break
-    readelf.terminate()
-    return adjustment
-
-
-devnull = open(os.devnull)
-file_stuff = {}
-
-
-def addressToSymbol(file, address):
-    if file not in file_stuff:
-        debug_file = separate_debug_file_for(file) or file
-
-        # Start an addr2line process for this file. Note that addr2line
-        # sometimes prints error messages, which we want to suppress.
-        args = ['/usr/bin/addr2line', '-C', '-f', '-e', debug_file]
-        addr2line = subprocess.Popen(args, stdin=subprocess.PIPE,
-                                     stdout=subprocess.PIPE,
-                                     stderr=devnull)
-        address_adjustment = address_adjustment_for(file)
-        cache = {}
-        file_stuff[file] = (addr2line, address_adjustment, cache)
-    else:
-        (addr2line, address_adjustment, cache) = file_stuff[file]
-
-    if address in cache:
-        return cache[address]
-
-    # For each line of input, addr2line produces two lines of output.
-    addr2line.stdin.write(hex(int(address, 16) + address_adjustment) + '\n')
-    addr2line.stdin.flush()
-    result = (addr2line.stdout.readline().rstrip("\r\n"),
-              addr2line.stdout.readline().rstrip("\r\n"))
-    cache[address] = result
-    return result
-
-
-# Matches lines produced by NS_FormatCodeAddress().
-line_re = re.compile("^(.*#\d+: )(.+)\[(.+) \+(0x[0-9A-Fa-f]+)\](.*)$")
-
-
-def fixSymbols(line, jsonEscape=False):
-    result = line_re.match(line)
-    if result is not None:
-        (before, fn, file, address, after) = result.groups()
-
-        if os.path.exists(file) and os.path.isfile(file):
-            (name, fileline) = addressToSymbol(file, address)
-
-            # If addr2line gave us something useless, keep what we had before.
-            if name == "??":
-                name = fn
-            if fileline == "??:0" or fileline == "??:?":
-                fileline = file
-
-            if jsonEscape:
-                name = json.dumps(name)[1:-1]         # [1:-1] strips the quotes
-                fileline = json.dumps(fileline)[1:-1]
-
-            nl = '\n' if line[-1] == '\n' else ''
-            return "%s%s (%s)%s%s" % (before, name, fileline, after, nl)
-        else:
-            sys.stderr.write("Warning: File \"" + file + "\" does not exist.\n")
-            return line
-    else:
-        return line
-
-
-if __name__ == "__main__":
-    for line in sys.stdin:
-        sys.stdout.write(fixSymbols(line))
deleted file mode 100755
--- a/tools/rb/fix_macosx_stack.py
+++ /dev/null
@@ -1,157 +0,0 @@
-#!/usr/bin/python
-# vim:sw=4:ts=4:et:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# This script uses |atos| to post-process the entries produced by
-# NS_FormatCodeAddress(), which on Mac often lack a file name and a line
-# number.
-
-from __future__ import absolute_import, print_function
-
-import json
-import os
-import pty
-import re
-import subprocess
-import sys
-import termios
-
-
-class unbufferedLineConverter:
-    """
-    Wrap a child process that responds to each line of input with one line of
-    output.  Uses pty to trick the child into providing unbuffered output.
-    """
-
-    def __init__(self, command, args=[]):
-        pid, fd = pty.fork()
-        if pid == 0:
-            # We're the child.  Transfer control to command.
-            os.execvp(command, [command] + args)
-        else:
-            # Disable echoing.
-            attr = termios.tcgetattr(fd)
-            attr[3] = attr[3] & ~termios.ECHO
-            termios.tcsetattr(fd, termios.TCSANOW, attr)
-            # Set up a file()-like interface to the child process
-            self.r = os.fdopen(fd, "r", 1)
-            self.w = os.fdopen(os.dup(fd), "w", 1)
-
-    def convert(self, line):
-        self.w.write(line + "\n")
-        return self.r.readline().rstrip("\r\n")
-
-    @staticmethod
-    def test():
-        assert unbufferedLineConverter("rev").convert("123") == "321"
-        assert unbufferedLineConverter("cut", ["-c3"]).convert("abcde") == "c"
-        print("Pass")
-
-
-def separate_debug_file_for(file):
-    return None
-
-
-address_adjustments = {}
-
-
-def address_adjustment(file):
-    if file not in address_adjustments:
-        result = None
-        otool = subprocess.Popen(["otool", "-l", file], stdout=subprocess.PIPE)
-        while True:
-            line = otool.stdout.readline()
-            if line == "":
-                break
-            if line == "  segname __TEXT\n":
-                line = otool.stdout.readline()
-                if not line.startswith("   vmaddr "):
-                    raise Exception("unexpected otool output")
-                result = int(line[10:], 16)
-                break
-        otool.stdout.close()
-
-        if result is None:
-            raise Exception("unexpected otool output")
-
-        address_adjustments[file] = result
-
-    return address_adjustments[file]
-
-
-atoses = {}
-
-
-def addressToSymbol(file, address):
-    converter = None
-    if file not in atoses:
-        debug_file = separate_debug_file_for(file) or file
-        converter = unbufferedLineConverter(
-            '/usr/bin/xcrun', ['atos', '-arch', 'x86_64', '-o', debug_file])
-        atoses[file] = converter
-    else:
-        converter = atoses[file]
-    return converter.convert("0x%X" % address)
-
-
-cxxfilt_proc = None
-
-
-def cxxfilt(sym):
-    if cxxfilt_proc is None:
-        # --no-strip-underscores because atos already stripped the underscore
-        globals()["cxxfilt_proc"] = subprocess.Popen(['c++filt',
-                                                      '--no-strip-underscores',
-                                                      '--format', 'gnu-v3'],
-                                                     stdin=subprocess.PIPE,
-                                                     stdout=subprocess.PIPE)
-    cxxfilt_proc.stdin.write(sym + "\n")
-    return cxxfilt_proc.stdout.readline().rstrip("\n")
-
-
-# Matches lines produced by NS_FormatCodeAddress().
-line_re = re.compile("^(.*#\d+: )(.+)\[(.+) \+(0x[0-9A-Fa-f]+)\](.*)$")
-atos_name_re = re.compile("^(.+) \(in ([^)]+)\) \((.+)\)$")
-
-
-def fixSymbols(line, jsonEscape=False):
-    result = line_re.match(line)
-    if result is not None:
-        (before, fn, file, address, after) = result.groups()
-        address = int(address, 16)
-
-        if os.path.exists(file) and os.path.isfile(file):
-            address += address_adjustment(file)
-            info = addressToSymbol(file, address)
-
-            # atos output seems to have three forms:
-            #   address
-            #   address (in foo.dylib)
-            #   symbol (in foo.dylib) (file:line)
-            name_result = atos_name_re.match(info)
-            if name_result is not None:
-                # Print the first two forms as-is, and transform the third
-                (name, library, fileline) = name_result.groups()
-                # atos demangles, but occasionally it fails.  cxxfilt can mop
-                # up the remaining cases(!), which will begin with '_Z'.
-                if (name.startswith("_Z")):
-                    name = cxxfilt(name)
-                info = "%s (%s, in %s)" % (name, fileline, library)
-
-            if jsonEscape:
-                info = json.dumps(info)[1:-1]   # [1:-1] strips the quotes
-
-            nl = '\n' if line[-1] == '\n' else ''
-            return before + info + after + nl
-        else:
-            sys.stderr.write("Warning: File \"" + file + "\" does not exist.\n")
-            return line
-    else:
-        return line
-
-
-if __name__ == "__main__":
-    for line in sys.stdin:
-        sys.stdout.write(fixSymbols(line))
deleted file mode 100755
--- a/tools/rb/fix_stack_using_bpsyms.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/env python
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# This script uses breakpad symbols to post-process the entries produced by
-# NS_FormatCodeAddress(), which on TBPL builds often lack a file name and a
-# line number (and on Linux even the symbol is often bad).
-
-from __future__ import absolute_import, with_statement
-
-import bisect
-import collections
-import json
-import os
-import re
-import subprocess
-import sys
-
-here = os.path.dirname(__file__)
-FunctionSymbol = collections.namedtuple('FunctionSymbol', ['name', 'size'])
-
-
-def prettyFileName(name):
-    if name.startswith("../") or name.startswith("..\\"):
-        # dom_quickstubs.cpp and many .h files show up with relative paths that are useless
-        # and/or don't correspond to the layout of the source tree.
-        return os.path.basename(name) + ":"
-    elif name.startswith("hg:"):
-        bits = name.split(":")
-        if len(bits) == 4:
-            (junk, repo, path, rev) = bits
-            # We could construct an hgweb URL with /file/ or /annotate/, like this:
-            # return "http://%s/annotate/%s/%s#l" % (repo, rev, path)
-            return path + ":"
-    return name + ":"
-
-
-class SymbolFile:
-    def __init__(self, fn):
-        addrs = []  # list of addresses, which will be sorted once we're done initializing
-        funcs = {}  # hash: address --> (function name, function size)
-        pubaddrs = []  # list of addresses for public symbols, sorted
-        pubs = {}  # hash: address --> public symbol name
-        # hash: filenum (string) --> prettified filename ready to have a line number appended
-        files = {}
-        with open(fn) as f:
-            for line in f:
-                line = line.rstrip()
-                # https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md
-                if line.startswith("FUNC "):
-                    # FUNC [<multiple>] <address> <size> <stack_param_size> <name>
-                    line = line.replace("FUNC m ", "FUNC ")  # Ignore the multiple marker
-                    bits = line.split(None, 4)
-                    if len(bits) < 5:
-                        bits.append('unnamed_function')
-                    (junk, rva, size, ss, name) = bits
-                    rva = int(rva, 16)
-                    funcs[rva] = FunctionSymbol(name, int(size, 16))
-                    addrs.append(rva)
-                    lastFuncName = name
-                elif line.startswith("PUBLIC "):
-                    # PUBLIC [<multiple>] <address> <stack_param_size> <name>
-                    line = line.replace("PUBLIC m ", "PUBLIC ")  # Ignore the multiple marker
-                    (junk, rva, ss, name) = line.split(None, 3)
-                    rva = int(rva, 16)
-                    pubs[rva] = name
-                    pubaddrs.append(rva)
-                elif line.startswith("FILE "):
-                    # FILE <number> <name>
-                    (junk, filenum, name) = line.split(None, 2)
-                    files[filenum] = prettyFileName(name)
-                elif line[0] in "0123456789abcdef":
-                    # This is one of the "line records" corresponding to the last FUNC record
-                    # <address> <size> <line> <filenum>
-                    (rva, size, line, filenum) = line.split(None)
-                    rva = int(rva, 16)
-                    file = files[filenum]
-                    name = lastFuncName + " [" + file + line + "]"
-                    funcs[rva] = FunctionSymbol(name, int(size, 16))
-                    addrs.append(rva)
-                # skip everything else
-        self.addrs = sorted(addrs)
-        self.funcs = funcs
-        self.pubaddrs = sorted(pubaddrs)
-        self.pubs = pubs
-
-    def __find_matching_func(self, address):
-        # Look for a FUNC entry that contains the given address
-        i = bisect.bisect(self.addrs, address)
-        if i > 0:
-            func_addr = self.addrs[i - 1]
-            func = self.funcs[func_addr]
-            if address >= func_addr and address < func_addr + func.size:
-                return func.name
-
-        return None
-
-    def __find_closest_public_symbol(self, address):
-        # Find the closest PUBLIC entry that's lower than the given address
-        i = bisect.bisect(self.pubaddrs, address)
-        if i > 0:
-            return self.pubs[self.pubaddrs[i - 1]]
-        else:
-            return None
-
-    def addrToSymbol(self, address):
-        entry = self.__find_matching_func(address)
-
-        if entry is not None:
-            return entry
-
-        entry = self.__find_closest_public_symbol(address)
-
-        if entry is not None:
-            return entry
-
-        return ""
-
-
-def findIdForPath(path):
-    """Finds the breakpad id for the object file at the given path."""
-    # We should always be packaged with a "fileid" executable.
-    fileid_exe = os.path.join(here, 'fileid')
-    if not os.path.isfile(fileid_exe):
-        fileid_exe = fileid_exe + '.exe'
-        if not os.path.isfile(fileid_exe):
-            raise Exception("Could not find fileid executable in %s" % here)
-
-    if not os.path.isfile(path):
-        for suffix in ('.exe', '.dll'):
-            if os.path.isfile(path + suffix):
-                path = path + suffix
-    try:
-        return subprocess.check_output([fileid_exe, path]).rstrip()
-    except subprocess.CalledProcessError as e:
-        raise Exception("Error getting fileid for %s: %s" %
-                        (path, e.output))
-
-
-def guessSymbolFile(full_path, symbolsDir):
-    """Guess a symbol file based on an object file's basename, ignoring the path and UUID."""
-    fn = os.path.basename(full_path)
-    d1 = os.path.join(symbolsDir, fn)
-    root, _ = os.path.splitext(fn)
-    if os.path.exists(os.path.join(symbolsDir, root) + '.pdb'):
-        d1 = os.path.join(symbolsDir, root) + '.pdb'
-        fn = root
-    if not os.path.exists(d1):
-        return None
-    uuids = os.listdir(d1)
-    if len(uuids) == 0:
-        raise Exception("Missing symbol file for " + fn)
-    if len(uuids) > 1:
-        uuid = findIdForPath(full_path)
-    else:
-        uuid = uuids[0]
-    return os.path.join(d1, uuid, fn + ".sym")
-
-
-parsedSymbolFiles = {}
-
-
-def getSymbolFile(file, symbolsDir):
-    p = None
-    if file not in parsedSymbolFiles:
-        symfile = guessSymbolFile(file, symbolsDir)
-        if symfile:
-            p = SymbolFile(symfile)
-        else:
-            p = None
-        parsedSymbolFiles[file] = p
-    else:
-        p = parsedSymbolFiles[file]
-    return p
-
-
-def addressToSymbol(file, address, symbolsDir):
-    p = getSymbolFile(file, symbolsDir)
-    if p:
-        return p.addrToSymbol(address)
-    else:
-        return ""
-
-
-# Matches lines produced by NS_FormatCodeAddress().
-line_re = re.compile("^(.*#\d+: )(.+)\[(.+) \+(0x[0-9A-Fa-f]+)\](.*)$")
-
-
-def fixSymbols(line, symbolsDir, jsonEscape=False):
-    result = line_re.match(line)
-    if result is not None:
-        (before, fn, file, address, after) = result.groups()
-        address = int(address, 16)
-        symbol = addressToSymbol(file, address, symbolsDir)
-        if not symbol:
-            symbol = "%s + 0x%x" % (os.path.basename(file), address)
-        if jsonEscape:
-            symbol = json.dumps(symbol)[1:-1]   # [1:-1] strips the quotes
-        return before + symbol + after + "\n"
-    else:
-        return line
-
-
-if __name__ == "__main__":
-    symbolsDir = sys.argv[1]
-    for line in iter(sys.stdin.readline, ''):
-        sys.stdout.write(fixSymbols(line, symbolsDir))
deleted file mode 100644
--- a/tools/rb/python.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[DEFAULT]
-
-[test_fix_stack_using_bpsyms.py]
deleted file mode 100755
--- a/tools/rb/test_fix_stack_using_bpsyms.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from __future__ import absolute_import
-
-import mozunit
-import platform
-import sys
-
-from mock import MagicMock, patch
-from fix_stack_using_bpsyms import fixSymbols, SymbolFile
-
-
-def test_fixSymbols_non_stack_line():
-    line = 'foobar\n'
-    res = fixSymbols(line, '.')
-    assert res == line
-
-
-def test_fix_Symbols_missing_symbol():
-    line = '#01: foobar[{:s}foo.{:s} +0xfc258]\n'
-    result = '#01: foo.{:s} + 0xfc258\n'
-    if platform.system() == "Windows":
-        line = line.format('C:\\application\\firefox\\', 'dll')
-        result = result.format('dll')
-    else:
-        line = line.format('/home/firerox/', 'so', '')
-        result = result.format('so')
-
-    output = fixSymbols(line, '.')
-    assert output == result
-
-
-symfile_data = '''FILE 0 source.c
-FUNC fc256 2 0 func
-FUNC fc258 4 0 func_line
-fc258 2 1 0
-fc25a 2 2 0
-FUNC m fc25c 2 0 func_multiple
-PUBLIC fc256 0 func_public
-PUBLIC fc260 0 other_public'''
-
-open_name = \
-    ('builtins.%s' if sys.version_info >= (3,) else '__builtin__.%s') % 'open'
-
-
-@patch(open_name, spec=open)
-def test_parse_SymbolFile(mock_open):
-    m = MagicMock()
-    m.__enter__.return_value.__iter__.return_value = (symfile_data.split('\n'))
-    m.__exit__.return_value = False
-    mock_open.side_effect = [m]
-    symfile = SymbolFile('foo.sym')
-    assert symfile is not None
-    assert symfile.addrToSymbol(int('fc255', 16)) == ''
-    assert symfile.addrToSymbol(int('fc256', 16)) == 'func'
-    assert symfile.addrToSymbol(int('fc258', 16)) == 'func_line [source.c:1]'
-    assert symfile.addrToSymbol(int('fc25a', 16)) == 'func_line [source.c:2]'
-    assert symfile.addrToSymbol(int('fc25b', 16)) == 'func_line [source.c:2]'
-    assert symfile.addrToSymbol(int('fc260', 16)) == 'other_public'
-    assert symfile.addrToSymbol(int('fc261', 16)) == 'other_public'
-
-
-if __name__ == '__main__':
-    mozunit.main()
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -169,18 +169,17 @@ nsresult NS_NewTimerWithFuncCallback(nsI
 // |Callback::Type::Function| timer depends on the circumstances.
 //
 // - If it was explicitly named (e.g. it was initialized with
 //   InitWithNamedFuncCallback()) then that explicit name will be shown.
 //
 // - Otherwise, if we are on a platform that supports function name lookup
 //   (Mac or Linux) then the looked-up name will be shown with a
 //   "[from dladdr]" annotation. On Mac the looked-up name will be immediately
-//   useful. On Linux it'll need post-processing with
-//   tools/rb/fix_linux_stack.py.
+//   useful. On Linux it'll need post-processing with `tools/rb/fix_stacks.py`.
 //
 // - Otherwise, no name will be printed. If many timers hit this case then
 //   you'll need to re-run the workload on a Mac to find out which timers they
 //   are, and then give them explicit names.
 //
 // If you redirect this output to a file called "out", you can then
 // post-process it with a command something like the following.
 //
@@ -670,17 +669,17 @@ void nsTimerImpl::LogFiring(const Callba
             name = "???[__cxa_demangle: invalid mangled name]";
           } else if (status == -3) {
             name = "???[__cxa_demangle: invalid argument]";
           } else {
             name = "???[__cxa_demangle: unexpected status value]";
           }
 
         } else if (info.dli_fname) {
-          // The "#0: " prefix is necessary for fix_linux_stack.py to interpret
+          // The "#0: " prefix is necessary for `fix_stacks.py` to interpret
           // this string as something to convert.
           snprintf(buf, buflen, "#0: ???[%s +0x%" PRIxPTR "]\n", info.dli_fname,
                    uintptr_t(addr) - uintptr_t(info.dli_fbase));
           name = buf;
 
         } else {
           name = "???[dladdr: no symbol or shared object obtained]";
         }