Pytanie Jak kontrolować gdb w kodzie C lub Python bez API GDB Python?


Próbuję napisać program w python lub c, który może debugować kod c przy użyciu gdb.

Czytałem rozwiązanie Toma i Wywołaj i kontroluj GDB z Pythona. Ale są one mniej więcej rozwiązaniem dla skryptów gdb w python. Ponieważ mam zamiar użyć arm-gdb do debugowania osadzonego programu, nie mogę włączyć skryptów Pythona w moim gdb.

Moim celem jest stworzenie abstrakcji gdb na wysokim poziomie. Na przykład uruchom gdb, ustaw niektóre punkty przerwania i kontynuuj w moim kodzie. Czytałem również jakiś materialny interfejs gdb / mi. Ale czy ktoś mógłby mi powiedzieć, jak używać interfejsu gdb / mi, aby stworzyć proces gdb i komunikować się z gdb z kodu c / Pythona? (Na szczęście moja arm-gdb obsługuje interfejs gdb / mi).


12
2017-07-25 21:27


pochodzenie


Mam niepublikowaną bibliotekę ruby ​​(nie pytona lub C, przepraszam), która robi to ... porzucony, ale działający projekt (abstrakcja wiadomości GDB MI i parser / budowniczy, CLI / biblioteka wywołania map, ...). Czy mogę to opublikować, jeśli jest to przydatne? - Martin Carpenter
@Martin To miło z twojej strony, że opublikujesz to, aby móc to potraktować jako odniesienie ... Dzięki za twój wysiłek. - Penny
Okay, zrobię małe wykopaliska :) i opublikuję odpowiedź z linkiem. - Martin Carpenter
dlaczego nie używać bezpośrednio libptrace? - Alex


Odpowiedzi:


Zgodnie z obietnicą zawartą w komentarzach opublikowałem moją (wczesną, niekompletną, prawie na pewno zapluskwioną) pracę z rubinem http://github.com/mcarpenter/rubug.

Oto przykład (możesz to znaleźć w examples/breakpoint). Funkcjonować check_for_crash to wywołanie zwrotne, które może zostać wywołane po wywołaniu programu factorial jest uruchomiony. Punkt przerwania przyjmuje nazwę funkcji (fac; wiodący dwukropek wskazuje tylko, że jest to rubinowy symbol, który pod każdym względem jest lekki strunowy).

EXE = 'factorial'

def check_for_crash(gdb, event)
  case event.type
  when :command_response
    raise RuntimeError, 'oops' unless
  [ :done, :running ].include? event.response.result
  when :breakpoint
    puts 'Breakpoint reached'
    pp event
    gdb.continue
  when :exit
    puts 'Exit'
    gdb.stop_event_loop
    exit
  end
end

gdb = Rubug::Gdb.new
resp = gdb.file EXE
gdb.register_callback(method :check_for_crash)
gdb.break(:fac)
gdb.run '5 > /dev/null'
gdb.start_event_loop

Ostrożnie jest cię ostrzec, że kod może być ... okrutny. Obecnie (tutaj zatrzymałem się) nic się nie dzieje (po aktualizacji gdb w połowie mojej pracy zobacz Gramatyka poniżej).

Istnieje kilka przykładów w katalogu tego samego nazwa, która może okazać się pomocna. Aby (próbować!) Uruchomić je, będziesz musiał zrobić coś takiego:

rake clean
rake grammar
rake make 
cd examples/simple_fuzzer
ruby -I ../../lib -r rubygems simple_fuzzer.rb

Biorąc pod uwagę czas, w którym zostało to napisane, prawdopodobnie powinieneś iść z rubinem1.8 jeśli masz wybór (nie byłem wtedy w 1.9 i prawdopodobnie istnieje problemy z kodowaniem stringów w punkcie 1.9).

Analizę odpowiedzi przeprowadza się na treetopie http://treetop.rubyforge.org, parser PEG. Patrząc na gramatykę z świeże oczy, jestem pewien, że można to uprościć. Musisz to zainstalować (i inne wymagane klejnoty) przy użyciu gem install ....

Kilka innych porad, jeśli robisz Pythonize:

Dokumentacja

Na zewnątrz jest niewiele "Debugowanie za pomocą GDB" (rozdział 22). Wysłałem ten plik PDF i po prostu ch. 22 jako osobny plik do docs sekcja repozytorium.

Async

Protokół jest asynchroniczny (początkowo zakładałem, że tak protokół typu komenda / odpowiedź, to był błąd). Gdybym był ponownie zaimplementować to prawdopodobnie użyłbym czegoś takiego jak maszyna zdarzenia lub libevent zamiast toczyć własne select() pętla.

Gramatyka

Gramatyka jest trochę ... myląca. Chociaż dokumentacja (27.2.2) stwierdza, że ​​odpowiedź "składa się z zero lub więcej poza pasmem zapisy następnie, opcjonalnie, przez pojedynczy rekord wyniku ":

`output -> ( out-of-band-record )* [ result-record ] "(gdb)" nl`

powinieneś zdawać sobie sprawę, że ponieważ cokolwiek może przybyć w każdej chwili read() na gnieździe może najwyraźniej wrócić async / result /jeszcze async/ terminator (!). Na przykład widzę to z moim bieżącym gdb:

=thread-group-started,id="i1",pid="1086"
=thread-created,id="1",group-id="i1"
^running
*running,thread-id="all"
(gdb)

Linia uruchomiona ^ jest rekordem wyników, wszystkie pozostałe są asynchroniczne (wtedy Terminator). To wydaje się dość znaczącą wadą specyfikacja.

Prędkość

Moim głównym celem jest bezpieczeństwo i byłem zainteresowany MI dla zautomatyzowane fuzzing, inspekcja binarna itp. Do tego celu służy również GDB / MI powolny (koszt uruchomienia programu w debugerze). YMMV.

Mapowanie MI / CLI

Było kilka rzeczy w standardowym zestawie poleceń CLI gdb, że ja nie można zobaczyć, jak zaimplementować za pomocą poleceń MI. Mam szkielet kod dla czegoś takiego:

gdb = Gdb::MI.new
gdb.cli(:file, '/bin/ls')
gdb.cli(:set, :args, '> /dev/null')
gdb.cli(:run)
gdb.cli(:quit)

(co jest miłe i jasne, myślę, że dla nas, którzy nie są znanymi przez MI-expert-ale-gdb). Nie pamiętam już, jakie były te problematyczne sprawy (minął ponad rok odkąd na to patrzyłem), ale jeśli te neurony wybuchną, wrócę i zaktualizuj to.

Alternatywy

Kiedy zacząłem na tej drodze znalazłem wpis na blogu od Jamis Buck: http://weblog.jamisbuck.org/2006/9/25/gdb-wrapper-for-ruby To otacza a sesja wiersza poleceń gdb w popen (), która trochę mnie skrzywiła. W w szczególności można się spodziewać, że będzie kruchej, ponieważ gdb sprawia, że ​​nie gwarancje stabilności wydruku CLI. Możesz (lub nie) preferuj takie podejście.

Jeśli jesteś w systemie Windows, możesz zainteresować się PyDbg / PeiMei: http://code.google.com/p/paimei/

Możesz także polubić książkę Gray Hat Python: Programowanie w języku Python dla hakerów (Seitz). Ponownie, głównie w oparciu o okna, ale może okazać się inspirujące.


5
2017-08-17 23:07





Wymienione linki są bardziej "wywoływaniem Pythona z GDB", ale pytasz, jak wywołać GDB z Pythona lub C. GDB / MI interfejs jest zdecydowanie do zrobienia. Eclipse, Emacs i KDevelop używają GDB / MI do abstrakcyjnego interfejsu debugowania. Osobiście użyłem KDevelop z trzema różnymi, krzyżowo skompilowanymi wersjami gdb dla ARM, AVR i H8S. Protokół MI zaprojektowano tak, aby był analizowany przez oprogramowanie, więc składnia jest bardzo regularna.

Wyszukiwarka Google przyniosła Opakowanie Python GDB To powinno ci na początek wystarczyć.


1
2017-08-22 18:58





A co z używaniem http://www.noah.org/python/pexpect/ ? Jest to wersja pythonowa http://en.wikipedia.org/wiki/Expect co jest bardzo przydatne do automatyzacji zadań za pomocą poleceń zewnętrznych.


0
2017-08-22 18:03