Upload
alexander-zimin
View
5.861
Download
4
Embed Size (px)
Citation preview
Роман Ермолов
Отладка приложений под iOS
План1 Интересные возможности LLDB2 Отладка иерархии UIView3 Отладка без исходников
Интересные возможности
LLDB1 breakpoint 1.1 condition 1.2 command
Интересные возможности
LLDB1 breakpoint 1.1 condition 1.2 command
breakpoint
- (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; self.contentManagerVC.view.frame = self.layout.contentFrame; // ... self.voiceSearchController.view.frame = self.layout.voiceSearchFrame; }
6
breakpoint
7
breakpoint
8
Интересные возможности
LLDB1 breakpoint 1.1 condition 1.2 command
condition
10
@implementation YBSplitViewController - (void)loadView { self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds]; // ... } - (void)viewDidLoad { [super viewDidLoad]; // ... } @end
condition
11
@implementation YBSplitViewController - (void)loadView { self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds]; // ... } - (void)viewDidLoad { [super viewDidLoad]; // ... } - (void)didMoveToParentViewController:(UIViewController*)parent { [super didMoveToParentViewController:parent]; } @end
condition// Устанавливаем символьный брейкпоинт -[YBSplitViewController didMoveToParentViewController:]
12
// Устанавливаем символьный брейкпоинт -[UIViewController didMoveToParentViewController:] // Добавляем условие (Class)[$arg1 class] == [YBSplitViewController class]
(lldb) breakpoint set -F "-[YBSplitViewController didMoveToParentViewController:]" Breakpoint 1: no locations (pending). WARNING: Unable to resolve breakpoint to any actual locations.
condition
(lldb) po $arg1 <YBSplitViewController: 0xSome_Address>
13
Интересные возможности
LLDB1 breakpoint 1.1 condition 1.2 command
print/po
print/po- (void)configureForScreenType:(YBScreenType)screenType { self.collapsedHeight = [[self class] collapsedHeightForScreenType:screenType]; //... }
16
- (void)configureForScreenType:(YBScreenType)screenType { self.collapsedHeight = [[self class] collapsedHeightForScreenType:screenType]; NSLog(@"%f", self.collapsedHeight); //... }
17
print/po
- (void)configureForScreenType:(YBScreenType)screenType { self.collapsedHeight = [[self class] collapsedHeightForScreenType:screenType]; //... }
18
// Добавляем команду print self.collapsedHeight
(CGFloat) $0 = 15
print/po
print/po
19
// Добавляем команду po self.childViewController
// Добавляем команду expression (void)NSLog(@"Content insets %@", (NSString *)NSStringFromUIEdgeInsets(self.contentInsetsInCarousel))
<ViewController 0xSome_Address lines: 5, text: some_title>
2015-08-16 12:30:25.604 Debugging-Objc[7319:398126] Content insets {10, 20, 30, 40}
thread return
thread return- (void)showAlertViewIfNeeded { if (![self shouldShowAlertView]) { return; } [self showAlertView]; } - (BOOL)shouldShowAlertView { return ([self application].applicationState == UIApplicationStateActive && [self isSyncInitializing]); }
21
thread return- (void)showAlertViewIfNeeded { // if (![self shouldShowAlertView]) { // return; // } [self showAlertView]; } - (BOOL)shouldShowAlertView { return YES; // return ([self application].applicationState == UIApplicationStateActive // && [self isSyncInitializing]); }
22
thread return- (BOOL)shouldShowAlertView { return ([self application].applicationState == UIApplicationStateActive && [self isSyncInitializing]); } // Добавляем команду thread return YES
23
thread return 123.45 thread return [NSArray array] thread return @"string"
Интересные возможности
LLDB1 breakpoint 1.1 condition 1.2 command
watchpoint@implementation YBFieldValidator - (void)validateField:(NSString *)field { if ([self fieldIsEmpty:field]) { _state = YBJSONRequestStateFailed; } else { _state = YBJSONRequestStateSuccess; } } - (void)setInvalidStateWithErrors:(NSArray *)errors { _state = YBJSONRequestStateFailed; } @end
25
watchpoint
26
@implementation YBFieldValidator - (void)validateField:(NSString *)field { if ([self fieldIsEmpty:field]) { _state = YBJSONRequestStateFailed; } else { _state = YBJSONRequestStateSuccess; } } - (void)setInvalidStateWithErrors:(NSArray *)errors { _state = YBJSONRequestStateFailed; } @end
watchpoint(lldb) watchpoint set variable —-watch read_write _state Watchpoint created: Watchpoint 1: addr = 0xSome_Address size = 8 state = enabled type = rw watchpoint spec = '_state' new value: 0
27
Watchpoint 1 hit: old value: 0 new value: 3
Отладка иерархии UIView
Отладка иерархии UIView
29
iOS 7-(lldb) po [[[[UIApplication sharedApplication] delegate] window] recursiveDescription] <UIWindow: 0xSome_Address; frame = (0 0; 375 667); ...> | <UIView: 0xSome_Address; frame = (0 0; 375 667); ...> | | <ViewWithCustomNextResponder: 0xSome_Address; ...>
iOS 8+
Отладка иерархии UIView
30
Отладка иерархии UIView
31
Отладка иерархии UIView
Reveal Spark Inspector
32
Отладка иерархии UIView
(lldb) expression (void)[0x7fd7aaec45b0 setTintColor:[UIColor redColor]]
33
(lldb) expression (void)[CATransaction flush]
Отладка без исходников
Отладка без исходников
35
Отладка без исходников
36
Sample app Safari
Процесс отладки1 Определение точки входа
2 Остановка программы
3 Оценка текущего состояния
4 Анализ поведения
37
Работа с методами
Работа с методами
// objc.h typedef id (*IMP)(id self, SEL _cmd, ...);
39
@interface CustomClass : NSObject - (void)methodFoo:(id)foo bar:(id)bar baz:(id)baz; - (void)setQux:(CGFloat)qux; - (void)setCorge:(CGRect)corge; @end
// NSObject.h - (IMP)methodForSelector:(SEL)aSelector; + (IMP)instanceMethodForSelector:(SEL)aSelector;
Работа с методами
40
// 1. Получаем адрес функции (lldb) expression IMP $address = (IMP)[[CustomClass class] instanceMethodForSelector:@selector(methodFoo:bar:baz:)]
// 2. Ставим breakpoint на адрес (lldb) breakpoint set —-address $address Breakpoint 1: where = SomeApplication`___lldb_unnamed_function653$$, address = 0xSome_Address
Работа с методами. АргументыСпособы передачи аргументов в функцию:
через регистры процессора
через стек
смешанный (часть передается через регистры, часть через стек или другую память)
41
Архитектуры:
armv7* / arm64 / x86_64
Работа с методами. Аргументы
42
armv7 arm64 x86_64 алиас
self r0 x0 rdi $arg1
_cmd r1 x1 rsi $arg2
arg1 r2 x2 rdx $arg3
arg2 r3 x3 rcx $arg4
arg3 $(sp) x4 r8 $arg5
Работа с методами. Аргументы
43
// Устанавливаем breakpoint - (void)methodFoo:(id)foo bar:(id)bar baz:(id)baz;(lldb) po $arg1 <CustomClass: 0xSome_Address>
(lldb) print (SEL)$arg2 (SEL) $0 = "methodFoo:bar:baz:"(lldb) po $arg3 <FooClass: 0xSome_Address>
(lldb) po $arg4 <BarClass: 0xSome_Address>
(lldb) po $arg5 <BazClass: 0xSome_Address>
Работа с методами. Аргументы (x86_64)
44
// Устанавливаем breakpoint - (void)setQux:(CGFloat)qux;
(lldb) po $arg1 <CustomClass: 0xSome_Address>(lldb) print (SEL)$arg2 (SEL) $0 = "setQux:"(lldb) print $arg3 (unsigned long) $1 = 4677571844(lldb) expression (void)NSLog(@"%f", $xmm0) 2015-08-16 12:33:50.316 Debugging-Objc[4470:281979] 0.900000
[customClassObject setQux:0.9];
Работа с методами. Аргументы (x86_64)
45
// Устанавливаем breakpoint - (void)setCorge:(CGRect)corge;
(lldb) po $arg1 <CustomClass: 0xSome_Address>(lldb) print (SEL)$arg2 (SEL) $0 = "setCorge:"(lldb) print $arg3 (unsigned long) $1 = 4677571844
[customClassObject setCorge:CGRectMake(10.5, 15.5, 30, 40)];
Работа с методами. Аргументы (x86_64)
46
struct CGRect { CGPoint origin; CGSize size; };
(lldb) memory read $rsp+8 --format float64 --count 4 --size 8
struct CGPoint { CGFloat x; CGFloat y; };
struct CGSize { CGFloat width; CGFloat height; };
0xSome_Address : {10.5} // origin.x 0xSome_Address+8 : {15.5} // origin.y 0xSome_Address+16: {30} // size.width 0xSome_Address+24: {40} // size.height
Работа с объектами
Работа с объектами/// A pointer to an instance of a class. typedef struct objc_object *id;
/// Represents an instance of a class. struct objc_object { Class isa OBJC_ISA_AVAILABILITY; };
48
Работа с объектами
49
@interface CustomClass : NSObject { @private NSInteger _counter; } @end
struct CustomClass_object { Class isa; NSInteger _counter; };
Работа с объектами. Значение ivar
(lldb) po [0xSome_Address valueForKey:@"_counter"] 123
50
// 1. Получаем описание переменной (lldb) expression struct objc_ivar* $variable = (struct objc_ivar*) class_getInstanceVariable([CustomClass class], "_counter")// 2. Получаем смещение (lldb) expression ptrdiff_t $offset = (ptrdiff_t)ivar_getOffset($variable)// 3. Получаем значение переменной (lldb) memory read 0xSome_Address+$offset --format int64 --count 1 --size 8 0xSome_Address+$offset: {123}
Работа с объектами. Watchpoint
51
// 1. Получаем описание переменной (lldb) expression struct objc_ivar* $variable = (struct objc_ivar*) class_getInstanceVariable([CustomClass class], "_counter")// 2. Получаем смещение (lldb) expression ptrdiff_t $offset = (ptrdiff_t)ivar_getOffset($variable)// 3. Ставим watchpoint на адрес (lldb) watchpoint set expression —-watch read_write —-size 8 -- $arg1+$offset Watchpoint created: Watchpoint 0: addr = 0xSome_Address size = 8 type = rw new value: 0
ChiselУстановка брейкпоинтов на метод класса/объекта
Установка watchpoint’ов
Иерархия UIViewController
Открытие UIImage, UIView, UIColor в Preview
многое другое!
52
Hopper
Hopper
Дизассемблер
Декомпилятор
Отладчик
54
Hopper
55
Hopper
56
Hopper
57
Hopper
58
Процесс отладки
59
1 Определение точки входа
2 Остановка программы
3 Оценка текущего состояния
4 Анализ поведения
Итоги1 Интересные возможности LLDB2 Отладка иерархии UIView3 Отладка без исходников
МатериалыLLDB Command Map
Mac OS X Debugging Magic
iOS Debugging Magic
iOS ABI Function Call Guide
Hopper
Chisel
61
Спасибо за внимание!
Вопросы? (: