Xcode中使用LLDB除錯
在Xcode中除錯程式
對於我們日常的開發工作來說,更多的時候是在Xcode中進行除錯工作。因此上面所描述的流程,其實Xcode已經幫我們完成了大部分的工作,而且很多東西也可以在Xcode裡面看到。因此,我們可以把精力都集中在程式碼層面上。
在蘋果的官方文件中列出了我們在除錯中能用到的一些命令,我們在這重點講一些常用的命令。
列印
列印變數的值可以使用print
命令,該命令如果列印的是簡單型別,則會列出簡單型別的型別和值。如果是物件,還會打印出物件指標地址,如下所示:
(lldb) print a
(NSInteger) $0 = 0
(lldb) print b
(NSInteger) $1 = 0
(lldb) print str
(NSString *) $2 = 0x0000000100001048 @"abc"
(lldb) print url
(NSURL *) $3 = 0x0000000100206cc0 @"abc"
複製程式碼
在輸出結果中我們還能看到類似於$0
,$1
這樣的符號,我們可以將其看作是指向物件的一個引用,我們在控制面板中可以直接使用這個符號來操作對應的物件,這些東西存在於LLDB的全名空間中,目的是為了輔助除錯。如下所示:
(lldb) exp $0 = 100
(NSInteger) $9 = 100
(lldb) p a
(NSInteger) $10 = 100
複製程式碼
另外$
後面的數值是遞增的,每列印一個與物件相關的命令,這個值都會加1。 上面的print
po
(print object
的縮寫)命令,如下所示:
(lldb) po str
abc
複製程式碼
當然,po
命令是"exp -O --"
命令的別名,使用"exp -O --"
能達到同樣的效果。 對於簡單型別,我們還可以為其指定不同的列印格式,其命令格式是print/
,如下所示:
(lldb) p/x a
(NSInteger) $13 = 0x0000000000000064
複製程式碼
格式的完整清單可以參考Output Formats。
expression
在開發中,我們經常會遇到這樣一種情況:我們設定一個檢視的背景顏色,執行後發現顏色不好看。嗯,好吧,在程式碼裡面修改一下,再編譯執行一下,嗯,還是不好看,然後再修改吧~~這樣無形中浪費了我們大把的時間。在這種情況下,expression
(lldb) exp a = 10
(NSInteger) $0 = 10
(lldb) exp b = 100
(NSInteger) $1 = 100
2015-01-25 14:00:41.313 test[18064:71466] a + b = 110, abc
複製程式碼
expression
命令的功能不僅於此,正如上面的po命令,其實際也是"expression -O --"
命令的別名。更詳細使用可以參考Evaluating Expressions。
image
image
命令的用法也挺多,首先可以用它來檢視工程中使用的庫,如下所示:
(lldb) image list
[ 0] 432A6EBF-B9D2-3850-BCB2-821B9E62B1E0 0x0000000100000000 /Users/**/Library/Developer/Xcode/DerivedData/test-byjqwkhxixddxudlnvqhrfughkra/Build/Products/Debug/test
[ 1] 65DCCB06-339C-3E25-9702-600A28291D0E 0x00007fff5fc00000 /usr/lib/dyld
[ 2] E3746EDD-DFB1-3ECB-88ED-A91AC0EF3AAA 0x00007fff8d324000 /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
[ 3] 759E155D-BC42-3D4E-869B-6F57D477177C 0x00007fff8869f000 /usr/lib/libobjc.A.dylib
[ 4] 5C161F1A-93BA-3221-A31D-F86222005B1B 0x00007fff8c75c000 /usr/lib/libSystem.B.dylib
[ 5] CBD1591C-405E-376E-87E9-B264610EBF49 0x00007fff8df0d000 /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
[ 6] A260789B-D4D8-316A-9490-254767B8A5F1 0x00007fff8de36000 /usr/lib/libauto.dylib
複製程式碼
我們還可以用它來查詢可執行檔案或共享庫的原始地址,這一點還是很有用的,當我們的程式崩潰時,我們可以使用這條命令來查詢崩潰所在的具體位置,如下所示:
NSArray *array = @[@1, @2];
NSLog(@"item 3: %@", array[2]);
複製程式碼
這段程式碼在執行後會丟擲如下異常:
2015-01-25 14:12:01.007 test[18122:76474] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff8e06f66c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff886ad76e objc_exception_throw + 43
2 CoreFoundation 0x00007fff8df487de -[__NSArrayI objectAtIndex:] + 190
3 test 0x0000000100000de0 main + 384
4 libdyld.dylib 0x00007fff8f1b65c9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
複製程式碼
根據以上資訊,我們可以判斷崩潰位置是在main.m
檔案中,要想知道具體在哪一行,可以使用以下命令:
(lldb) image lookup --address 0x0000000100000de0
Address: test[0x0000000100000de0] (test.__TEXT.__text + 384)
Summary: test`main + 384 at main.m:23
複製程式碼
可以看到,最後定位到了main.m
檔案的第23
行,正是我們程式碼所在的位置。 我們還可以使用image lookup
命令來檢視具體的型別,如下所示:
(lldb) image lookup --type NSURL
Best match found in /Users/**/Library/Developer/Xcode/DerivedData/test-byjqwkhxixddxudlnvqhrfughkra/Build/Products/Debug/test:
id = {0x100000157}, name = "NSURL", byte-size = 40, decl = NSURL.h:17, clang_type = "@interface NSURL : NSObject{
NSString * _urlString;
NSURL * _baseURL;
void * _clients;
void * _reserved;
}
@property ( readonly,getter = absoluteString,setter = <null selector>,nonatomic ) NSString * absoluteString;
@property ( readonly,getter = relativeString,setter = <null selector>,nonatomic ) NSString * relativeString;
@property ( readonly,getter = baseURL,setter = <null selector>,nonatomic ) NSURL * baseURL;
@property ( readonly,getter = absoluteURL,setter = <null selector>,nonatomic ) NSURL * absoluteURL;
@property ( readonly,getter = scheme,setter = <null selector>,nonatomic ) NSString * scheme;
@property ( readonly,getter = resourceSpecifier,setter = <null selector>,nonatomic ) NSString * resourceSpecifier;
@property ( readonly,getter = host,setter = <null selector>,nonatomic ) NSString * host;
@property ( readonly,getter = port,setter = <null selector>,nonatomic ) NSNumber * port;
@property ( readonly,getter = user,setter = <null selector>,nonatomic ) NSString * user;
@property ( readonly,getter = password,setter = <null selector>,nonatomic ) NSString * password;
@property ( readonly,getter = path,setter = <null selector>,nonatomic ) NSString * path;
@property ( readonly,getter = fragment,setter = <null selector>,nonatomic ) NSString * fragment;
@property ( readonly,getter = parameterString,setter = <null selector>,nonatomic ) NSString * parameterString;
@property ( readonly,getter = query,setter = <null selector>,nonatomic ) NSString * query;
@property ( readonly,getter = relativePath,setter = <null selector>,nonatomic ) NSString * relativePath;
@property ( readonly,getter = fileSystemRepresentation,setter = <null selector> ) const char * fileSystemRepresentation;
@property ( readonly,getter = isFileURL,setter = <null selector>,readwrite ) BOOL fileURL;
@property ( readonly,getter = standardizedURL,setter = <null selector>,nonatomic ) NSURL * standardizedURL;
@property ( readonly,getter = filePathURL,setter = <null selector>,nonatomic ) NSURL * filePathURL;
@end"
複製程式碼
可以看到,輸出結果中列出了NSURL
的一些成員變數及屬性資訊。 image
命令還有許多其它功能,具體可以參考Executable and Shared Library Query Commands。
參考
轉載自: 南峰子的技術部落格 (LLDB偵錯程式使用簡介)