#!/usr/bin/env python3 # Copyright 2013 The Flutter Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # # On Fuchsia, in lieu of the ELF dynamic symbol table consumed through dladdr, # the Dart VM profiler consumes symbols produced by this tool, which have the # format # # struct { # uint32_t num_entries; # struct { # uint32_t offset; # uint32_t size; # uint32_t string_table_offset; # } entries[num_entries]; # const char* string_table; # } # # Entries are sorted by offset. String table entries are NUL-terminated. # # See also //third_party/dart/runtime/vm/native_symbol_fuchsia.cc import optparse import os import re import utils import subprocess import struct class Symbol: def __init__(self, offset, size, name): self.offset = offset self.size = size self.name = name parser = optparse.OptionParser() parser.add_option("--nm", type="string", help="Path to `nm` tool") parser.add_option("--binary", type="string") parser.add_option("--output", type="string") options = parser.parse_args()[0] nm = options.nm if not nm: raise Exception('--nm not specified') binary = options.binary if not binary: raise Exception('--binary not specified') output = options.output if not output: raise Exception('--output not specified') p = subprocess.Popen( [nm, "--demangle", "--numeric-sort", "--print-size", binary], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) nm_output, _ = p.communicate() nm_lines = nm_output.decode('utf-8').split('\n') regex = re.compile("([0-9A-Za-z]+) ([0-9A-Za-z]+) (t|T|w|W) (.*)") symbols = [] for line in nm_lines: m = regex.match(line) if not m: continue offset = int(m.group(1), 16) if offset > 0x100000000: # Mac adds an extra 4GB for some reason offset -= 0x100000000 size = int(m.group(2), 16) name = m.group(4).split("(")[0] if name == "__mh_execute_header": # Skip very out-of-range thing. continue symbols.append(Symbol(offset, size, name.encode('utf-8'))) if len(symbols) == 0: raise Exception(binary + " has no symbols") stream = open(output, "wb") stream.write(struct.pack("I", len(symbols))) nameOffset = 0 for symbol in symbols: stream.write(struct.pack("I", symbol.offset)) stream.write(struct.pack("I", symbol.size)) stream.write(struct.pack("I", nameOffset)) nameOffset += len(symbol.name) nameOffset += 1 for symbol in symbols: stream.write(symbol.name) stream.write(b"\0") stream.close()