Как написать скрипт gdb (с python)? Пример добавить точки останова, запустить, какую точку останова мы достигли? - PullRequest
12 голосов
/ 31 октября 2010

Я пытаюсь создать небольшой модульный тест с gdb для встроенного mcu, который контролируется OpenOCD (который дает мне контроль над моей целью через сервер gdb).

Поэтому я хотел бы автоматизировать это с помощью некоторого сценария gdb.

Я хотел бы написать какой-нибудь сценарий для gdb, который более или менее делает это:

  1. Добавить паруиз точек останова
  2. Запустить программу
  3. Когда мы остановились, где она остановилась (получить информацию о кадре)
  4. Выход.

Есть идеи?

Пример того, как это сделать в сценариях Python GDB, был бы неплох.

Спасибо, Йохан


Примечание :

Допустим, у нас есть эта базовая структура, которая более или менее входит в test_failed () или test_success () в зависимости от того, что возвращает функция start_test ().

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);    
}

Выполнить это вручную в gdbочень прямолинейно,

(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) 

Поэтому следующим шагом, который я попытался, было добавить эти команды GDB в сценарий запуска GDB, который более или менее просто выглядел так:

break test_success
break test_failed
target remote localhost:3333
cont 
frame

и запуститьэто с

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

И такого рода работы, но это не очень приятно.Как мне это сделать с помощью «новых и классных» скриптов на python, которые, похоже, поддерживает gdb.

Ответы [ 4 ]

10 голосов
/ 10 ноября 2010

FYI Последние версии GDB могут быть написаны в Python.Вы можете вызвать код Python из командной строки GDB.Это открывает целый новый мир, проверьте соответствующую документацию.Из командной строки запустите:

 dnf/yum/apt-get install gdb-doc
 info gdb extending python

Если вам не нравится текстовый информационный браузер, вот один (среди многих?) Альтернативный графический браузер:

yelp 'info:gdb' # , go to "Extending"

Здесьпример скрипта gdb-pythonОн присоединяет GDB к первой найденной программе 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))
7 голосов
/ 15 августа 2014

Сокращенный пример, который я сейчас использую:

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")

Вы можете выполнить этот скрипт из подсказки GDB следующим образом:

(gdb) source script.py

Или из командной строки:

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

Для получения дополнительной информации см. Полные Документы GDB Python API .

2 голосов
/ 31 октября 2010

ОК, я нашел ответ, задавая вопрос ... и это было очень просто.

Вы не должны использовать и "--command", и "--eval"в то же время, если вы ожидаете, что они будут выполняться в определенном порядке!

Более предсказуемый способ - поместить все в файл commands.gdb и игнорировать --eval.

Так чтостановится примерно так:

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

Где команда.g.gd выглядит следующим образом:

break test_success
break test_failed
target remote localhost:3333
cont 
frame

Но, вероятно, было бы гораздо приятнее сделать это с чем-то вроде python.

1 голос
/ 17 октября 2017

Просто хотел отметить кое-что, что меня смущает, когда я возвращаюсь к этой теме (заметьте, я сейчас нахожусь на Ubuntu 14.04, GNU gdb (Ubuntu 7.7.1-0ubuntu5 ~ 14.04.3) 7.7.1):

Во-первых, есть упоминания о том, что " можно вызвать gdb в качестве интерпретатора ":

... означает, что можно написать текстовый файл сценария со строкой шебанга #!/usr/bin/gbd -P или #!/usr/bin/gbd --python,затем напишите в нем код Python, затем сделайте его исполняемым chmod +x pygdbscript, затем запустите ./pygdbscript; ... но как в этом посте:

..., если я попробую что-нибудь подобное, я получу gdb: unrecognized option '--python'. Видимо, эта опция была / была функцией какого-то "лучника"ветвь gdb?!


Итак, чтобы запустить скрипт Python в gdb, на самом деле есть два способа:

  • Назовите файл скрипта с помощьюрасширение .py; скажем test.py здесь:
def Something():
  print("hello from python")

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

Обратите внимание, в этом случае вы просто пишете простой код Python, и вам не нужно import gdb для доступа кgdb объект. Вы можете запустить с любым из:

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

..., которые кажутся эквивалентными, так как результат для любого из них - одна и та же распечатка до того, как gdb будет введенвыход из сценария возможен для выхода:

$ 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

ПРИМЕЧАНИЕ , что для этого случая также такие имена, как test.gdb.py, будут интерпретироваться как чистые сценарии Python, поскольку с тех пор заканчиваются .py.

  • Назовите ваш сценарий что-нибудь еще - пока оно не не заканчивается расширением .py;скажем test.pygdb здесь:
python
def Something():
  print("hello from python")

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

В этом случае gdb интерпретирует скрипт как gdb скрипт, то есть с gdb командами - и это означает, что любой Pythonкод, который вы можете здесь написать, должен быть заключен в "python" в качестве начальной строки и "end" в конце кода Python.Опять же, он будет вызван любым из следующих эквивалентных вызовов:

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

... и затем вывод будет таким же, как в предыдущем случае (так как это тот же скрипт Python, выполняющийся):

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

И в ответ на OP: если код C в OP находится в /tmp/myprog.c - с добавленным int start_test() { return rand() % 50; } сверху, иначе он не скомпилируется - и компилируется сgcc -g myprog.c -o myprog.exe в /tmp/myprog.exe;затем вы можете использовать скрипт myprog.gdb.py следующим образом:

# 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)

... затем запустить этот скрипт с:

$ 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) 

Обратите внимание, что в концеэтого сценария остается интерактивное приглашение (gdb), и вы можете использовать его здесь в обычном режиме;если вам не нужна интерактивная подсказка, вы можете сделать gdb.execute("quit");, как в приведенных выше сценариях, чтобы принудительно завершить gdb в конце выполнения сценария.

Кроме того, для примера подкласса класса точки остановав gdb Python см. Как напечатать текущую строку источника в точке останова в GDB и ничего больше?

...