nlohmannのjson C++実装 を使用してプロジェクトに取り組んでいます。
GDBでnlohmannのJSONキー/値を簡単に探索するにはどうすればよいですか?
これを使用しようとしました STL gdb wrapping これは、nlohmannのJSON libが使用している標準C++ライブラリ構造を探索するためのヘルパーを提供するためです。しかし、私はそれが便利だとは思いません。
簡単な使用例を次に示します。
json foo;
foo["flex"] = 0.2;
foo["awesome_str"] = "bleh";
foo["nested"] = {{"bar", "barz"}};
GDBに入れたいもの:
(gdb) p foo
{
"flex" : 0.2,
"awesome_str": "bleh",
"nested": etc.
}
現在の行動
(gdb) p foo
$1 = {
m_type = nlohmann::detail::value_t::object,
m_value = {
object = 0x129ccdd0,
array = 0x129ccdd0,
string = 0x129ccdd0,
boolean = 208,
number_integer = 312266192,
number_unsigned = 312266192,
number_float = 1.5427999782486669e-315
}
}
(gdb) p foo.at("flex")
Cannot evaluate function -- may be inlined // I suppose it depends on my compilation process. But I guess it does not invalidate the question.
(gdb) p *foo.m_value.object
$2 = {
_M_t = {
_M_impl = {
<std::allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 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> > > >> = {
<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, 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> > > >> = {<No data fields>}, <No data fields>},
<std::_Rb_tree_key_compare<std::less<void> >> = {
_M_key_compare = {<No data fields>}
},
<std::_Rb_tree_header> = {
_M_header = {
_M_color = std::_S_red,
_M_parent = 0x4d72d0,
_M_left = 0x4d7210,
_M_right = 0x4d7270
},
_M_node_count = 5
}, <No data fields>}
}
}
print of std :: string に関するGDB機能とスタックオーバーフローの質問を読んで、自分の答えを見つけました。 short pathが今のところ最良のオプションです。
ショートパスv3.1.2
私は単に次のように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"
}
}
ショートパスv3.7.0 [編集] 2019-onv-06新しいto_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, json::error_handler_t::strict).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
オーバーザ(しかし私には役に立たない)
もう1つの方法は、GDBpretty printerをpythonで定義し、プロジェクトに密接に関連付けることです(オートローディングスタッフ)詳細なアプローチについては このリンク を参照してください。
基本的に、gdbで次のように入力します。
(gdb) p foo
そして、GDBは_foo
のタイプを自動的にテストし、関連するプリティプリンターがあればそれを呼び出します。それは同じ結果になるでしょう。主な違いは、よく知られているprint
コマンドを使用して行われることであり、さらに重要なのは、from(精度に感謝ロシア語を採用)。デバッグする人は、新しいコマンド(短い答えで定義されたpjson
のような)を学ぶ必要はありません。
以下に、いくつかのGDBドキュメントの抜粋+ python機能しないコードの試み。
引用:
Pretty-printerは2つの部分で構成されます。タイプがサポートされているかどうかを検出するルックアップ関数と、プリンター自体です。
以下は、
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エラーメッセージが表示されます(コードサンプルの下を参照)
注:Value.Type
チェックをバイパスして、GDB内でC++クラスメソッドの呼び出しを許可することになっている ここで提供されるトリック に依存しています(オブジェクトメソッドが見つかり、そのvalue.Type
はgdb.TYPE_CODE_METHOD
になりますが、gdb pythonは呼び出し可能とは見なしません。呼び出し可能なのはgdb.TYPE_CODE_FUNC
のみです。したがって、実際のメソッドを実行するためのハックとしてparse_and_eval
actsコール)。
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年3月24日を編集:雇用されたロシア語によって与えられる精度を追加します。
私の解決策は〜/ .gdbinitファイルを編集することでした。
define jsontostring
printf "%s\n", $arg0.dump(2, ' ', true, nlohmann::detail::error_handler_t::strict).c_str()
end
これにより、「jsontostring」コマンドは、ファイルを調達する必要なく、すべてのgdbセッションで利用可能になります。
(gdb) jsontostring object