Роман Ермолов - Отладка приложений под ios

Post on 15-Apr-2017

5.861 Views

Category:

Software

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Роман Ермолов

Отладка приложений под 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 Отладка без исходников

Спасибо за внимание!

Вопросы? (:

64

Роман Ермолов

iOS-разработчик

Контакты

@roman_ermolov

iforve@yandex.ru

top related