2010-10-30 11 views
10

Próbuję stworzyć mały test jednostkowy z gdb, dla wbudowanego MCU, który jest kontrolowany przez OpenOCD (który daje mi kontrolę nad moim celem za pośrednictwem serwera GDB).Jak skryptować gdb (z pythonem)? Przykład: dodaj punkty przerwania, uruchom, jaki punkt przełomowy trafiliśmy?

Chciałbym zautomatyzować to za pomocą skryptów gdb.

Chciałbym napisać jakiś skrypt do gdb, które bardziej lub mniej robi to:

  1. dodać kilka przerwań
  2. Uruchom program
  3. Kiedy zatrzymać, gdzie się zatrzyma (pobierz informacje o ramce)
  4. Zamknij.

Jakieś pomysły?

Przykład, jak to zrobić w skryptach Pythona gdb byłoby miłe.

Dzięki Johan


Uwaga:

Załóżmy, że mamy tę podstawową strukturę, że bardziej lub mniej idzie do test_failed() lub test_success() w zależności od tego, co funkcja start_test() zwraca.

void test_failed() {  
    while(1);  
} 

void test_success() {  
    while(1);  
} 

int main(void) {  
    int status = start_test();  

    if(status > 0) {  
     test_failed();  
    }  
    test_success(); 

    while(1);  
} 

Aby to zrobić ręcznie w gdb jest bardzo ciasna przodu,

(gdb) break test_success 
Breakpoint 1 at 0x20: file src/main.c, line 9. 
(gdb) break test_failed 
Breakpoint 2 at 0x18: file src/main.c, line 5. 
(gdb) cont 
Continuing. 

Breakpoint 1, test_success() at src/main.c:9 
9  while(1); 
(gdb) frame 
#0 test_success() at src/main.c:9 
9  while(1); 
(gdb) 

Więc następnym krokiem Próbowałem było dodanie poleceń tych gdb do skryptu startowego gdb, że mniej więcej tak wyglądało to .

break test_success 
break test_failed 
target remote localhost:3333 
cont 
frame 

i uruchomić go z

arm-none-eabi-gdb --batch --command=commands.gdb main.elf 

a tego rodzaju prac, ale nie jest to bardzo miłe. Jak to zrobić za pomocą "nowych i fajnych" skryptów python, , które wydają się wspierać gdb.

+1

Sprawdź również poradnik na wiki: https://sourceware.org/gdb/wiki/PythonGdbTutorial –

Odpowiedz

8

Najnowsze wersje GDB FYI są skryptowalne w Pythonie. Możesz wywołać kod Pythona z wiersza poleceń gdb. To otwiera zupełnie nowy świat, sprawdź odpowiednią dokumentację. Z przebiegu linii komend:

info gdb extending python 

Jeśli nie podoba ci się informacje o przeglądarce tekstowej, tutaj jest jeden (wśród wielu?) Alternatywa, Przeglądarka graficzna:

yelp 'info:gdb?Extending GDB' 

Oto gdb próbka Skrypt-Python. Załącza gdb do pierwszego uruchomionego programu "your_program".

#!/usr/bin/python 

import subprocess 
import string 

def backquotes(cmdwords): 
     output = subprocess.Popen(cmdwords, stdout=subprocess.PIPE).communicate()[0] 
     return output.strip() 

pid = backquotes(['pgrep', 'your_program']) 

gdb.execute("attach " + str(pid)) 
+0

Nie stało masz fajne linki? lub howto lub coś, co może popchnąć mnie we właściwym kierunku (ponieważ stary styl skryptowania gdb nie jest zbyt optymalny ...) – Johan

2

OK, znalazłem odpowiedź, zadając pytanie ... i to było naprawdę proste.

Nie należy używać jednocześnie "--command" i "--eval", jeśli oczekuje się, że zostaną wykonane w określonej kolejności!

Bardziej przewidywalnym sposobem jest umieszczenie wszystkiego w pliku commands.gdb i zignorowanie opcji --eval.

Tak więc staje się coś takiego:

arm-none-eabi-gdb --batch --command=commands.gdb main.elf 

Gdzie polecenia.gdb wygląda tak:

break test_success 
break test_failed 
target remote localhost:3333 
cont 
frame 

Ale byłoby o wiele przyjemniej zrobić to z czymś takim jak pyton.

5

przykładem zmniejszona że obecnie używam:

class DebugPrintingBreakpoint(gdb.Breakpoint): 
    debugging_IDs = frozenset({37, 153, 420}) 
    def stop(self): 
     top = gdb.newest_frame() 
     someVector = top.read_var('aVectorVar') 
     # Access the begin() & end() pointer of std::vector in GNU Standard C++ lib 
     first = someVector['_M_impl']['_M_start'] 
     last = someVector['_M_impl']['_M_finish'] 
     values = [] 
     while first != last: 
      values.append(int(first.dereference()['intID'])) 
      first = first + 1 
     if not set(values) & debugging_IDs: 
      return False # skip: none of the items we're looking for can be found by ID in the vector on the stack 
     print("Found other accompanying IDs: {}".format(values)) 
     return True # drop to gdb's prompt 
# Ensure shared libraries are loaded already 
gdb.execute("start") 
# Set our breakpoint, which happens to reside in some shared lib, hence the "start" previously 
DebugPrintingBreakpoint("source.cpp:42") 
gdb.execute("continue") 

można wykonać ten skrypt z wiersza GDB jest tak:

(gdb) source script.py 

Albo z wiersza poleceń:

$ gdb --command script.py ./executable.elf 

Zobacz co mplete GDB Python API docs w celu uzyskania dalszych informacji.

+0

Nie mam 'gdb.continue' na 7.7.1, jaka to wersja? –

+1

'gdb.execute (" kontynuuj ")' działa :-) –

1

Po prostu chciałem zauważyć coś, co jest mylące, gdy wrócę do tego tematu (Uwaga, obecnie jestem na Ubuntu 14.04, GNU gdb (Ubuntu 7.7.1-0ubuntu5 ~ 14.04.3) 7.7.1):

Po pierwsze, istnieją wzmianki o to czy jest "możliwe, aby wywołać gdb jako tłumacza":

... sens, należałoby napisać skrypt plik tekstowy z linią shebang #!/usr/bin/gbd -P lub #!/usr/bin/gbd --python, a następnie napisać kod Python w nim, a następnie uczynić go wykonywalnym chmod +x pygdbscript, a następnie uruchomić ./pygdbscript; ... ale jak w tym poście:

..., mam gdb: unrecognized option '--python' jeśli próbuję coś podobnego. Podobno ta opcja jest/była funkcją w jakiejś gałęzi "łuczników" gdb?!


Tak, aby uruchomić skrypt Pythona w gdb istnieją właściwie dwa sposoby:

  • Nazwa pliku skryptu z rozszerzeniem .py; powiedzieć test.py tutaj:
def Something(): 
    print("hello from python") 

Something() 
gdb.execute("quit"); 

Uwaga, w tym przypadku, po prostu napisać zwykły kod Pythona; i nie trzeba do import gdb, aby uzyskać dostęp do obiektu gdb. Ten można uruchomić z jednym z:

gdb -x test.py 
gdb -x=test.py 
gdb --command test.py 
gdb --command=test.py 
gdb -command test.py 
gdb -command=test.py 

... co wydaje się być równoważne, jako wynik dla każdego z nich jest taki sam wydruk przed gdb jest instruowany, aby wyjść przez skrypt:

$ gdb -x=test.py 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1 
... 
For help, type "help". 
Type "apropos word" to search for commands related to "word". 
hello from python 

UWAGA, że w tym przypadku, jak również nazwy test.gdb.py będą interpretowane jako czystych skryptów Pythona, gdyż wtedy kończy się .py.

  • Nazwa skryptu cokolwiek innego - tak długo, jak to robi nie.py koniec z rozszerzeniem; powiedzieć test.pygdb tutaj:
python 
def Something(): 
    print("hello from python") 

Something() 
gdb.execute("quit"); 
end 

W tym przypadku gdb interpretuje skrypt jako bycie gdb skrypt, czyli z gdb poleceń - a to oznacza, że ​​bez względu na kod Pythona może chcesz napisać tutaj, koniecznością zapakowane w "python" jako linię startową i "end" na końcu kodu Pythona. Ponownie, to można nazwać któregokolwiek z tych połączeń równorzędnych:

gdb -x test.pygdb 
gdb -x=test.pygdb 
gdb --command test.pygdb 
gdb --command=test.pygdb 
gdb -command test.pygdb 
gdb -command=test.pygdb 

... i to wyjście jest taki sam, jak w poprzednim przypadku (ponieważ jest to ten sam skrypt Pythona bieg):

$ gdb -x test.pygdb 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1 
... 
hello from python 

w odpowiedzi na OP: jeśli kod C w pO znajduje się /tmp/myprog.c - z dodanym int start_test() { return rand() % 50; } na górze, w przeciwnym razie nie będzie opracować -, i opracowano zz gcc -g myprog.c -o myprog.exe do /tmp/myprog.exe; następnie można użyć myprog.gdb.py skrypt tak:

# need to specify the executable file which we debug (in this case, not from command line) 
# here `gdb` command `file` is used - it does not have a Python equivalent (https://sourceware.org/gdb/onlinedocs/gdb/Objfiles-In-Python.html#index-Objfile_002eframe_005ffilters) 
# so we must use gdb.execute: 

myexefile="/tmp/myprog.exe" 
print(""" 
### myprog.gdb.py is running: """ + myexefile + """ - and adding breakpoints: 
""") 

gdb.execute("file " + myexefile) 
gdb.execute("set pagination off") 

ax = gdb.Breakpoint("test_success") 
bx = gdb.Breakpoint("test_failed") 

gdb.execute("run") 

# here the program will break, so we can do: 

print(""" 
### myprog.gdb.py after the break - current stack frame: 
""") 

current_frame_at_break = gdb.selected_frame() 
print(current_frame_at_break) # instead of gdb.execute("frame") 

print(""" 
### myprog.gdb.py - backtrace: 
""") 

gdb.execute("backtrace 2") 

print(""" 
### myprog.gdb.py - go to frame that called current frame: 
""") 

parent_frame = current_frame_at_break.older() 
print(parent_frame) 
status_var = parent_frame.read_var("status") 
print("status_var is: ", status_var) 

... następnie uruchomić ten skrypt:

$ gdb -x myprog.gdb.py 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1 
.... 
For help, type "help". 
Type "apropos word" to search for commands related to "word". 

### myprog.gdb.py is running: /tmp/myprog.exe - and adding breakpoints: 

Breakpoint 1 at 0x400565: file myprog.c, line 8. 
Breakpoint 2 at 0x40055f: file myprog.c, line 4. 

Breakpoint 2, test_failed() at myprog.c:4 
4  while(1);  

### myprog.gdb.py after the break - current stack frame: 

{stack=0x7fffffffdc70,code=0x40055b,!special} 

### myprog.gdb.py - backtrace: 

#0 test_failed() at myprog.c:4 
#1 0x000000000040058c in main() at myprog.c:15 

### myprog.gdb.py - go to frame that called current frame: 

{stack=0x7fffffffdc90,code=0x400567,!special} 
status_var is: 33 
(gdb) 

Zauważ, że na końcu tej skrypcie (gdb) interaktywny wiersz pozostaje i możesz go normalnie używać tutaj; jeśli nie potrzebujesz interaktywnego pytania, możesz wykonać, tak jak w powyższych skryptach, aby wymusić na końcu wykonywania skryptu gdb.

Również na przykładzie klasy subclassing przerwania w gdb Pythonie zobaczyć How to print the current line of source at breakpoint in GDB and nothing else?

Powiązane problemy