2013-06-04 4 views
7

Il problema:Come utilizzare il contenuto dello stack in una condizione di punto di interruzione LLDB?

Ho una situazione in cui abbiamo una riproduzione multimediale durante il lancio, e objc_exception_throw() colpisce circa 5 volte durante quel periodo, ma viene sempre preso, ed è modo sud di l'oggetto del lettore multimediale.

Sono stanco di entrambi (a) dover continuare manualmente n volte, o (b) di dover lasciare i punti di interruzione disabilitati fino a dopo il completamento della riproduzione.

Quello che ho provato:

  • rendendo il punto di interruzione ignorare i primi cinque colpi (problema: non è sempre esattamente cinque volte)
  • creare il mio punto di rottura simbolica con il mio obiettivo come il modulo (problema: nulla è cambiato)

Quello che mi piacerebbe fare:

Una soluzione che viene in mente è quella di valutare lo stack quando il punto di interruzione colpisce e continuare se in esso sono elencati un particolare metodo o funzione. Ma non ho idea di come farlo.

Altre idee benvenute.

risposta

12

Lo fai usando Python.

Quanto segue definisce un elenco di ignorazioni e una funzione che è possibile allegare come comando a un punto di interruzione.

La funzione acquisisce i nomi delle funzioni nel backtrace e set-interseca quei nomi con l'elenco ignorato. Se alcuni nomi corrispondono, continua a eseguire il processo. Questo salta in modo efficace nel debugger per gli stack indesiderati.

(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 

ho provato contro il seguente file, e salta con successo il primo tiro dentro recurse_then_throw_and_catch e gocce nel debugger durante il lancio all'interno 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(); 
} 

immagino si potrebbe aggiungere questa funzione al vostro .lldbinit e poi collegarlo al breakpoint come necessario dalla console. (Non credo che è possibile impostare un comando di script all'interno di Xcode.)

+0

Accidenti, amico. La migliore risposta che avrei potuto sperare. – MikeyWard

+0

Bella risposta. L'unica avvertenza è che questo '' continua' 'se uno qualsiasi di 'ignored_functions' appare in qualsiasi punto dello stack, invece di controllare semplicemente il frame" sopra "' objc_exception_throw'. –

+0

@JasonMolenda Completamente corretto."Ovunque nello stack" era quello che pensavo fosse voluto in base a "valutare lo stack quando il punto di interruzione colpisce e continuare se in esso è elencato un particolare metodo o funzione". Sarebbe semplice adattarsi a fare 'if frame.GetThread(). GetFrameAtIndex (1) .GetFunctionName() in ignored_functions:' invece. L'intuizione chiave è di usare una funzione Python come comando breakpoint. –

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

Se un comando python breakpoint restituisce False, lldb andrà avanti. Quindi questo sta dicendo: se il frame any nella pila ha la stringa 'xyz' nel suo nome, quindi restituire True (per interrompere). Altrimenti se nessun frame ha quel nome, questa espressione any restituirà False (per continuare).