@@ -414,10 +414,18 @@ class CrashLogParser:
414
414
def __init__ (self , path , verbose ):
415
415
self .path = os .path .expanduser (path )
416
416
self .verbose = verbose
417
- self .parse_mode = CrashLogParseMode .NORMAL
418
417
self .thread = None
419
418
self .app_specific_backtrace = False
420
419
self .crashlog = CrashLog (self .path , self .verbose )
420
+ self .parse_mode = CrashLogParseMode .NORMAL
421
+ self .parsers = {
422
+ CrashLogParseMode .NORMAL : self .parse_normal ,
423
+ CrashLogParseMode .THREAD : self .parse_thread ,
424
+ CrashLogParseMode .IMAGES : self .parse_images ,
425
+ CrashLogParseMode .THREGS : self .parse_thread_registers ,
426
+ CrashLogParseMode .SYSTEM : self .parse_system ,
427
+ CrashLogParseMode .INSTRS : self .parse_instructions ,
428
+ }
421
429
422
430
def parse (self ):
423
431
with open (self .path ,'r' ) as f :
@@ -445,145 +453,153 @@ def parse(self):
445
453
if len (self .crashlog .info_lines ) > 0 and len (self .crashlog .info_lines [- 1 ]):
446
454
self .crashlog .info_lines .append (line )
447
455
self .parse_mode = CrashLogParseMode .NORMAL
448
- elif self .parse_mode == CrashLogParseMode .NORMAL :
449
- if line .startswith ('Process:' ):
450
- (self .crashlog .process_name , pid_with_brackets ) = line [
451
- 8 :].strip ().split (' [' )
452
- self .crashlog .process_id = pid_with_brackets .strip ('[]' )
453
- elif line .startswith ('Path:' ):
454
- self .crashlog .process_path = line [5 :].strip ()
455
- elif line .startswith ('Identifier:' ):
456
- self .crashlog .process_identifier = line [11 :].strip ()
457
- elif line .startswith ('Version:' ):
458
- version_string = line [8 :].strip ()
459
- matched_pair = re .search ("(.+)\((.+)\)" , version_string )
460
- if matched_pair :
461
- self .crashlog .process_version = matched_pair .group (1 )
462
- self .crashlog .process_compatability_version = matched_pair .group (
463
- 2 )
464
- else :
465
- self .crashlog .process = version_string
466
- self .crashlog .process_compatability_version = version_string
467
- elif self .parent_process_regex .search (line ):
468
- parent_process_match = self .parent_process_regex .search (
469
- line )
470
- self .crashlog .parent_process_name = parent_process_match .group (1 )
471
- self .crashlog .parent_process_id = parent_process_match .group (2 )
472
- elif line .startswith ('Exception Type:' ):
473
- self .crashlog .thread_exception = line [15 :].strip ()
474
- continue
475
- elif line .startswith ('Exception Codes:' ):
476
- self .crashlog .thread_exception_data = line [16 :].strip ()
477
- continue
478
- elif line .startswith ('Exception Subtype:' ): # iOS
479
- self .crashlog .thread_exception_data = line [18 :].strip ()
480
- continue
481
- elif line .startswith ('Crashed Thread:' ):
482
- self .crashlog .crashed_thread_idx = int (line [15 :].strip ().split ()[0 ])
483
- continue
484
- elif line .startswith ('Triggered by Thread:' ): # iOS
485
- self .crashlog .crashed_thread_idx = int (line [20 :].strip ().split ()[0 ])
486
- continue
487
- elif line .startswith ('Report Version:' ):
488
- self .crashlog .version = int (line [15 :].strip ())
489
- continue
490
- elif line .startswith ('System Profile:' ):
491
- self .parse_mode = CrashLogParseMode .SYSTEM
492
- continue
493
- elif (line .startswith ('Interval Since Last Report:' ) or
494
- line .startswith ('Crashes Since Last Report:' ) or
495
- line .startswith ('Per-App Interval Since Last Report:' ) or
496
- line .startswith ('Per-App Crashes Since Last Report:' ) or
497
- line .startswith ('Sleep/Wake UUID:' ) or
498
- line .startswith ('Anonymous UUID:' )):
499
- # ignore these
500
- continue
501
- elif line .startswith ('Thread' ):
502
- thread_state_match = self .thread_state_regex .search (line )
503
- if thread_state_match :
504
- self .app_specific_backtrace = False
505
- thread_state_match = self .thread_regex .search (line )
506
- thread_idx = int (thread_state_match .group (1 ))
507
- self .parse_mode = CrashLogParseMode .THREGS
508
- self .thread = self .crashlog .threads [thread_idx ]
509
- continue
510
- thread_insts_match = self .thread_instrs_regex .search (line )
511
- if thread_insts_match :
512
- self .parse_mode = CrashLogParseMode .INSTRS
513
- continue
514
- thread_match = self .thread_regex .search (line )
515
- if thread_match :
516
- self .app_specific_backtrace = False
517
- self .parse_mode = CrashLogParseMode .THREAD
518
- thread_idx = int (thread_match .group (1 ))
519
- self .thread = self .crashlog .Thread (thread_idx , False )
520
- continue
521
- continue
522
- elif line .startswith ('Binary Images:' ):
523
- self .parse_mode = CrashLogParseMode .IMAGES
524
- continue
525
- elif line .startswith ('Application Specific Backtrace' ):
526
- app_backtrace_match = self .app_backtrace_regex .search (line )
527
- if app_backtrace_match :
528
- self .parse_mode = CrashLogParseMode .THREAD
529
- self .app_specific_backtrace = True
530
- idx = int (app_backtrace_match .group (1 ))
531
- self .thread = self .crashlog .Thread (idx , True )
532
- elif line .startswith ('Last Exception Backtrace:' ): # iOS
533
- self .parse_mode = CrashLogParseMode .THREAD
534
- self .app_specific_backtrace = True
535
- idx = 1
536
- self .thread = self .crashlog .Thread (idx , True )
537
- self .crashlog .info_lines .append (line .strip ())
538
- elif self .parse_mode == CrashLogParseMode .THREAD :
539
- if line .startswith ('Thread' ):
540
- continue
541
- if self .null_frame_regex .search (line ):
542
- print ('warning: thread parser ignored null-frame: "%s"' % line )
543
- continue
544
- frame_match = self .frame_regex .search (line )
545
- if frame_match :
546
- (frame_id , frame_img_name , _ , frame_img_version , _ ,
547
- frame_addr , frame_ofs ) = frame_match .groups ()
548
- ident = frame_img_name
549
- self .thread .add_ident (ident )
550
- if ident not in self .crashlog .idents :
551
- self .crashlog .idents .append (ident )
552
- self .thread .frames .append (self .crashlog .Frame (int (frame_id ), int (
553
- frame_addr , 0 ), frame_ofs ))
554
- else :
555
- print ('error: frame regex failed for line: "%s"' % line )
556
- elif self .parse_mode == CrashLogParseMode .IMAGES :
557
- image_match = self .image_regex_uuid .search (line )
558
- if image_match :
559
- (img_lo , img_hi , img_name , _ , img_version , _ ,
560
- _ , img_uuid , img_path ) = image_match .groups ()
561
- image = self .crashlog .DarwinImage (int (img_lo , 0 ), int (img_hi , 0 ),
562
- img_name .strip (),
563
- img_version .strip ()
564
- if img_version else "" ,
565
- uuid .UUID (img_uuid ), img_path ,
566
- self .verbose )
567
- self .crashlog .images .append (image )
568
- else :
569
- print ("error: image regex failed for: %s" % line )
570
-
571
- elif self .parse_mode == CrashLogParseMode .THREGS :
572
- stripped_line = line .strip ()
573
- # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00"
574
- reg_values = re .findall (
575
- '([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *' , stripped_line )
576
- for reg_value in reg_values :
577
- (reg , value ) = reg_value .split (': ' )
578
- self .thread .registers [reg .strip ()] = int (value , 0 )
579
- elif self .parse_mode == CrashLogParseMode .SYSTEM :
580
- self .crashlog .system_profile .append (line )
581
- elif self .parse_mode == CrashLogParseMode .INSTRS :
582
- pass
456
+ else :
457
+ self .parsers [self .parse_mode ](line )
583
458
584
459
return self .crashlog
585
460
586
461
462
+ def parse_normal (self , line ):
463
+ if line .startswith ('Process:' ):
464
+ (self .crashlog .process_name , pid_with_brackets ) = line [
465
+ 8 :].strip ().split (' [' )
466
+ self .crashlog .process_id = pid_with_brackets .strip ('[]' )
467
+ elif line .startswith ('Path:' ):
468
+ self .crashlog .process_path = line [5 :].strip ()
469
+ elif line .startswith ('Identifier:' ):
470
+ self .crashlog .process_identifier = line [11 :].strip ()
471
+ elif line .startswith ('Version:' ):
472
+ version_string = line [8 :].strip ()
473
+ matched_pair = re .search ("(.+)\((.+)\)" , version_string )
474
+ if matched_pair :
475
+ self .crashlog .process_version = matched_pair .group (1 )
476
+ self .crashlog .process_compatability_version = matched_pair .group (
477
+ 2 )
478
+ else :
479
+ self .crashlog .process = version_string
480
+ self .crashlog .process_compatability_version = version_string
481
+ elif self .parent_process_regex .search (line ):
482
+ parent_process_match = self .parent_process_regex .search (
483
+ line )
484
+ self .crashlog .parent_process_name = parent_process_match .group (1 )
485
+ self .crashlog .parent_process_id = parent_process_match .group (2 )
486
+ elif line .startswith ('Exception Type:' ):
487
+ self .crashlog .thread_exception = line [15 :].strip ()
488
+ return
489
+ elif line .startswith ('Exception Codes:' ):
490
+ self .crashlog .thread_exception_data = line [16 :].strip ()
491
+ return
492
+ elif line .startswith ('Exception Subtype:' ): # iOS
493
+ self .crashlog .thread_exception_data = line [18 :].strip ()
494
+ return
495
+ elif line .startswith ('Crashed Thread:' ):
496
+ self .crashlog .crashed_thread_idx = int (line [15 :].strip ().split ()[0 ])
497
+ return
498
+ elif line .startswith ('Triggered by Thread:' ): # iOS
499
+ self .crashlog .crashed_thread_idx = int (line [20 :].strip ().split ()[0 ])
500
+ return
501
+ elif line .startswith ('Report Version:' ):
502
+ self .crashlog .version = int (line [15 :].strip ())
503
+ return
504
+ elif line .startswith ('System Profile:' ):
505
+ self .parse_mode = CrashLogParseMode .SYSTEM
506
+ return
507
+ elif (line .startswith ('Interval Since Last Report:' ) or
508
+ line .startswith ('Crashes Since Last Report:' ) or
509
+ line .startswith ('Per-App Interval Since Last Report:' ) or
510
+ line .startswith ('Per-App Crashes Since Last Report:' ) or
511
+ line .startswith ('Sleep/Wake UUID:' ) or
512
+ line .startswith ('Anonymous UUID:' )):
513
+ # ignore these
514
+ return
515
+ elif line .startswith ('Thread' ):
516
+ thread_state_match = self .thread_state_regex .search (line )
517
+ if thread_state_match :
518
+ self .app_specific_backtrace = False
519
+ thread_state_match = self .thread_regex .search (line )
520
+ thread_idx = int (thread_state_match .group (1 ))
521
+ self .parse_mode = CrashLogParseMode .THREGS
522
+ self .thread = self .crashlog .threads [thread_idx ]
523
+ return
524
+ thread_insts_match = self .thread_instrs_regex .search (line )
525
+ if thread_insts_match :
526
+ self .parse_mode = CrashLogParseMode .INSTRS
527
+ return
528
+ thread_match = self .thread_regex .search (line )
529
+ if thread_match :
530
+ self .app_specific_backtrace = False
531
+ self .parse_mode = CrashLogParseMode .THREAD
532
+ thread_idx = int (thread_match .group (1 ))
533
+ self .thread = self .crashlog .Thread (thread_idx , False )
534
+ return
535
+ return
536
+ elif line .startswith ('Binary Images:' ):
537
+ self .parse_mode = CrashLogParseMode .IMAGES
538
+ return
539
+ elif line .startswith ('Application Specific Backtrace' ):
540
+ app_backtrace_match = self .app_backtrace_regex .search (line )
541
+ if app_backtrace_match :
542
+ self .parse_mode = CrashLogParseMode .THREAD
543
+ self .app_specific_backtrace = True
544
+ idx = int (app_backtrace_match .group (1 ))
545
+ self .thread = self .crashlog .Thread (idx , True )
546
+ elif line .startswith ('Last Exception Backtrace:' ): # iOS
547
+ self .parse_mode = CrashLogParseMode .THREAD
548
+ self .app_specific_backtrace = True
549
+ idx = 1
550
+ self .thread = self .crashlog .Thread (idx , True )
551
+ self .crashlog .info_lines .append (line .strip ())
552
+
553
+ def parse_thread (self , line ):
554
+ if line .startswith ('Thread' ):
555
+ return
556
+ if self .null_frame_regex .search (line ):
557
+ print ('warning: thread parser ignored null-frame: "%s"' % line )
558
+ return
559
+ frame_match = self .frame_regex .search (line )
560
+ if frame_match :
561
+ (frame_id , frame_img_name , _ , frame_img_version , _ ,
562
+ frame_addr , frame_ofs ) = frame_match .groups ()
563
+ ident = frame_img_name
564
+ self .thread .add_ident (ident )
565
+ if ident not in self .crashlog .idents :
566
+ self .crashlog .idents .append (ident )
567
+ self .thread .frames .append (self .crashlog .Frame (int (frame_id ), int (
568
+ frame_addr , 0 ), frame_ofs ))
569
+ else :
570
+ print ('error: frame regex failed for line: "%s"' % line )
571
+
572
+ def parse_images (self , line ):
573
+ image_match = self .image_regex_uuid .search (line )
574
+ if image_match :
575
+ (img_lo , img_hi , img_name , _ , img_version , _ ,
576
+ _ , img_uuid , img_path ) = image_match .groups ()
577
+ image = self .crashlog .DarwinImage (int (img_lo , 0 ), int (img_hi , 0 ),
578
+ img_name .strip (),
579
+ img_version .strip ()
580
+ if img_version else "" ,
581
+ uuid .UUID (img_uuid ), img_path ,
582
+ self .verbose )
583
+ self .crashlog .images .append (image )
584
+ else :
585
+ print ("error: image regex failed for: %s" % line )
586
+
587
+
588
+ def parse_thread_registers (self , line ):
589
+ stripped_line = line .strip ()
590
+ # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00"
591
+ reg_values = re .findall (
592
+ '([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *' , stripped_line )
593
+ for reg_value in reg_values :
594
+ (reg , value ) = reg_value .split (': ' )
595
+ self .thread .registers [reg .strip ()] = int (value , 0 )
596
+
597
+ def parse_system (self , line ):
598
+ self .crashlog .system_profile .append (line )
599
+
600
+ def parse_instructions (self , line ):
601
+ pass
602
+
587
603
588
604
def usage ():
589
605
print ("Usage: lldb-symbolicate.py [-n name] executable-image" )
0 commit comments