Я нашел свой собственный ответ, читая далее возможности GDB и вопросы переполнения стека, касающиеся print 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's 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's 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
и, что еще важнее, будет эффективным, даже если нет низшего процесса вызова методов из (спасибо Занятый русский для точности). Отладчику не нужно будет изучать новую команду (например, pjson
, определенный в кратком ответе).
Ниже приведено извлечение документации из GDB + попытка кода Python, которая не работает.
Цитирование:
Pretty-printer состоит из двух частей: функция поиска для определения, поддерживается ли тип, и сам принтер.
Вот пример, показывающий, как можно написать принтер std::string
. См. Pretty Printing API , для подробностей об 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 (см. Ниже пример кода)
Примечание: он опирается на трюк , предоставленный здесь , который должен разрешать вызов метода класса 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:
# https://stackoverflow.com/a/22798055/7237062
# "(*("+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: добавить точность, заданную используемый русский язык.