Ответ 1
Я нашел свой собственный ответ, читая далее возможности GDB и вопросы, касающиеся печати std::string. Короткий путь - лучший вариант на данный момент.
Короткий путь
Я просто определил команду GDB следующим образом:
# this is a gdb script
# can be loaded from gdb using
# source my_script.txt (or. gdb or whatever you like)
define pjson
# use the lohmann builtin dump method, ident 4 and use space separator
printf "%s\n", $arg0.dump(4, ' ', true).c_str()
end
# configure command helper (text displayed when typing 'help pjson' in gdb)
document pjson
Prints a lohmann JSON C++ variable as a human-readable JSON string
end
Используя его в GDB:
(gdb) source my_custom_script.gdb
(gdb) pjson foo
{
"flex" : 0.2,
"awesome_str": "bleh",
"nested": {
"bar": "barz"
}
}
Сверху (но у меня не работает)
Другой способ - определить симпатичный принтер GDB в python и сделать его тесно связанным с вашим проектом (активирована функция автозагрузки). Смотрите эту ссылку для более глубокого подхода.
В основном, когда в gdb вы наберете:
(gdb) p foo
и GDB автоматически проверит тип foo
и вызовет соответствующий симпатичный принтер, если таковой имеется. Это привело бы к тому же результату. Основное отличие состоит в том, что это делается с помощью хорошо известной команды print
и, что более важно, будет эффективным, даже если не существует низшего процесса для вызова методов из (спасибо Employed Russian за точность). Отладчику не нужно будет изучать новую команду (например, pjson
, определенный в кратком ответе).
Ниже приведено извлечение некоторых документов из GDB + попытка кода Python, которая не работает.
Цитирование:
Pretty-printer состоит из двух частей: функция поиска для определения, поддерживается ли тип, и сам принтер.
Вот пример, показывающий, как можно написать принтер
std::string
. Подробнее о API, который должен предоставлять этот класс, см. в разделе Pretty Printing API.
class StdStringPrinter(object):
"Print a std::string"
def __init__(self, val):
self.val = val
def to_string(self):
return self.val['_M_dataplus']['_M_p']
def display_hint(self):
return 'string'
Все еще цитирую ради полноты:
А вот пример, показывающий, как можно написать функцию поиска для приведенного выше примера принтера.
def str_lookup_function(val):
lookup_tag = val.type.tag
if lookup_tag == None:
return None
regex = re.compile("^std::basic_string<char,.*>$")
if regex.match(lookup_tag):
return StdStringPrinter(val)
return None
Я пытался реализовать это таким образом. Тем не менее, у меня 100% отказов со следующим кодом, с загадочными сообщениями об ошибках GDB (см. ниже пример кода)
Примечание: он опирается на предоставленный здесь трюк trick provided here, который должен разрешать вызов метода класса C++ в GDB, минуя проверку Value.Type
(методы объекта можно найти, и их value.Type
будет gdb.TYPE_CODE_METHOD
, но GDB Python не будет считать их вызываемыми. Только gdb.TYPE_CODE_FUNC
могут быть вызваны. Таким образом, parse_and_eval
действует как хак для выполнения фактического вызова метода).
import gdb
import re
class StdStringPrinter(object):
"""Print a std::string"""
def __init__(self, val):
self.val = val
def to_string(self):
eval_string = "(*("+str(self.val.type)+"*)("+str(self.val.address)+")).c_str()" # works 50% of the time ...
return gdb.parse_and_eval(eval_string)
def display_hint(self):
return 'string'
class LohmannJSONPrinter(object):
"""Print a nlohmann::json"""
def __init__(self, val):
self.val = val
def to_string(self):
# workaround from here:
# /info/4449405/gdb-python-api-is-it-possible-to-make-a-call-to-a-classstruct-method/10038039#10038039
# "(*("+str(self.val.type)+"*)("+str(self.val.address)+")).method()"
eval_string = '(*('+str(self.val.type)+'*)('+str(self.val.address)+')).dump(4, " ", true)'
return gdb.parse_and_eval(eval_string) # fails 100% of the time
def display_hint(self):
return self.val.type
def build_pretty_printer():
pp = gdb.printing.RegexpCollectionPrettyPrinter("foo")
json = r"nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long long, unsigned long long, double, std::allocator, nlohmann::adl_serializer>"
pp.add_printer('nlohmann::json', json, LohmannJSONPrinter)
return pp
# executed at autoload gdb.printing.register_pretty_printer(gdb.current_objfile(),
build_pretty_printer())
Ошибки:
Cannot insert breakpoint -18. // or any negative value
Cannot access memory at address 0x111a2180 // appears to be a fixed value at each execution
Python Exception <class 'gdb.error'> Command aborted.
или
$2 = Python Exception <class 'gdb.error'> Attempt to take address of value not located in memory.:
Изменить 2019-март-24: добавить точность, заданную занятым русским языком.