1be691f3bSpatrick#!/usr/bin/env python 2061da546Spatrick 3061da546Spatrickimport cmd 4061da546Spatrickimport optparse 5061da546Spatrickimport os 6061da546Spatrickimport shlex 7061da546Spatrickimport struct 8061da546Spatrickimport sys 9061da546Spatrick 10061da546SpatrickARMAG = "!<arch>\n" 11061da546SpatrickSARMAG = 8 12061da546SpatrickARFMAG = "`\n" 13061da546SpatrickAR_EFMT1 = "#1/" 14061da546Spatrick 15061da546Spatrick 16061da546Spatrickdef memdump(src, bytes_per_line=16, address=0): 17061da546Spatrick FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' 18061da546Spatrick for x in range(256)]) 19061da546Spatrick for i in range(0, len(src), bytes_per_line): 20061da546Spatrick s = src[i:i+bytes_per_line] 21061da546Spatrick hex_bytes = ' '.join(["%02x" % (ord(x)) for x in s]) 22061da546Spatrick ascii = s.translate(FILTER) 23061da546Spatrick print("%#08.8x: %-*s %s" % (address+i, bytes_per_line*3, hex_bytes, 24061da546Spatrick ascii)) 25061da546Spatrick 26061da546Spatrick 27061da546Spatrickclass Object(object): 28061da546Spatrick def __init__(self, file): 29061da546Spatrick def read_str(file, str_len): 30061da546Spatrick return file.read(str_len).rstrip('\0 ') 31061da546Spatrick 32061da546Spatrick def read_int(file, str_len, base): 33061da546Spatrick return int(read_str(file, str_len), base) 34061da546Spatrick 35061da546Spatrick self.offset = file.tell() 36061da546Spatrick self.file = file 37061da546Spatrick self.name = read_str(file, 16) 38061da546Spatrick self.date = read_int(file, 12, 10) 39061da546Spatrick self.uid = read_int(file, 6, 10) 40061da546Spatrick self.gid = read_int(file, 6, 10) 41061da546Spatrick self.mode = read_int(file, 8, 8) 42061da546Spatrick self.size = read_int(file, 10, 10) 43061da546Spatrick if file.read(2) != ARFMAG: 44061da546Spatrick raise ValueError('invalid BSD object at offset %#08.8x' % ( 45061da546Spatrick self.offset)) 46061da546Spatrick # If we have an extended name read it. Extended names start with 47061da546Spatrick name_len = 0 48061da546Spatrick if self.name.startswith(AR_EFMT1): 49061da546Spatrick name_len = int(self.name[len(AR_EFMT1):], 10) 50061da546Spatrick self.name = read_str(file, name_len) 51061da546Spatrick self.obj_offset = file.tell() 52061da546Spatrick self.obj_size = self.size - name_len 53061da546Spatrick file.seek(self.obj_size, 1) 54061da546Spatrick 55061da546Spatrick def dump(self, f=sys.stdout, flat=True): 56061da546Spatrick if flat: 57061da546Spatrick f.write('%#08.8x: %#08.8x %5u %5u %6o %#08.8x %s\n' % (self.offset, 58061da546Spatrick self.date, self.uid, self.gid, self.mode, self.size, 59061da546Spatrick self.name)) 60061da546Spatrick else: 61061da546Spatrick f.write('%#08.8x: \n' % self.offset) 62061da546Spatrick f.write(' name = "%s"\n' % self.name) 63061da546Spatrick f.write(' date = %#08.8x\n' % self.date) 64061da546Spatrick f.write(' uid = %i\n' % self.uid) 65061da546Spatrick f.write(' gid = %i\n' % self.gid) 66061da546Spatrick f.write(' mode = %o\n' % self.mode) 67061da546Spatrick f.write(' size = %#08.8x\n' % (self.size)) 68061da546Spatrick self.file.seek(self.obj_offset, 0) 69061da546Spatrick first_bytes = self.file.read(4) 70061da546Spatrick f.write('bytes = ') 71061da546Spatrick memdump(first_bytes) 72061da546Spatrick 73061da546Spatrick def get_bytes(self): 74061da546Spatrick saved_pos = self.file.tell() 75061da546Spatrick self.file.seek(self.obj_offset, 0) 76061da546Spatrick bytes = self.file.read(self.obj_size) 77061da546Spatrick self.file.seek(saved_pos, 0) 78061da546Spatrick return bytes 79061da546Spatrick 80061da546Spatrick def save(self, path=None, overwrite=False): 81061da546Spatrick ''' 82061da546Spatrick Save the contents of the object to disk using 'path' argument as 83061da546Spatrick the path, or save it to the current working directory using the 84061da546Spatrick object name. 85061da546Spatrick ''' 86061da546Spatrick 87061da546Spatrick if path is None: 88061da546Spatrick path = self.name 89061da546Spatrick if not overwrite and os.path.exists(path): 90061da546Spatrick print('error: outfile "%s" already exists' % (path)) 91061da546Spatrick return 92061da546Spatrick print('Saving "%s" to "%s"...' % (self.name, path)) 93061da546Spatrick with open(path, 'w') as f: 94061da546Spatrick f.write(self.get_bytes()) 95061da546Spatrick 96061da546Spatrick 97061da546Spatrickclass StringTable(object): 98061da546Spatrick def __init__(self, bytes): 99061da546Spatrick self.bytes = bytes 100061da546Spatrick 101061da546Spatrick def get_string(self, offset): 102061da546Spatrick length = len(self.bytes) 103061da546Spatrick if offset >= length: 104061da546Spatrick return None 105061da546Spatrick return self.bytes[offset:self.bytes.find('\0', offset)] 106061da546Spatrick 107061da546Spatrick 108061da546Spatrickclass Archive(object): 109061da546Spatrick def __init__(self, path): 110061da546Spatrick self.path = path 111061da546Spatrick self.file = open(path, 'r') 112061da546Spatrick self.objects = [] 113061da546Spatrick self.offset_to_object = {} 114061da546Spatrick if self.file.read(SARMAG) != ARMAG: 115061da546Spatrick print("error: file isn't a BSD archive") 116061da546Spatrick while True: 117061da546Spatrick try: 118061da546Spatrick self.objects.append(Object(self.file)) 119061da546Spatrick except ValueError: 120061da546Spatrick break 121061da546Spatrick 122061da546Spatrick def get_object_at_offset(self, offset): 123061da546Spatrick if offset in self.offset_to_object: 124061da546Spatrick return self.offset_to_object[offset] 125061da546Spatrick for obj in self.objects: 126061da546Spatrick if obj.offset == offset: 127061da546Spatrick self.offset_to_object[offset] = obj 128061da546Spatrick return obj 129061da546Spatrick return None 130061da546Spatrick 131061da546Spatrick def find(self, name, mtime=None, f=sys.stdout): 132061da546Spatrick ''' 133061da546Spatrick Find an object(s) by name with optional modification time. There 134061da546Spatrick can be multple objects with the same name inside and possibly with 135061da546Spatrick the same modification time within a BSD archive so clients must be 136061da546Spatrick prepared to get multiple results. 137061da546Spatrick ''' 138061da546Spatrick matches = [] 139061da546Spatrick for obj in self.objects: 140061da546Spatrick if obj.name == name and (mtime is None or mtime == obj.date): 141061da546Spatrick matches.append(obj) 142061da546Spatrick return matches 143061da546Spatrick 144061da546Spatrick @classmethod 145061da546Spatrick def dump_header(self, f=sys.stdout): 146061da546Spatrick f.write(' DATE UID GID MODE SIZE NAME\n') 147061da546Spatrick f.write(' ---------- ----- ----- ------ ---------- ' 148061da546Spatrick '--------------\n') 149061da546Spatrick 150061da546Spatrick def get_symdef(self): 151061da546Spatrick def get_uint32(file): 152061da546Spatrick '''Extract a uint32_t from the current file position.''' 153061da546Spatrick v, = struct.unpack('=I', file.read(4)) 154061da546Spatrick return v 155061da546Spatrick 156061da546Spatrick for obj in self.objects: 157061da546Spatrick symdef = [] 158061da546Spatrick if obj.name.startswith("__.SYMDEF"): 159061da546Spatrick self.file.seek(obj.obj_offset, 0) 160061da546Spatrick ranlib_byte_size = get_uint32(self.file) 161061da546Spatrick num_ranlib_structs = ranlib_byte_size/8 162061da546Spatrick str_offset_pairs = [] 163061da546Spatrick for _ in range(num_ranlib_structs): 164061da546Spatrick strx = get_uint32(self.file) 165061da546Spatrick offset = get_uint32(self.file) 166061da546Spatrick str_offset_pairs.append((strx, offset)) 167061da546Spatrick strtab_len = get_uint32(self.file) 168061da546Spatrick strtab = StringTable(self.file.read(strtab_len)) 169061da546Spatrick for s in str_offset_pairs: 170061da546Spatrick symdef.append((strtab.get_string(s[0]), s[1])) 171061da546Spatrick return symdef 172061da546Spatrick 173061da546Spatrick def get_object_dicts(self): 174061da546Spatrick ''' 175061da546Spatrick Returns an array of object dictionaries that contain they following 176061da546Spatrick keys: 177061da546Spatrick 'object': the actual bsd.Object instance 178061da546Spatrick 'symdefs': an array of symbol names that the object contains 179061da546Spatrick as found in the "__.SYMDEF" item in the archive 180061da546Spatrick ''' 181061da546Spatrick symdefs = self.get_symdef() 182061da546Spatrick symdef_dict = {} 183061da546Spatrick if symdefs: 184061da546Spatrick for (name, offset) in symdefs: 185061da546Spatrick if offset in symdef_dict: 186061da546Spatrick object_dict = symdef_dict[offset] 187061da546Spatrick else: 188061da546Spatrick object_dict = { 189061da546Spatrick 'object': self.get_object_at_offset(offset), 190061da546Spatrick 'symdefs': [] 191061da546Spatrick } 192061da546Spatrick symdef_dict[offset] = object_dict 193061da546Spatrick object_dict['symdefs'].append(name) 194061da546Spatrick object_dicts = [] 195061da546Spatrick for offset in sorted(symdef_dict): 196061da546Spatrick object_dicts.append(symdef_dict[offset]) 197061da546Spatrick return object_dicts 198061da546Spatrick 199061da546Spatrick def dump(self, f=sys.stdout, flat=True): 200061da546Spatrick f.write('%s:\n' % self.path) 201061da546Spatrick if flat: 202061da546Spatrick self.dump_header(f=f) 203061da546Spatrick for obj in self.objects: 204061da546Spatrick obj.dump(f=f, flat=flat) 205061da546Spatrick 206061da546Spatrickclass Interactive(cmd.Cmd): 207061da546Spatrick '''Interactive prompt for exploring contents of BSD archive files, type 208061da546Spatrick "help" to see a list of supported commands.''' 209061da546Spatrick image_option_parser = None 210061da546Spatrick 211061da546Spatrick def __init__(self, archives): 212061da546Spatrick cmd.Cmd.__init__(self) 213061da546Spatrick self.use_rawinput = False 214061da546Spatrick self.intro = ('Interactive BSD archive prompt, type "help" to see a ' 215061da546Spatrick 'list of supported commands.') 216061da546Spatrick self.archives = archives 217061da546Spatrick self.prompt = '% ' 218061da546Spatrick 219061da546Spatrick def default(self, line): 220061da546Spatrick '''Catch all for unknown command, which will exit the interpreter.''' 221061da546Spatrick print("unknown command: %s" % line) 222061da546Spatrick return True 223061da546Spatrick 224061da546Spatrick def do_q(self, line): 225061da546Spatrick '''Quit command''' 226061da546Spatrick return True 227061da546Spatrick 228061da546Spatrick def do_quit(self, line): 229061da546Spatrick '''Quit command''' 230061da546Spatrick return True 231061da546Spatrick 232061da546Spatrick def do_extract(self, line): 233061da546Spatrick args = shlex.split(line) 234061da546Spatrick if args: 235061da546Spatrick extracted = False 236061da546Spatrick for object_name in args: 237061da546Spatrick for archive in self.archives: 238061da546Spatrick matches = archive.find(object_name) 239061da546Spatrick if matches: 240061da546Spatrick for object in matches: 241061da546Spatrick object.save(overwrite=False) 242061da546Spatrick extracted = True 243061da546Spatrick if not extracted: 244061da546Spatrick print('error: no object matches "%s" in any archives' % ( 245061da546Spatrick object_name)) 246061da546Spatrick else: 247061da546Spatrick print('error: must specify the name of an object to extract') 248061da546Spatrick 249061da546Spatrick def do_ls(self, line): 250061da546Spatrick args = shlex.split(line) 251061da546Spatrick if args: 252061da546Spatrick for object_name in args: 253061da546Spatrick for archive in self.archives: 254061da546Spatrick matches = archive.find(object_name) 255061da546Spatrick if matches: 256061da546Spatrick for object in matches: 257061da546Spatrick object.dump(flat=False) 258061da546Spatrick else: 259061da546Spatrick print('error: no object matches "%s" in "%s"' % ( 260061da546Spatrick object_name, archive.path)) 261061da546Spatrick else: 262061da546Spatrick for archive in self.archives: 263061da546Spatrick archive.dump(flat=True) 264061da546Spatrick print('') 265061da546Spatrick 266061da546Spatrick 267061da546Spatrick 268061da546Spatrickdef main(): 269061da546Spatrick parser = optparse.OptionParser( 270061da546Spatrick prog='bsd', 271061da546Spatrick description='Utility for BSD archives') 272061da546Spatrick parser.add_option( 273061da546Spatrick '--object', 274061da546Spatrick type='string', 275061da546Spatrick dest='object_name', 276061da546Spatrick default=None, 277061da546Spatrick help=('Specify the name of a object within the BSD archive to get ' 278061da546Spatrick 'information on')) 279061da546Spatrick parser.add_option( 280061da546Spatrick '-s', '--symbol', 281061da546Spatrick type='string', 282061da546Spatrick dest='find_symbol', 283061da546Spatrick default=None, 284061da546Spatrick help=('Specify the name of a symbol within the BSD archive to get ' 285061da546Spatrick 'information on from SYMDEF')) 286061da546Spatrick parser.add_option( 287061da546Spatrick '--symdef', 288061da546Spatrick action='store_true', 289061da546Spatrick dest='symdef', 290061da546Spatrick default=False, 291061da546Spatrick help=('Dump the information in the SYMDEF.')) 292061da546Spatrick parser.add_option( 293061da546Spatrick '-v', '--verbose', 294061da546Spatrick action='store_true', 295061da546Spatrick dest='verbose', 296061da546Spatrick default=False, 297061da546Spatrick help='Enable verbose output') 298061da546Spatrick parser.add_option( 299061da546Spatrick '-e', '--extract', 300061da546Spatrick action='store_true', 301061da546Spatrick dest='extract', 302061da546Spatrick default=False, 303061da546Spatrick help=('Specify this to extract the object specified with the --object ' 304061da546Spatrick 'option. There must be only one object with a matching name or ' 305061da546Spatrick 'the --mtime option must be specified to uniquely identify a ' 306061da546Spatrick 'single object.')) 307061da546Spatrick parser.add_option( 308061da546Spatrick '-m', '--mtime', 309061da546Spatrick type='int', 310061da546Spatrick dest='mtime', 311061da546Spatrick default=None, 312061da546Spatrick help=('Specify the modification time of the object an object. This ' 313061da546Spatrick 'option is used with either the --object or --extract options.')) 314061da546Spatrick parser.add_option( 315061da546Spatrick '-o', '--outfile', 316061da546Spatrick type='string', 317061da546Spatrick dest='outfile', 318061da546Spatrick default=None, 319061da546Spatrick help=('Specify a different name or path for the file to extract when ' 320061da546Spatrick 'using the --extract option. If this option isn\'t specified, ' 321061da546Spatrick 'then the extracted object file will be extracted into the ' 322061da546Spatrick 'current working directory if a file doesn\'t already exist ' 323061da546Spatrick 'with that name.')) 324061da546Spatrick parser.add_option( 325061da546Spatrick '-i', '--interactive', 326061da546Spatrick action='store_true', 327061da546Spatrick dest='interactive', 328061da546Spatrick default=False, 329061da546Spatrick help=('Enter an interactive shell that allows users to interactively ' 330061da546Spatrick 'explore contents of .a files.')) 331061da546Spatrick 332061da546Spatrick (options, args) = parser.parse_args(sys.argv[1:]) 333061da546Spatrick 334061da546Spatrick if options.interactive: 335061da546Spatrick archives = [] 336061da546Spatrick for path in args: 337061da546Spatrick archives.append(Archive(path)) 338061da546Spatrick interpreter = Interactive(archives) 339061da546Spatrick interpreter.cmdloop() 340061da546Spatrick return 341061da546Spatrick 342061da546Spatrick for path in args: 343061da546Spatrick archive = Archive(path) 344061da546Spatrick if options.object_name: 345061da546Spatrick print('%s:\n' % (path)) 346061da546Spatrick matches = archive.find(options.object_name, options.mtime) 347061da546Spatrick if matches: 348061da546Spatrick dump_all = True 349061da546Spatrick if options.extract: 350061da546Spatrick if len(matches) == 1: 351061da546Spatrick dump_all = False 352061da546Spatrick matches[0].save(path=options.outfile, overwrite=False) 353061da546Spatrick else: 354061da546Spatrick print('error: multiple objects match "%s". Specify ' 355061da546Spatrick 'the modification time using --mtime.' % ( 356061da546Spatrick options.object_name)) 357061da546Spatrick if dump_all: 358061da546Spatrick for obj in matches: 359061da546Spatrick obj.dump(flat=False) 360061da546Spatrick else: 361061da546Spatrick print('error: object "%s" not found in archive' % ( 362061da546Spatrick options.object_name)) 363061da546Spatrick elif options.find_symbol: 364061da546Spatrick symdefs = archive.get_symdef() 365061da546Spatrick if symdefs: 366061da546Spatrick success = False 367061da546Spatrick for (name, offset) in symdefs: 368061da546Spatrick obj = archive.get_object_at_offset(offset) 369061da546Spatrick if name == options.find_symbol: 370061da546Spatrick print('Found "%s" in:' % (options.find_symbol)) 371061da546Spatrick obj.dump(flat=False) 372061da546Spatrick success = True 373061da546Spatrick if not success: 374061da546Spatrick print('Didn\'t find "%s" in any objects' % ( 375061da546Spatrick options.find_symbol)) 376061da546Spatrick else: 377061da546Spatrick print("error: no __.SYMDEF was found") 378061da546Spatrick elif options.symdef: 379061da546Spatrick object_dicts = archive.get_object_dicts() 380061da546Spatrick for object_dict in object_dicts: 381061da546Spatrick object_dict['object'].dump(flat=False) 382061da546Spatrick print("symbols:") 383061da546Spatrick for name in object_dict['symdefs']: 384061da546Spatrick print(" %s" % (name)) 385061da546Spatrick else: 386061da546Spatrick archive.dump(flat=not options.verbose) 387061da546Spatrick 388061da546Spatrick 389061da546Spatrickif __name__ == '__main__': 390061da546Spatrick main() 391061da546Spatrick 392061da546Spatrick 393061da546Spatrickdef print_mtime_error(result, dmap_mtime, actual_mtime): 394061da546Spatrick print("error: modification time in debug map (%#08.8x) doesn't " 395061da546Spatrick "match the .o file modification time (%#08.8x)" % ( 396061da546Spatrick dmap_mtime, actual_mtime), file=result) 397061da546Spatrick 398061da546Spatrick 399061da546Spatrickdef print_file_missing_error(result, path): 400061da546Spatrick print("error: file \"%s\" doesn't exist" % (path), file=result) 401061da546Spatrick 402061da546Spatrick 403061da546Spatrickdef print_multiple_object_matches(result, object_name, mtime, matches): 404061da546Spatrick print("error: multiple matches for object '%s' with with " 405061da546Spatrick "modification time %#08.8x:" % (object_name, mtime), file=result) 406061da546Spatrick Archive.dump_header(f=result) 407061da546Spatrick for match in matches: 408061da546Spatrick match.dump(f=result, flat=True) 409061da546Spatrick 410061da546Spatrick 411061da546Spatrickdef print_archive_object_error(result, object_name, mtime, archive): 412061da546Spatrick matches = archive.find(object_name, f=result) 413061da546Spatrick if len(matches) > 0: 414061da546Spatrick print("error: no objects have a modification time that " 415061da546Spatrick "matches %#08.8x for '%s'. Potential matches:" % ( 416061da546Spatrick mtime, object_name), file=result) 417061da546Spatrick Archive.dump_header(f=result) 418061da546Spatrick for match in matches: 419061da546Spatrick match.dump(f=result, flat=True) 420061da546Spatrick else: 421061da546Spatrick print("error: no object named \"%s\" found in archive:" % ( 422061da546Spatrick object_name), file=result) 423061da546Spatrick Archive.dump_header(f=result) 424061da546Spatrick for match in archive.objects: 425061da546Spatrick match.dump(f=result, flat=True) 426061da546Spatrick # archive.dump(f=result, flat=True) 427061da546Spatrick 428061da546Spatrick 429061da546Spatrickclass VerifyDebugMapCommand: 430061da546Spatrick name = "verify-debug-map-objects" 431061da546Spatrick 432061da546Spatrick def create_options(self): 433061da546Spatrick usage = "usage: %prog [options]" 434061da546Spatrick description = '''This command reports any .o files that are missing 435061da546Spatrickor whose modification times don't match in the debug map of an executable.''' 436061da546Spatrick 437061da546Spatrick self.parser = optparse.OptionParser( 438061da546Spatrick description=description, 439061da546Spatrick prog=self.name, 440061da546Spatrick usage=usage, 441061da546Spatrick add_help_option=False) 442061da546Spatrick 443061da546Spatrick self.parser.add_option( 444061da546Spatrick '-e', '--errors', 445061da546Spatrick action='store_true', 446061da546Spatrick dest='errors', 447061da546Spatrick default=False, 448061da546Spatrick help="Only show errors") 449061da546Spatrick 450061da546Spatrick def get_short_help(self): 451061da546Spatrick return "Verify debug map object files." 452061da546Spatrick 453061da546Spatrick def get_long_help(self): 454061da546Spatrick return self.help_string 455061da546Spatrick 456061da546Spatrick def __init__(self, debugger, unused): 457061da546Spatrick self.create_options() 458061da546Spatrick self.help_string = self.parser.format_help() 459061da546Spatrick 460061da546Spatrick def __call__(self, debugger, command, exe_ctx, result): 461061da546Spatrick import lldb 462061da546Spatrick # Use the Shell Lexer to properly parse up command options just like a 463061da546Spatrick # shell would 464061da546Spatrick command_args = shlex.split(command) 465061da546Spatrick 466061da546Spatrick try: 467061da546Spatrick (options, args) = self.parser.parse_args(command_args) 468061da546Spatrick except: 469061da546Spatrick result.SetError("option parsing failed") 470061da546Spatrick return 471061da546Spatrick 472061da546Spatrick # Always get program state from the SBExecutionContext passed in 473061da546Spatrick target = exe_ctx.GetTarget() 474061da546Spatrick if not target.IsValid(): 475061da546Spatrick result.SetError("invalid target") 476061da546Spatrick return 477061da546Spatrick archives = {} 478061da546Spatrick for module_spec in args: 479061da546Spatrick module = target.module[module_spec] 480061da546Spatrick if not (module and module.IsValid()): 481061da546Spatrick result.SetError('error: invalid module specification: "%s". ' 482061da546Spatrick 'Specify the full path, basename, or UUID of ' 483061da546Spatrick 'a module ' % (module_spec)) 484061da546Spatrick return 485061da546Spatrick num_symbols = module.GetNumSymbols() 486061da546Spatrick num_errors = 0 487061da546Spatrick for i in range(num_symbols): 488061da546Spatrick symbol = module.GetSymbolAtIndex(i) 489061da546Spatrick if symbol.GetType() != lldb.eSymbolTypeObjectFile: 490061da546Spatrick continue 491061da546Spatrick path = symbol.GetName() 492061da546Spatrick if not path: 493061da546Spatrick continue 494061da546Spatrick # Extract the value of the symbol by dumping the 495061da546Spatrick # symbol. The value is the mod time. 496061da546Spatrick dmap_mtime = int(str(symbol).split('value = ') 497061da546Spatrick [1].split(',')[0], 16) 498061da546Spatrick if not options.errors: 499061da546Spatrick print('%s' % (path), file=result) 500061da546Spatrick if os.path.exists(path): 501061da546Spatrick actual_mtime = int(os.stat(path).st_mtime) 502061da546Spatrick if dmap_mtime != actual_mtime: 503061da546Spatrick num_errors += 1 504061da546Spatrick if options.errors: 505061da546Spatrick print('%s' % (path), end=' ', file=result) 506061da546Spatrick print_mtime_error(result, dmap_mtime, 507061da546Spatrick actual_mtime) 508061da546Spatrick elif path[-1] == ')': 509061da546Spatrick (archive_path, object_name) = path[0:-1].split('(') 510061da546Spatrick if not archive_path and not object_name: 511061da546Spatrick num_errors += 1 512061da546Spatrick if options.errors: 513061da546Spatrick print('%s' % (path), end=' ', file=result) 514061da546Spatrick print_file_missing_error(path) 515061da546Spatrick continue 516061da546Spatrick if not os.path.exists(archive_path): 517061da546Spatrick num_errors += 1 518061da546Spatrick if options.errors: 519061da546Spatrick print('%s' % (path), end=' ', file=result) 520061da546Spatrick print_file_missing_error(archive_path) 521061da546Spatrick continue 522061da546Spatrick if archive_path in archives: 523061da546Spatrick archive = archives[archive_path] 524061da546Spatrick else: 525061da546Spatrick archive = Archive(archive_path) 526061da546Spatrick archives[archive_path] = archive 527061da546Spatrick matches = archive.find(object_name, dmap_mtime) 528061da546Spatrick num_matches = len(matches) 529061da546Spatrick if num_matches == 1: 530061da546Spatrick print('1 match', file=result) 531061da546Spatrick obj = matches[0] 532061da546Spatrick if obj.date != dmap_mtime: 533061da546Spatrick num_errors += 1 534061da546Spatrick if options.errors: 535061da546Spatrick print('%s' % (path), end=' ', file=result) 536061da546Spatrick print_mtime_error(result, dmap_mtime, obj.date) 537061da546Spatrick elif num_matches == 0: 538061da546Spatrick num_errors += 1 539061da546Spatrick if options.errors: 540061da546Spatrick print('%s' % (path), end=' ', file=result) 541061da546Spatrick print_archive_object_error(result, object_name, 542061da546Spatrick dmap_mtime, archive) 543061da546Spatrick elif num_matches > 1: 544061da546Spatrick num_errors += 1 545061da546Spatrick if options.errors: 546061da546Spatrick print('%s' % (path), end=' ', file=result) 547061da546Spatrick print_multiple_object_matches(result, 548061da546Spatrick object_name, 549061da546Spatrick dmap_mtime, matches) 550061da546Spatrick if num_errors > 0: 551061da546Spatrick print("%u errors found" % (num_errors), file=result) 552061da546Spatrick else: 553061da546Spatrick print("No errors detected in debug map", file=result) 554061da546Spatrick 555061da546Spatrick 556061da546Spatrickdef __lldb_init_module(debugger, dict): 557061da546Spatrick # This initializer is being run from LLDB in the embedded command 558061da546Spatrick # interpreter. 559061da546Spatrick # Add any commands contained in this module to LLDB 560061da546Spatrick debugger.HandleCommand( 561*f6aab3d8Srobert 'command script add -o -c %s.VerifyDebugMapCommand %s' % ( 562061da546Spatrick __name__, VerifyDebugMapCommand.name)) 563061da546Spatrick print('The "%s" command has been installed, type "help %s" for detailed ' 564061da546Spatrick 'help.' % (VerifyDebugMapCommand.name, VerifyDebugMapCommand.name)) 565