Annotate symbolizing bash script

 
#指定了该脚本应该由bash来处理。
#!/bin/bash
#准备两个临时文件。
#1. AWK_SCRIPT:在awk命令中被用作文本匹配的文件,并提供了对应的Action。
#   当匹配的文本被发现时,对应的Action会被执行。
#2. SH_SCRIPT:当前脚本会对传入的crash report文件用awk进行修改,结果就
#   存储在SH_SCRIPT中,将来会再次被include到当前的脚本中来执行。
#
#Note:$$是脚本所在进程的PID。
AWK_SCRIPT=/tmp/symbolizecrashlog_$$.awk
SH_SCRIPT=/tmp/symbolizecrashlog_$$.sh
 
#Note:$#是传入的脚本参数的个数。
if [[ $# < 2 ]]
then
 echo "Usage: $0 [ -arch <arch> ] symbol-file [ crash.log, … ]"
 exit 1
fi
 
ARCH_PARAMS=”
if [[ "${1}" == ‘-arch’ ]]
then
 ARCH_PARAMS="-arch ${2}"
#Note:从参数列表中删除2个参数。
 shift 2
fi
 
SYMBOL_FILE="${1}"
shift
 
#使用here document语法。<< _END为起始标记,_END为结束标记。被包含其中的
#多行文本将会被重定向到AWK_SCRIPT所指定的文件中。说白了就是生成awk匹配文件。
cat > "${AWK_SCRIPT}" << _END
/^[0-9]+ +[-._a-zA-Z0-9]+ *\t0x[0-9a-fA-F]+ / {
#Note:这里是awk的Action的定义,为匹配的行加入对于symbolize函数的调用。
 addr_index = index(\$0,\$3);
 end_index = addr_index+length(\$3);
 line_legnth = length;
 printf("echo ‘%s’\"\$(symbolize %s ‘%s’)\"\n",substr(\$0,1,end_index),
  \$3,substr(\$0,end_index+1,line_legnth-end_index));
 next;
 }
{ gsub(/’/,"’\\\\”"); printf("echo ‘%s’\n",\$0); }
_END
 
function symbolize()
{
 # Translate the address using atos
#2>/dev/null是将标准错误输出重定向到空设备。就是说关闭标准输出。
#有意思的是另外一种容易混淆的写法:
#">/dev/null 2>&1" also can write as "1>/dev/null 2>&1"
#stdout redirect to /dev/null (no stdout),
#and redirect stderr to stdout (stderr gone as well).
#End up it turns both stderr and stdout off.
 
 SYMBOL=$(atos -o "${SYMBOL_FILE}" ${ARCH_PARAMS} "${1}" 2>/dev/null)
 # If successful, output the translated symbol. If atos returns an address, output the original symbol
 
#判断SYMBOL变量是否为16进制的地址。
#个人觉得这个写法有问题。双引号中禁用了通配符,而且搜索了一下,没发现##的用法。
#可能的写法应该是$SYMBOL =~ "0x[0-9a-fA-F]*"。
 if [[ "${SYMBOL##0x[0-9a-fA-F]*}" ]]
 then
  echo -n "${SYMBOL}"
 else
  echo -n "${2}"
 fi
}
 
#此时$*,也就是参数列表由于经过几次shift只剩下了一个crash report文件。
awk -f "${AWK_SCRIPT}" $* > "${SH_SCRIPT}"
 
#引入SH_SCRIPT,symbolize函数会被调用到,从而调用ATOS来解析stack。
. "${SH_SCRIPT}"
rm -f "${AWK_SCRIPT}" "${SH_SCRIPT}"

Symbolication.Framework

在CocoaDev的论坛上看到,觉得不错,就赶紧给收藏了。Symbolication.Framework是个Private Framework,用微软的话来讲就是Undocumented Library。其功能”感觉“类似于Debugging Tools for Windows中的dbghelp.dll或者OS自带的imagehlp.dll。(但是由于用到的功能仅仅限于将地址转换为Symbol,所以说感觉像。)貌似Xcode解析StackTrace的时候用的就是这个库。改了下代码如下:

#import <Foundation/Foundation.h>

 

struct _VMURange {

    unsigned long long location;

    unsigned long long length;

};

 

@interface VMUAddressRange : NSObject {

    struct _VMURange _addressRange;

}

 

@end

 

@interface VMUSymbol : VMUAddressRange {

    NSString *_name;

    NSString *_mangledName;

    void *_owner;

    unsigned int _flags;

}

 

– (id)name;

 

@end

 

@interface VMUSymbolicator : NSObject {

    NSMutableArray *_symbolOwners;

    NSArray *_symbolOwnerAddressRanges;

    NSString *_path;

    void *_machTaskContainer;

    BOOL _isProtected;

}

 

+ (id)symbolicatorForPid:(int)fp8;

– (id)symbolForAddress:(unsigned long long)address;

 

@end

 

void printStackTrace(NSException *exception)

{

          VMUSymbolicator * symbolicator = [VMUSymbolicator symbolicatorForPid:getpid()];

          NSArray * addresses = [exception callStackReturnAddresses];

         

          for (NSNumber * address in addresses) {

                   VMUSymbol * symbol = [symbolicator symbolForAddress:[address unsignedLongLongValue]];

                   NSLog(@"%@", [symbol name]);

          }

}

 

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 

          @try {

                   [NSException raise:NSGenericException format:@"Test Exception"];

          }

          @catch (NSException *ex) {

                   printStackTrace(ex);

          }

         

    [pool drain];

    return 0;

}

Symbolication.Framework可以在/System/Library/PrivateFrameworks中找到。