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  import lldb 
 30  import commands 
 31  import optparse 
 32  import os 
 33  import plistlib 
 34  import re 
 35  import shlex 
 36  import sys 
 37  import time 
 38  import uuid 
157   
160      """Class that represents an load address range""" 
161      sect_info_regex = re.compile('(?P<name>[^=]+)=(?P<range>.*)') 
162      addr_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*$') 
163      range_regex = re.compile( 
164          '^\s*(?P<start>0x[0-9A-Fa-f]+)\s*(?P<op>[-+])\s*(?P<end>0x[0-9A-Fa-f]+)\s*$') 
165   
166 -    def __init__(self, start_addr=None, end_addr=None, name=None): 
 170   
171      @classmethod 
183   
186   
188          match = self.sect_info_regex.match(s) 
189          if match: 
190              self.name = match.group('name') 
191              range_str = match.group('range') 
192              addr_match = self.addr_regex.match(range_str) 
193              if addr_match: 
194                  self.start_addr = int(addr_match.group('start'), 16) 
195                  self.end_addr = None 
196                  return True 
197   
198              range_match = self.range_regex.match(range_str) 
199              if range_match: 
200                  self.start_addr = int(range_match.group('start'), 16) 
201                  self.end_addr = int(range_match.group('end'), 16) 
202                  op = range_match.group('op') 
203                  if op == '+': 
204                      self.end_addr += self.start_addr 
205                  return True 
206          print 'error: invalid section info string "%s"' % s 
207          print 'Valid section info formats are:' 
208          print 'Format                Example                    Description' 
209          print '--------------------- -----------------------------------------------' 
210          print '<name>=<base>        __TEXT=0x123000             Section from base address only' 
211          print '<name>=<base>-<end>  __TEXT=0x123000-0x124000    Section from base address and end address' 
212          print '<name>=<base>+<size> __TEXT=0x123000+0x1000      Section from base address and size' 
213          return False 
 214   
216          if self.name: 
217              if self.end_addr is not None: 
218                  if self.start_addr is not None: 
219                      return "%s=[0x%16.16x - 0x%16.16x)" % ( 
220                          self.name, self.start_addr, self.end_addr) 
221              else: 
222                  if self.start_addr is not None: 
223                      return "%s=0x%16.16x" % (self.name, self.start_addr) 
224              return self.name 
225          return "<invalid>" 
  226   
229      """A class that represents an executable image and any associated data""" 
230   
232          self.path = path 
233          self.resolved_path = None 
234          self.resolved = False 
235          self.unavailable = False 
236          self.uuid = uuid 
237          self.section_infos = list() 
238          self.identifier = None 
239          self.version = None 
240          self.arch = None 
241          self.module = None 
242          self.symfile = None 
243          self.slide = None 
 244   
245      @classmethod 
262   
263 -    def dump(self, prefix): 
 264          print "%s%s" % (prefix, self) 
 265   
267          print 'path = "%s"' % (self.path) 
268          print 'resolved_path = "%s"' % (self.resolved_path) 
269          print 'resolved = %i' % (self.resolved) 
270          print 'unavailable = %i' % (self.unavailable) 
271          print 'uuid = %s' % (self.uuid) 
272          print 'section_infos = %s' % (self.section_infos) 
273          print 'identifier = "%s"' % (self.identifier) 
274          print 'version = %s' % (self.version) 
275          print 'arch = %s' % (self.arch) 
276          print 'module = %s' % (self.module) 
277          print 'symfile = "%s"' % (self.symfile) 
278          print 'slide = %i (0x%x)' % (self.slide, self.slide) 
 279   
281          s = '' 
282          if self.uuid: 
283              s += "%s " % (self.get_uuid()) 
284          if self.arch: 
285              s += "%s " % (self.arch) 
286          if self.version: 
287              s += "%s " % (self.version) 
288          resolved_path = self.get_resolved_path() 
289          if resolved_path: 
290              s += "%s " % (resolved_path) 
291          for section_info in self.section_infos: 
292              s += ", %s" % (section_info) 
293          if self.slide is not None: 
294              s += ', slide = 0x%16.16x' % self.slide 
295          return s 
 296   
298           
299          self.section_infos.append(section) 
 300   
302          for section_info in self.section_infos: 
303              if section_info.contains(load_addr): 
304                  return section_info 
305          return None 
 306   
308          if self.resolved_path: 
309              return self.resolved_path 
310          elif self.path: 
311              return self.path 
312          return None 
 313   
319   
321          if self.symfile: 
322              return os.path.basename(self.symfile) 
323          return None 
 324   
326          return self.section_infos or self.slide is not None 
 327   
329          if self.unavailable: 
330              return None   
331           
332           
333          if self.has_section_load_info(): 
334              if target: 
335                  if self.module: 
336                      if self.section_infos: 
337                          num_sections_loaded = 0 
338                          for section_info in self.section_infos: 
339                              if section_info.name: 
340                                  section = self.module.FindSection( 
341                                      section_info.name) 
342                                  if section: 
343                                      error = target.SetSectionLoadAddress( 
344                                          section, section_info.start_addr) 
345                                      if error.Success(): 
346                                          num_sections_loaded += 1 
347                                      else: 
348                                          return 'error: %s' % error.GetCString() 
349                                  else: 
350                                      return 'error: unable to find the section named "%s"' % section_info.name 
351                              else: 
352                                  return 'error: unable to find "%s" section in "%s"' % ( 
353                                      range.name, self.get_resolved_path()) 
354                          if num_sections_loaded == 0: 
355                              return 'error: no sections were successfully loaded' 
356                      else: 
357                          err = target.SetModuleLoadAddress( 
358                              self.module, self.slide) 
359                          if err.Fail(): 
360                              return err.GetCString() 
361                      return None 
362                  else: 
363                      return 'error: invalid module' 
364              else: 
365                  return 'error: invalid target' 
366          else: 
367              return 'error: no section infos' 
 368   
393   
395           
396           
397           
398           
399           
400           
401          self.resolved = True 
402          return True 
 403   
408   
410          if self.uuid: 
411              return str(self.uuid).upper() 
412          return None 
 413   
 438   
441   
443          """A class the represents the information needed to symbolicate addresses in a program""" 
444          self.target = None 
445          self.images = list()   
446          self.addr_mask = 0xffffffffffffffff 
 447   
448      @classmethod 
463   
465          s = "Symbolicator:\n" 
466          if self.target: 
467              s += "Target = '%s'\n" % (self.target) 
468              s += "Target modules:\n" 
469              for m in self.target.modules: 
470                  s += str(m) + "\n" 
471          s += "Images:\n" 
472          for image in self.images: 
473              s += '    %s\n' % (image) 
474          return s 
 475   
477          images = list() 
478          for image in self.images: 
479              if image.identifier == identifier: 
480                  images.append(image) 
481          if len(images) == 0: 
482              regex_text = '^.*\.%s$' % (re.escape(identifier)) 
483              regex = re.compile(regex_text) 
484              for image in self.images: 
485                  if regex.match(image.identifier): 
486                      images.append(image) 
487          return images 
 488   
494   
511   
513          if not self.target: 
514              self.create_target() 
515          if self.target: 
516              live_process = False 
517              process = self.target.process 
518              if process: 
519                  state = process.state 
520                  if state > lldb.eStateUnloaded and state < lldb.eStateDetached: 
521                      live_process = True 
522               
523               
524               
525              if not live_process: 
526                  image = self.find_image_containing_load_addr(load_addr) 
527                  if image: 
528                      image.add_module(self.target) 
529              symbolicated_address = Address(self.target, load_addr) 
530              if symbolicated_address.symbolicate(verbose): 
531                  if symbolicated_address.so_addr: 
532                      symbolicated_addresses = list() 
533                      symbolicated_addresses.append(symbolicated_address) 
534                       
535                      while True: 
536                          inlined_parent_so_addr = lldb.SBAddress() 
537                          inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope( 
538                              symbolicated_address.so_addr, inlined_parent_so_addr) 
539                          if not inlined_parent_sym_ctx: 
540                              break 
541                          if not inlined_parent_so_addr: 
542                              break 
543   
544                          symbolicated_address = Address( 
545                              self.target, inlined_parent_so_addr.GetLoadAddress( 
546                                  self.target)) 
547                          symbolicated_address.sym_ctx = inlined_parent_sym_ctx 
548                          symbolicated_address.so_addr = inlined_parent_so_addr 
549                          symbolicated_address.symbolicate(verbose) 
550   
551                           
552                          symbolicated_addresses.append(symbolicated_address) 
553   
554                      if symbolicated_addresses: 
555                          return symbolicated_addresses 
556          else: 
557              print 'error: no target in Symbolicator' 
558          return None 
  559   
560   
561 -def disassemble_instructions( 
562          target, 
563          instructions, 
564          pc, 
565          insts_before_pc, 
566          insts_after_pc, 
567          non_zeroeth_frame): 
 568      lines = list() 
569      pc_index = -1 
570      comment_column = 50 
571      for inst_idx, inst in enumerate(instructions): 
572          inst_pc = inst.GetAddress().GetLoadAddress(target) 
573          if pc == inst_pc: 
574              pc_index = inst_idx 
575          mnemonic = inst.GetMnemonic(target) 
576          operands = inst.GetOperands(target) 
577          comment = inst.GetComment(target) 
578           
579          lines.append("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands)) 
580          if comment: 
581              line_len = len(lines[-1]) 
582              if line_len < comment_column: 
583                  lines[-1] += ' ' * (comment_column - line_len) 
584                  lines[-1] += "; %s" % comment 
585   
586      if pc_index >= 0: 
587           
588           
589          if non_zeroeth_frame and pc_index > 0: 
590              pc_index = pc_index - 1 
591          if insts_before_pc == -1: 
592              start_idx = 0 
593          else: 
594              start_idx = pc_index - insts_before_pc 
595          if start_idx < 0: 
596              start_idx = 0 
597          if insts_before_pc == -1: 
598              end_idx = inst_idx 
599          else: 
600              end_idx = pc_index + insts_after_pc 
601          if end_idx > inst_idx: 
602              end_idx = inst_idx 
603          for i in range(start_idx, end_idx + 1): 
604              if i == pc_index: 
605                  print ' -> ', lines[i] 
606              else: 
607                  print '    ', lines[i] 
 608   
617   
626   
631   
634      for sym in module: 
635          print sym 
 636   
639   
640      usage = "usage: %prog [options] <addr1> [addr2 ...]" 
641      description = '''Symbolicate one or more addresses using LLDB's python scripting API..''' 
642      parser = optparse.OptionParser( 
643          description=description, 
644          prog='crashlog.py', 
645          usage=usage) 
646      parser.add_option( 
647          '-v', 
648          '--verbose', 
649          action='store_true', 
650          dest='verbose', 
651          help='display verbose debug info', 
652          default=False) 
653      parser.add_option( 
654          '-p', 
655          '--platform', 
656          type='string', 
657          metavar='platform', 
658          dest='platform', 
659          help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') 
660      parser.add_option( 
661          '-f', 
662          '--file', 
663          type='string', 
664          metavar='file', 
665          dest='file', 
666          help='Specify a file to use when symbolicating') 
667      parser.add_option( 
668          '-a', 
669          '--arch', 
670          type='string', 
671          metavar='arch', 
672          dest='arch', 
673          help='Specify a architecture to use when symbolicating') 
674      parser.add_option( 
675          '-s', 
676          '--slide', 
677          type='int', 
678          metavar='slide', 
679          dest='slide', 
680          help='Specify the slide to use on the file specified with the --file option', 
681          default=None) 
682      parser.add_option( 
683          '--section', 
684          type='string', 
685          action='append', 
686          dest='section_strings', 
687          help='specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr>') 
688      try: 
689          (options, args) = parser.parse_args(command_args) 
690      except: 
691          return 
692      symbolicator = Symbolicator() 
693      images = list() 
694      if options.file: 
695          image = Image(options.file) 
696          image.arch = options.arch 
697           
698           
699          if options.section_strings: 
700              for section_str in options.section_strings: 
701                  section = Section() 
702                  if section.set_from_string(section_str): 
703                      image.add_section(section) 
704                  else: 
705                      sys.exit(1) 
706          if options.slide is not None: 
707              image.slide = options.slide 
708          symbolicator.images.append(image) 
709   
710      target = symbolicator.create_target() 
711      if options.verbose: 
712          print symbolicator 
713      if target: 
714          for addr_str in args: 
715              addr = int(addr_str, 0) 
716              symbolicated_addrs = symbolicator.symbolicate( 
717                  addr, options.verbose) 
718              for symbolicated_addr in symbolicated_addrs: 
719                  print symbolicated_addr 
720              print 
721      else: 
722          print 'error: no target for %s' % (symbolicator) 
 723   
724  if __name__ == '__main__': 
725       
726      lldb.debugger = lldb.SBDebugger.Create() 
727      Symbolicate(sys.argv[1:]) 
728