duel
command in gdb on some ancient IRIX, about fifteen years ago. It was an incredibly cool thing to view various related lists, arrays of structures, and other similar constructs. Dreamed, they say, if I had such a Linux, and forgot. About ten years ago I remembered, googled - it turned out that DUEL, this is actually a 93rd patch for gdb 4.6, and not at all something unique in IRIX. Only the author for ideological reasons released it as the public domain, and gdb-schnick were also ideological and wanted the GPL, so it did not threaten to get into the upstream patch. I ported it to the then gdb 6.6.2, gave it to gentoo and before the release of the 7th gdb enjoyed life. Then the duel from gentoo was thrown out, it was difficult to port to the new gdb, nobody took it. And recently I tried to revive him. Only instead of a patch (it is necessary to assemble together with gdb from sources, it uses all sorts of internal gdb functions) I wrote it from scratch on python. Now Duel.py (this is the name of the new implementation of Duel) is loaded into gdb on the fly, and I hope the Python API will not change from version to version as undocumented gdb shny giblets. So, meet: DUEL is a high-level data analysis language for gdb. (gdb) dl table_list-->next_local->table_name tables->table_name = 0x7fffc40126b8 "t2" tables->next_local->table_name = 0x7fffc4012d18 "t1" tables-->next_local[[2]]->table_name = 0x7fffc4013388 "t1"
TABLE_LIST
connected list of TABLE_LIST
structures and displays TABLE_LIST::table_name
for each list TABLE_LIST::table_name
. (gdb) dl longopts[0..].name @0 longopts[0].name = "help" longopts[1].name = "allow-suspicious-udfs" longopts[2].name = "ansi" <... cut ...> longopts[403].name = "session_track_schema" longopts[404].name = "session_track_transaction_info" longopts[405].name = "session_track_state_change"
name == 0
. And you can simply count how many of them: (gdb) dl #/longopts[0..].name @0 #/longopts[0..].name@0 = 406
(gdb) dl 1..4 1 = 1 2 = 2 3 = 3 4 = 4
(gdb) dl my_long_options[1..4].(name,def_value) my_long_options[1].(name) = "allow-suspicious-udfs" my_long_options[1].(def_value) = 0 my_long_options[2].(name) = "ansi" my_long_options[2].(def_value) = 0 my_long_options[3].(name) = "autocommit" my_long_options[3].(def_value) = 1 my_long_options[4].(name) = "bind-address" my_long_options[4].(def_value) = 0
..20
, then the range will start from zero and there will be 20 values in it, just as if 0..19
was written. If you specify only the beginning, you get an open range! In order for duel not to continue generating numbers until the thermal death of the universe (or until the counter overflow, whichever happens earlier), the stop operator is usually used along with the open range by the condition, @
.x@y
, the expression x
will generate values as long as y
false. For example, (gdb) dl arr[0..]@(count > 10)
arr[]
array until arr[i].count
is not more than ten. (gdb) dl str[0..]@0
'\0'
. A more practical example is to output all command line options from argv
: (gdb) dl argv[0..]@0 argv[0] = "./mysqld" argv[1] = "--log-output=file" argv[2] = "--gdb" argv[3] = "--core-file"
(gdb) dl argv[..argc] argv[0] = "./mysqld" argv[1] = "--log-output=file" argv[2] = "--gdb" argv[3] = "--core-file"
a-->b
generates a set of values a
, a->b
, a->b->b
, and so on, until it hits a null. I have already given an example of how in this way one can go through a single-linked list. But it works the same way for trees, for example: (gdb) dl tree-->(left,right)->info
(gdb) dl i:=5 i = 5 (gdb) dl i+6 i+6 = 11 (gdb) dl {i}+6 5+6 = 11 (gdb) dl {i+6} 11 = 11
(gdb) dl if (my_long_options[i:=1..20].name[0] == 'd') my_long_options[i].name if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-abort-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-assert-on-error" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-assert-if-crashed-table" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-disconnect-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-exit-info" (gdb) dl if (my_long_options[i:=1..20].name[0] == 'd') my_long_options[{i}].name if(my_long_options[i].name[0] == 'd') my_long_options[16].name = "debug-abort-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[17].name = "debug-assert-on-error" if(my_long_options[i].name[0] == 'd') my_long_options[18].name = "debug-assert-if-crashed-table" if(my_long_options[i].name[0] == 'd') my_long_options[19].name = "debug-disconnect-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[20].name = "debug-exit-info"
x !=? y
x !=? y
, only those that are not equal to y
are selected from the set of x
values. Above was an example with a conditional if
. With the filter, the same result is easier: (gdb) dl my_long_options[1..20].(name[0] ==? 'd' => name) my_long_options[16].(name) = "debug-abort-slave-event-count" my_long_options[17].(name) = "debug-assert-on-error" my_long_options[18].(name) = "debug-assert-if-crashed-table" my_long_options[19].(name) = "debug-disconnect-slave-event-count" my_long_options[20].(name) = "debug-exit-info"
if
) and other rarely necessary things.head
and follow the signs until we reach the head
again): (gdb) head-->(next!=?head)
x[]
. The [[ ]]
operator selects elements from the sequence: (gdb) dl (x[0..] >? 0)[[2]]
#/
, which returns the number of elements in the sequence, and the selector operator [[ ]]
: (gdb) head-->next[[#/head-->next - 1]]
(gdb) dl x[i:=..100] >? x[i+1]
-->
and @0
.Source: https://habr.com/ru/post/328180/
All Articles