2013-06-04 13 views
7

Problem:Jak używać zawartości stosu w warunku punktu przerwania LLDB?

Mam sytuację, w której mamy odtwarzanie multimediów podczas startu i objc_exception_throw() trafia około 5 razy w ciągu tego okresu, ale zawsze złapać, i to sposób południe od obiekt odtwarzacza multimediów.

Mam dość albo (a) konieczności ręcznego kontynuowania n razy, albo (b) konieczności pozostawienia punktów przerwania wyłączonych do czasu zakończenia odtwarzania.

Co próbowałem:

  • dokonywania przerwania zignorować pierwsze pięć trafień (problem: to nie zawsze dokładnie pięć razy)
  • tworząc własne symboliczne przerwania używając mojego docelowy jako moduł (problem: nic się nie zmieniło)

Co chciałbym zrobić:

Jednym z rozwiązań, które przychodzi na myśl, jest ocena stosu, kiedy punkt krytyczny zostanie trafiony, i kontynuacja, jeśli konkretna metoda lub funkcja jest tam wymieniona. Ale nie mam pojęcia, jak to zrobić.

Inne pomysły również mile widziane.

Odpowiedz

12

Robisz to za pomocą Pythona.

Poniżej zdefiniowano listę ignorowanych i funkcję, którą można dołączyć jako polecenie do punktu przerwania.

Funkcja przejmuje nazwy funkcji w śladzie i ustawia - przecina te nazwy z listą ignorowanych. Jeśli jakaś nazwa pasuje, kontynuuje proces. To skutecznie pomija wpadanie do debuggera w poszukiwaniu niechcianych stosów.

(lldb) b objc_exception_throw 
Breakpoint 1: where = libobjc.A.dylib`objc_exception_throw, address = 0x00000000000113c5 
(lldb) script 
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. 
>>> ignored_functions = ['recurse_then_throw_and_catch'] 
def continue_ignored(frame, bp_loc, dict): 
    global ignored_functions 
    names = set([frame.GetFunctionName() for frame in frame.GetThread()]) 
    all_ignored = set(ignored_functions) 
    ignored_here = all_ignored.intersection(names) 
    if len(ignored_here) > 0: 
     frame.GetThread().GetProcess().Continue() 

quit() 

(lldb) br comm add -F continue_ignored 1 
(lldb) r 

Próbowałem ją przed następującym pliku, i to skutecznie pomija pierwszy rzut wewnątrz recurse_then_throw_and_catch i spada do debuggera podczas rzutu wewnątrz throw_for_real.

#import <Foundation/Foundation.h> 

void 
f(int n) 
{ 
    if (n <= 0) @throw [NSException exceptionWithName:@"plugh" reason:@"foo" userInfo:nil]; 

    f(n - 1); 
} 

void 
recurse_then_throw_and_catch(void) 
{ 
    @try { 
     f(5); 
    } @catch (NSException *e) { 
     NSLog(@"Don't care: %@", e); 
    } 
} 

void 
throw_for_real(void) 
{ 
    f(2); 
} 

int 
main(void) 
{ 
    recurse_then_throw_and_catch(); 
    throw_for_real(); 
} 

sobie wyobrazić, można dodać tę funkcję do .lldbinit a następnie podłączyć go do pułapki, ile potrzeba z konsoli. (Nie sądzę, można ustawić polecenie skryptu od wewnątrz Xcode.)

+0

Cholera, koleś. Najlepsza odpowiedź, na jaką mogłem liczyć. – MikeyWard

+0

Dobra odpowiedź. Jedynym zastrzeżeniem jest to, że będzie to "kontynuacja", jeśli dowolne z 'ignored_functions' pojawi się gdziekolwiek na stosie, zamiast jedynie sprawdzać ramkę" powyżej "' objc_exception_throw'. –

+0

@JasonMolenda Całkowicie poprawne."Gdziekolwiek na stosie" było to, co według mnie było poszukiwane na podstawie "oceny stosu, gdy punkt krytyczny trafi, i kontynuacji, jeśli konkretna metoda lub funkcja jest tam wymieniona". Byłoby łatwo dostosować się do 'if frame.GetThread(). GetFrameAtIndex (1) .GetFunctionName() w ignored_functions:' zamiast tego. Kluczowym wglądem jest użycie funkcji Pythona jako polecenia punktu przerwania. –

1
break command add -s python -o "return any('xyz' in f.name for f in frame.thread)" 

Jeśli pytona punktu przerwania zwrotów dowodzenia False, lldb będzie dalej. A więc jest tak: jeśli ramka any w stosie ma ciągi 'xyz' w swojej nazwie, to zwróć True (aby zatrzymać). W przeciwnym razie, jeśli żadna ramka nie ma tej nazwy, wyrażenie any zwróci False (aby kontynuować).

Powiązane problemy