diff options
Diffstat (limited to 'examples/python/bsd.py')
| -rwxr-xr-x | examples/python/bsd.py | 564 | 
1 files changed, 0 insertions, 564 deletions
diff --git a/examples/python/bsd.py b/examples/python/bsd.py deleted file mode 100755 index 3e9528c65845..000000000000 --- a/examples/python/bsd.py +++ /dev/null @@ -1,564 +0,0 @@ -#!/usr/bin/python - -import cmd -import optparse -import os -import shlex -import struct -import sys - -ARMAG = "!<arch>\n" -SARMAG = 8 -ARFMAG = "`\n" -AR_EFMT1 = "#1/" - - -def memdump(src, bytes_per_line=16, address=0): -    FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' -                     for x in range(256)]) -    for i in range(0, len(src), bytes_per_line): -        s = src[i:i+bytes_per_line] -        hex_bytes = ' '.join(["%02x" % (ord(x)) for x in s]) -        ascii = s.translate(FILTER) -        print("%#08.8x: %-*s %s" % (address+i, bytes_per_line*3, hex_bytes, -                                    ascii)) - - -class Object(object): -    def __init__(self, file): -        def read_str(file, str_len): -            return file.read(str_len).rstrip('\0 ') - -        def read_int(file, str_len, base): -            return int(read_str(file, str_len), base) - -        self.offset = file.tell() -        self.file = file -        self.name = read_str(file, 16) -        self.date = read_int(file, 12, 10) -        self.uid = read_int(file, 6, 10) -        self.gid = read_int(file, 6, 10) -        self.mode = read_int(file, 8, 8) -        self.size = read_int(file, 10, 10) -        if file.read(2) != ARFMAG: -            raise ValueError('invalid BSD object at offset %#08.8x' % ( -                             self.offset)) -        # If we have an extended name read it. Extended names start with -        name_len = 0 -        if self.name.startswith(AR_EFMT1): -            name_len = int(self.name[len(AR_EFMT1):], 10) -            self.name = read_str(file, name_len) -        self.obj_offset = file.tell() -        self.obj_size = self.size - name_len -        file.seek(self.obj_size, 1) - -    def dump(self, f=sys.stdout, flat=True): -        if flat: -            f.write('%#08.8x: %#08.8x %5u %5u %6o %#08.8x %s\n' % (self.offset, -                    self.date, self.uid, self.gid, self.mode, self.size, -                    self.name)) -        else: -            f.write('%#08.8x: \n' % self.offset) -            f.write(' name = "%s"\n' % self.name) -            f.write(' date = %#08.8x\n' % self.date) -            f.write('  uid = %i\n' % self.uid) -            f.write('  gid = %i\n' % self.gid) -            f.write(' mode = %o\n' % self.mode) -            f.write(' size = %#08.8x\n' % (self.size)) -            self.file.seek(self.obj_offset, 0) -            first_bytes = self.file.read(4) -            f.write('bytes = ') -            memdump(first_bytes) - -    def get_bytes(self): -        saved_pos = self.file.tell() -        self.file.seek(self.obj_offset, 0) -        bytes = self.file.read(self.obj_size) -        self.file.seek(saved_pos, 0) -        return bytes - -    def save(self, path=None, overwrite=False): -        ''' -            Save the contents of the object to disk using 'path' argument as -            the path, or save it to the current working directory using the -            object name. -        ''' - -        if path is None: -            path = self.name -        if not overwrite and os.path.exists(path): -            print('error: outfile "%s" already exists' % (path)) -            return -        print('Saving "%s" to "%s"...' % (self.name, path)) -        with open(path, 'w') as f: -            f.write(self.get_bytes()) - - -class StringTable(object): -    def __init__(self, bytes): -        self.bytes = bytes - -    def get_string(self, offset): -        length = len(self.bytes) -        if offset >= length: -            return None -        return self.bytes[offset:self.bytes.find('\0', offset)] - - -class Archive(object): -    def __init__(self, path): -        self.path = path -        self.file = open(path, 'r') -        self.objects = [] -        self.offset_to_object = {} -        if self.file.read(SARMAG) != ARMAG: -            print("error: file isn't a BSD archive") -        while True: -            try: -                self.objects.append(Object(self.file)) -            except ValueError: -                break - -    def get_object_at_offset(self, offset): -        if offset in self.offset_to_object: -            return self.offset_to_object[offset] -        for obj in self.objects: -            if obj.offset == offset: -                self.offset_to_object[offset] = obj -                return obj -        return None - -    def find(self, name, mtime=None, f=sys.stdout): -        ''' -            Find an object(s) by name with optional modification time. There -            can be multple objects with the same name inside and possibly with -            the same modification time within a BSD archive so clients must be -            prepared to get multiple results. -        ''' -        matches = [] -        for obj in self.objects: -            if obj.name == name and (mtime is None or mtime == obj.date): -                matches.append(obj) -        return matches - -    @classmethod -    def dump_header(self, f=sys.stdout): -        f.write('            DATE       UID   GID   MODE   SIZE       NAME\n') -        f.write('            ---------- ----- ----- ------ ---------- ' -                '--------------\n') - -    def get_symdef(self): -        def get_uint32(file): -            '''Extract a uint32_t from the current file position.''' -            v, = struct.unpack('=I', file.read(4)) -            return v - -        for obj in self.objects: -            symdef = [] -            if obj.name.startswith("__.SYMDEF"): -                self.file.seek(obj.obj_offset, 0) -                ranlib_byte_size = get_uint32(self.file) -                num_ranlib_structs = ranlib_byte_size/8 -                str_offset_pairs = [] -                for _ in range(num_ranlib_structs): -                    strx = get_uint32(self.file) -                    offset = get_uint32(self.file) -                    str_offset_pairs.append((strx, offset)) -                strtab_len = get_uint32(self.file) -                strtab = StringTable(self.file.read(strtab_len)) -                for s in str_offset_pairs: -                    symdef.append((strtab.get_string(s[0]), s[1])) -            return symdef - -    def get_object_dicts(self): -        ''' -            Returns an array of object dictionaries that contain they following -            keys: -                'object': the actual bsd.Object instance -                'symdefs': an array of symbol names that the object contains -                           as found in the "__.SYMDEF" item in the archive -        ''' -        symdefs = self.get_symdef() -        symdef_dict = {} -        if symdefs: -            for (name, offset) in symdefs: -                if offset in symdef_dict: -                    object_dict = symdef_dict[offset] -                else: -                    object_dict = { -                        'object': self.get_object_at_offset(offset), -                        'symdefs': [] -                    } -                    symdef_dict[offset] = object_dict -                object_dict['symdefs'].append(name) -        object_dicts = [] -        for offset in sorted(symdef_dict): -            object_dicts.append(symdef_dict[offset]) -        return object_dicts - -    def dump(self, f=sys.stdout, flat=True): -        f.write('%s:\n' % self.path) -        if flat: -            self.dump_header(f=f) -        for obj in self.objects: -            obj.dump(f=f, flat=flat) - -class Interactive(cmd.Cmd): -    '''Interactive prompt for exploring contents of BSD archive files, type -      "help" to see a list of supported commands.''' -    image_option_parser = None - -    def __init__(self, archives): -        cmd.Cmd.__init__(self) -        self.use_rawinput = False -        self.intro = ('Interactive  BSD archive prompt, type "help" to see a ' -                      'list of supported commands.') -        self.archives = archives -        self.prompt = '% ' - -    def default(self, line): -        '''Catch all for unknown command, which will exit the interpreter.''' -        print("unknown command: %s" % line) -        return True - -    def do_q(self, line): -        '''Quit command''' -        return True - -    def do_quit(self, line): -        '''Quit command''' -        return True - -    def do_extract(self, line): -        args = shlex.split(line) -        if args: -            extracted = False -            for object_name in args: -                for archive in self.archives: -                    matches = archive.find(object_name) -                    if matches: -                        for object in matches: -                            object.save(overwrite=False) -                            extracted = True -            if not extracted: -                print('error: no object matches "%s" in any archives' % ( -                        object_name)) -        else: -            print('error: must specify the name of an object to extract') - -    def do_ls(self, line): -        args = shlex.split(line) -        if args: -            for object_name in args: -                for archive in self.archives: -                    matches = archive.find(object_name) -                    if matches: -                        for object in matches: -                            object.dump(flat=False) -                    else: -                        print('error: no object matches "%s" in "%s"' % ( -                                object_name, archive.path)) -        else: -            for archive in self.archives: -                archive.dump(flat=True) -                print('') - - - -def main(): -    parser = optparse.OptionParser( -        prog='bsd', -        description='Utility for BSD archives') -    parser.add_option( -        '--object', -        type='string', -        dest='object_name', -        default=None, -        help=('Specify the name of a object within the BSD archive to get ' -              'information on')) -    parser.add_option( -        '-s', '--symbol', -        type='string', -        dest='find_symbol', -        default=None, -        help=('Specify the name of a symbol within the BSD archive to get ' -              'information on from SYMDEF')) -    parser.add_option( -        '--symdef', -        action='store_true', -        dest='symdef', -        default=False, -        help=('Dump the information in the SYMDEF.')) -    parser.add_option( -        '-v', '--verbose', -        action='store_true', -        dest='verbose', -        default=False, -        help='Enable verbose output') -    parser.add_option( -        '-e', '--extract', -        action='store_true', -        dest='extract', -        default=False, -        help=('Specify this to extract the object specified with the --object ' -              'option. There must be only one object with a matching name or ' -              'the --mtime option must be specified to uniquely identify a ' -              'single object.')) -    parser.add_option( -        '-m', '--mtime', -        type='int', -        dest='mtime', -        default=None, -        help=('Specify the modification time of the object an object. This ' -              'option is used with either the --object or --extract options.')) -    parser.add_option( -        '-o', '--outfile', -        type='string', -        dest='outfile', -        default=None, -        help=('Specify a different name or path for the file to extract when ' -              'using the --extract option. If this option isn\'t specified, ' -              'then the extracted object file will be extracted into the ' -              'current working directory if a file doesn\'t already exist ' -              'with that name.')) -    parser.add_option( -        '-i', '--interactive', -        action='store_true', -        dest='interactive', -        default=False, -        help=('Enter an interactive shell that allows users to interactively ' -              'explore contents of .a files.')) - -    (options, args) = parser.parse_args(sys.argv[1:]) - -    if options.interactive: -        archives = [] -        for path in args: -            archives.append(Archive(path)) -        interpreter = Interactive(archives) -        interpreter.cmdloop() -        return - -    for path in args: -        archive = Archive(path) -        if options.object_name: -            print('%s:\n' % (path)) -            matches = archive.find(options.object_name, options.mtime) -            if matches: -                dump_all = True -                if options.extract: -                    if len(matches) == 1: -                        dump_all = False -                        matches[0].save(path=options.outfile, overwrite=False) -                    else: -                        print('error: multiple objects match "%s". Specify ' -                              'the modification time using --mtime.' % ( -                                options.object_name)) -                if dump_all: -                    for obj in matches: -                        obj.dump(flat=False) -            else: -                print('error: object "%s" not found in archive' % ( -                      options.object_name)) -        elif options.find_symbol: -            symdefs = archive.get_symdef() -            if symdefs: -                success = False -                for (name, offset) in symdefs: -                    obj = archive.get_object_at_offset(offset) -                    if name == options.find_symbol: -                        print('Found "%s" in:' % (options.find_symbol)) -                        obj.dump(flat=False) -                        success = True -                if not success: -                    print('Didn\'t find "%s" in any objects' % ( -                          options.find_symbol)) -            else: -                print("error: no __.SYMDEF was found") -        elif options.symdef: -            object_dicts = archive.get_object_dicts() -            for object_dict in object_dicts: -                object_dict['object'].dump(flat=False) -                print("symbols:") -                for name in object_dict['symdefs']: -                    print("  %s" % (name)) -        else: -            archive.dump(flat=not options.verbose) - - -if __name__ == '__main__': -    main() - - -def print_mtime_error(result, dmap_mtime, actual_mtime): -    print >>result, ("error: modification time in debug map (%#08.8x) doesn't " -                     "match the .o file modification time (%#08.8x)" % ( -                        dmap_mtime, actual_mtime)) - - -def print_file_missing_error(result, path): -    print >>result, "error: file \"%s\" doesn't exist" % (path) - - -def print_multiple_object_matches(result, object_name, mtime, matches): -    print >>result, ("error: multiple matches for object '%s' with with " -                     "modification time %#08.8x:" % (object_name, mtime)) -    Archive.dump_header(f=result) -    for match in matches: -        match.dump(f=result, flat=True) - - -def print_archive_object_error(result, object_name, mtime, archive): -    matches = archive.find(object_name, f=result) -    if len(matches) > 0: -        print >>result, ("error: no objects have a modification time that " -                         "matches %#08.8x for '%s'. Potential matches:" % ( -                            mtime, object_name)) -        Archive.dump_header(f=result) -        for match in matches: -            match.dump(f=result, flat=True) -    else: -        print >>result, "error: no object named \"%s\" found in archive:" % ( -            object_name) -        Archive.dump_header(f=result) -        for match in archive.objects: -            match.dump(f=result, flat=True) -        # archive.dump(f=result, flat=True) - - -class VerifyDebugMapCommand: -    name = "verify-debug-map-objects" - -    def create_options(self): -        usage = "usage: %prog [options]" -        description = '''This command reports any .o files that are missing -or whose modification times don't match in the debug map of an executable.''' - -        self.parser = optparse.OptionParser( -            description=description, -            prog=self.name, -            usage=usage, -            add_help_option=False) - -        self.parser.add_option( -            '-e', '--errors', -            action='store_true', -            dest='errors', -            default=False, -            help="Only show errors") - -    def get_short_help(self): -        return "Verify debug map object files." - -    def get_long_help(self): -        return self.help_string - -    def __init__(self, debugger, unused): -        self.create_options() -        self.help_string = self.parser.format_help() - -    def __call__(self, debugger, command, exe_ctx, result): -        import lldb -        # Use the Shell Lexer to properly parse up command options just like a -        # shell would -        command_args = shlex.split(command) - -        try: -            (options, args) = self.parser.parse_args(command_args) -        except: -            result.SetError("option parsing failed") -            return - -        # Always get program state from the SBExecutionContext passed in -        target = exe_ctx.GetTarget() -        if not target.IsValid(): -            result.SetError("invalid target") -            return -        archives = {} -        for module_spec in args: -            module = target.module[module_spec] -            if not (module and module.IsValid()): -                result.SetError('error: invalid module specification: "%s". ' -                                'Specify the full path, basename, or UUID of ' -                                'a module ' % (module_spec)) -                return -            num_symbols = module.GetNumSymbols() -            num_errors = 0 -            for i in range(num_symbols): -                symbol = module.GetSymbolAtIndex(i) -                if symbol.GetType() != lldb.eSymbolTypeObjectFile: -                    continue -                path = symbol.GetName() -                if not path: -                    continue -                # Extract the value of the symbol by dumping the -                # symbol. The value is the mod time. -                dmap_mtime = int(str(symbol).split('value = ') -                                 [1].split(',')[0], 16) -                if not options.errors: -                    print >>result, '%s' % (path) -                if os.path.exists(path): -                    actual_mtime = int(os.stat(path).st_mtime) -                    if dmap_mtime != actual_mtime: -                        num_errors += 1 -                        if options.errors: -                            print >>result, '%s' % (path), -                        print_mtime_error(result, dmap_mtime, -                                          actual_mtime) -                elif path[-1] == ')': -                    (archive_path, object_name) = path[0:-1].split('(') -                    if not archive_path and not object_name: -                        num_errors += 1 -                        if options.errors: -                            print >>result, '%s' % (path), -                        print_file_missing_error(path) -                        continue -                    if not os.path.exists(archive_path): -                        num_errors += 1 -                        if options.errors: -                            print >>result, '%s' % (path), -                        print_file_missing_error(archive_path) -                        continue -                    if archive_path in archives: -                        archive = archives[archive_path] -                    else: -                        archive = Archive(archive_path) -                        archives[archive_path] = archive -                    matches = archive.find(object_name, dmap_mtime) -                    num_matches = len(matches) -                    if num_matches == 1: -                        print >>result, '1 match' -                        obj = matches[0] -                        if obj.date != dmap_mtime: -                            num_errors += 1 -                            if options.errors: -                                print >>result, '%s' % (path), -                            print_mtime_error(result, dmap_mtime, obj.date) -                    elif num_matches == 0: -                        num_errors += 1 -                        if options.errors: -                            print >>result, '%s' % (path), -                        print_archive_object_error(result, object_name, -                                                   dmap_mtime, archive) -                    elif num_matches > 1: -                        num_errors += 1 -                        if options.errors: -                            print >>result, '%s' % (path), -                        print_multiple_object_matches(result, -                                                      object_name, -                                                      dmap_mtime, matches) -            if num_errors > 0: -                print >>result, "%u errors found" % (num_errors) -            else: -                print >>result, "No errors detected in debug map" - - -def __lldb_init_module(debugger, dict): -    # This initializer is being run from LLDB in the embedded command -    # interpreter. -    # Add any commands contained in this module to LLDB -    debugger.HandleCommand( -        'command script add -c %s.VerifyDebugMapCommand %s' % ( -            __name__, VerifyDebugMapCommand.name)) -    print('The "%s" command has been installed, type "help %s" for detailed ' -          'help.' % (VerifyDebugMapCommand.name, VerifyDebugMapCommand.name))  | 
