#!/usr/bin/perl -w # # This script parses a crashdump file and attempts to resolve addresses into function names. # # It finds symbol-rich binaries by: # a) searching in Spotlight to find .dSYM files by UUID, then finding the executable from there. # That finds the symbols for binaries that a developer has built with "DWARF with dSYM File". # b) searching in various SDK directories. # # Copyright (c) 2008-2015 Apple Inc. All Rights Reserved. # # use strict; use warnings; use Getopt::Long; use Cwd qw(realpath); use List::MoreUtils qw(uniq); use File::Basename qw(basename); use File::Glob ':glob'; use Env qw(DEVELOPER_DIR); use Config; no warnings "portable"; require bigint; if($Config{ivsize} < 8) { bigint->import(qw(hex)); } ############################# # Forward definitons sub usage(); ############################# # read and parse command line my $opt_help = 0; my $opt_verbose = 0; my $opt_output = "-"; my @opt_dsyms = (); my $opt_spotlight = 1; Getopt::Long::Configure ("bundling"); GetOptions ("help|h" => \$opt_help, "verbose|v" => \$opt_verbose, "output|o=s" => \$opt_output, "dsym|d=s" => \@opt_dsyms, "spotlight!" => \$opt_spotlight) or die("Error in command line arguments\n"); usage() if $opt_help; ############################# # have this thing to de-HTMLize Leopard-era plists my %entity2char = ( # Some normal chars that have special meaning in SGML context amp => '&', # ampersand 'gt' => '>', # greater than 'lt' => '<', # less than quot => '"', # double quote
# create mapping of framework => address => bt frame (adjust for sli # run atos with the addresses and binary files we just gathered my $arch = $arch_map{$symbol}; my $base = $base_map{$symbol}; my $lib = $image_map{$symbol}; my $cmd = "'$atos' -arch $arch -l $base -o '$escapedSymbol' @{[ keys % print STDERR "Running $cmd\n" if $opt_verbose; open my($ph),$cmd or die $!; my @symbolled_frames = map { chomp; $_ } <$ph>; close $ph or die $!; 別のプログラムを 呼び出している
run our fancy regex $process_section = replace_symbolized_frames($process_section,$bt # read the binary images my ($images,$first_bundle) = parse_images($process_section, $report_v if ( $opt_verbose ) { symbolはどこから? } @extra_search_paths = (@extra_search_paths, getSymbolDirPaths($model, $ fetch_symbolled_binaries($images,$build,$first_bundle,@extra_search_pat # If we didn't get *any* symbolled binaries, just print out the origina my $imageCount = keys(%$images);
didn't get *any* symbolled binaries, just print out the origina my $imageCount = keys(%$images); symbolへの道 $symbol = $$lib{symbol}; if ($symbol) { print STDERR "-- [$$lib{uuid}] found in cache\n" if $op } else { ($symbol, $arch) = getSymbolPathAndArchFor($$lib{path}, @{$uuid_cache{$$lib{uuid}}} = ($symbol, $arch); if ( $symbol ) { $$lib{symbol} = $symbol;
didn't get *any* symbolled binaries, just print out the origina my $imageCount = keys(%$images); $symbol = $$lib{symbol}; if ($symbol) { print STDERR "-- [$$lib{uuid}] found in cache\n" if $op } else { ($symbol, $arch) = getSymbolPathAndArchFor($$lib{path}, @{$uuid_cache{$$lib{uuid}}} = ($symbol, $arch); if ( $symbol ) { $$lib{symbol} = $symbol; sub getSymbolPathAndArchFor { my ($path,$build,$uuid,@extra_search_paths) = @_; # derive a few more parameters... my $bin = ($path =~ /^.*?([^\/]+)$/)[0]; # basename # Look in any of the manually-passed dSYMs if( @opt_dsyms ) { print STDERR "-- [$uuid] CHECK (manual)\n" if $opt_verbose; my ($out_path, $arch) = getSymbolPathAndArchFor_manualDSYM($uuid if(defined($out_path) && length($out_path) && defined($arch) && 4つの処理を順に呼び出して、uuidに 一致するシンボル情報ファイルを探している
size for a loaded image. /// /// - Parameter i: The index of the loaded image as reported by Dyld. /// - Returns: The image name, address, and size. internal func getAddressInfoForImage(atIndex i: UInt32) -> (name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) { debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } let header = unsafeBitCast(_dyld_get_image_header(i), to: UnsafePointer<MachHeader>.self) let name = String(validatingUTF8: _dyld_get_image_name(i)!)! var size: UInt = 0 let address = getsegmentdata(header, "__TEXT", &size) return (name, address, size) } __TEXTセグメント
magic: UInt32 /* mach magic number identifier */ public var cputype: cpu_type_t /* cpu specifier */ public var cpusubtype: cpu_subtype_t /* machine specifier */ public var filetype: UInt32 /* type of file */ public var ncmds: UInt32 /* number of load commands */ public var sizeofcmds: UInt32 /* the size of all the load commands */ public var flags: UInt32 /* flags */ public var reserved: UInt32 /* reserved */ public init() public init(magic: UInt32, cputype: cpu_type_t, cpusubtype: cpu_subtype_t, filetype: UInt32, ncmds: UInt32, sizeofcmds: UInt32, flags: UInt32, reserved: UInt32) }
mach_header_64 { public var magic: UInt32 /* mach magic number identifier */ public var cputype: cpu_type_t /* cpu specifier */ public var cpusubtype: cpu_subtype_t /* machine specifier */ public var filetype: UInt32 /* type of file */ public var ncmds: UInt32 /* number of load commands */ public var sizeofcmds: UInt32 /* the size of all the load commands */ public var flags: UInt32 /* flags */ public var reserved: UInt32 /* reserved */ public init() public init(magic: UInt32, cputype: cpu_type_t, cpusubtype: cpu_subtype_t, filetype: UInt32, ncmds: UInt32, sizeofcmds: UInt32, flags: UInt32, reserved: UInt32) } _dyld_get_image_header N = header.ncmds
cmd: UInt32 /* type of load command */ public var cmdsize: UInt32 /* total size of command in bytes */ public init() public init(cmd: UInt32, cmdsize: UInt32) } cmdに 応じたデータ cmdsize
UInt32 /* type of load command */ public var cmdsize: UInt32 /* total size of command in bytes */ public init() public init(cmd: UInt32, cmdsize: UInt32) } cmdsize UUIDの場合は… cmd = LC_UUID データとしてUUIDが16バイト LC_UUID 59 61 6b 88 aa 1b 37 07 a5 0b e4 a5 d0 98 c2 ae