Skip to content

Commit 932dab7

Browse files
committed
dbg: introduce lj-gco command
Our GDB extension already has dumpers for TValues. But sometimes it may be useful to dump GC objects (GCobj) without stack context. This patch adds additional wrappers around dumpers for GC objects to get the corresponding GC object from a TValue. Also, the lj-gco command is introduced. It allows dumping GC objects without stack context. The output format is the same as for the lj-tv command. Part of tarantool/tarantool#4808 Reviewed-by: Evgeniy Temirgaleev <e.temirgaleev@tarantool.org> Reviewed-by: Sergey Bronnikov <sergeyb@tarantool.org> Signed-off-by: Sergey Kaplun <skaplun@tarantool.org> (cherry picked from commit 7b919c0)
1 parent 2410dc4 commit 932dab7

2 files changed

Lines changed: 223 additions & 75 deletions

File tree

src/luajit_dbg.py

Lines changed: 125 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -882,44 +882,29 @@ def lightudV(tv):
882882

883883
# Dumpers.
884884

885+
# GCobj dumpers.
885886

886-
def dump_lj_tnil(tv):
887-
return 'nil'
888-
889-
890-
def dump_lj_tfalse(tv):
891-
return 'false'
892-
893-
894-
def dump_lj_ttrue(tv):
895-
return 'true'
896-
897-
898-
def dump_lj_tlightud(tv):
899-
return 'light userdata @ {}'.format(strx64(lightudV(tv)))
900-
901-
902-
def dump_lj_tstr(tv):
887+
def dump_lj_gco_str(gcobj):
903888
return 'string {body} @ {address}'.format(
904-
body=strdata(gcval(tv['gcr'])),
905-
address=strx64(gcval(tv['gcr']))
889+
body=strdata(gcobj),
890+
address=strx64(gcobj)
906891
)
907892

908893

909-
def dump_lj_tupval(tv):
910-
return 'upvalue @ {}'.format(strx64(gcval(tv['gcr'])))
894+
def dump_lj_gco_upval(gcobj):
895+
return 'upvalue @ {}'.format(strx64(gcobj))
911896

912897

913-
def dump_lj_tthread(tv):
914-
return 'thread @ {}'.format(strx64(gcval(tv['gcr'])))
898+
def dump_lj_gco_thread(gcobj):
899+
return 'thread @ {}'.format(strx64(gcobj))
915900

916901

917-
def dump_lj_tproto(tv):
918-
return 'proto @ {}'.format(strx64(gcval(tv['gcr'])))
902+
def dump_lj_gco_proto(gcobj):
903+
return 'proto @ {}'.format(strx64(gcobj))
919904

920905

921-
def dump_lj_tfunc(tv):
922-
func = dbg.cast('struct GCfuncC *', gcval(tv['gcr']))
906+
def dump_lj_gco_func(gcobj):
907+
func = dbg.cast('struct GCfuncC *', gcobj)
923908
ffid = func['ffid']
924909

925910
if ffid == 0:
@@ -936,62 +921,115 @@ def dump_lj_tfunc(tv):
936921
return 'fast function #{}'.format(int(ffid))
937922

938923

939-
def dump_lj_ttrace(tv):
940-
trace = dbg.cast('struct GCtrace *', gcval(tv['gcr']))
924+
def dump_lj_gco_trace(gcobj):
925+
trace = dbg.cast('struct GCtrace *', gcobj)
941926
return 'trace {traceno} @ {addr}'.format(
942927
traceno=strx64(trace['traceno']),
943928
addr=strx64(trace)
944929
)
945930

946931

947-
def dump_lj_tcdata(tv):
948-
return 'cdata @ {}'.format(strx64(gcval(tv['gcr'])))
932+
def dump_lj_gco_cdata(gcobj):
933+
return 'cdata @ {}'.format(strx64(gcobj))
949934

950935

951-
def dump_lj_ttab(tv):
952-
table = dbg.cast('GCtab *', gcval(tv['gcr']))
936+
def dump_lj_gco_tab(gcobj):
937+
table = dbg.cast('GCtab *', gcobj)
953938
return 'table @ {gcr} (asize: {asize}, hmask: {hmask})'.format(
954939
gcr=strx64(table),
955940
asize=table['asize'],
956941
hmask=strx64(table['hmask']),
957942
)
958943

959944

960-
def dump_lj_tudata(tv):
961-
return 'userdata @ {}'.format(strx64(gcval(tv['gcr'])))
945+
def dump_lj_gco_udata(gcobj):
946+
return 'userdata @ {}'.format(strx64(gcobj))
947+
948+
949+
def dump_lj_gco_invalid(gcobj):
950+
return 'not valid type @ {}'.format(strx64(gcobj))
951+
952+
953+
# TValue dumpers
954+
955+
def dump_lj_tv_nil(tv):
956+
return 'nil'
957+
958+
959+
def dump_lj_tv_false(tv):
960+
return 'false'
961+
962+
963+
def dump_lj_tv_true(tv):
964+
return 'true'
965+
966+
967+
def dump_lj_tv_lightud(tv):
968+
return 'light userdata @ {}'.format(strx64(lightudV(tv)))
969+
970+
971+
# Generate wrappers for TValues containing GCobj.
972+
gco_fn_dumpers = [
973+
fn for fn in globals().keys() if fn.startswith('dump_lj_gco')
974+
]
975+
for fn_name in gco_fn_dumpers:
976+
wrapped_fn_name = fn_name.replace('gco', 'tv')
977+
# Lambda takes `fn_name` as a reference, so the additional
978+
# lambda is needed to fixate the correct wrapper.
979+
globals()[wrapped_fn_name] = (lambda f: (
980+
lambda tv: globals()[f](gcval(tv['gcr']))
981+
))(fn_name)
962982

963983

964-
def dump_lj_tnumx(tv):
984+
def dump_lj_tv_numx(tv):
965985
if tvisint(tv):
966986
return 'integer {}'.format(dbg.cast('int32_t', tv['i']))
967987
else:
968988
return 'number {}'.format(dbg.cast('double', tv['n']))
969989

970990

971-
def dump_lj_invalid(tv):
972-
return 'not valid type @ {}'.format(strx64(gcval(tv['gcr'])))
973-
974-
975-
dumpers = {
976-
'LJ_TNIL': dump_lj_tnil,
977-
'LJ_TFALSE': dump_lj_tfalse,
978-
'LJ_TTRUE': dump_lj_ttrue,
979-
'LJ_TLIGHTUD': dump_lj_tlightud,
980-
'LJ_TSTR': dump_lj_tstr,
981-
'LJ_TUPVAL': dump_lj_tupval,
982-
'LJ_TTHREAD': dump_lj_tthread,
983-
'LJ_TPROTO': dump_lj_tproto,
984-
'LJ_TFUNC': dump_lj_tfunc,
985-
'LJ_TTRACE': dump_lj_ttrace,
986-
'LJ_TCDATA': dump_lj_tcdata,
987-
'LJ_TTAB': dump_lj_ttab,
988-
'LJ_TUDATA': dump_lj_tudata,
989-
'LJ_TNUMX': dump_lj_tnumx,
991+
gco_dumpers = {
992+
'LJ_TSTR': dump_lj_gco_str,
993+
'LJ_TUPVAL': dump_lj_gco_upval,
994+
'LJ_TTHREAD': dump_lj_gco_thread,
995+
'LJ_TPROTO': dump_lj_gco_proto,
996+
'LJ_TFUNC': dump_lj_gco_func,
997+
'LJ_TTRACE': dump_lj_gco_trace,
998+
'LJ_TCDATA': dump_lj_gco_cdata,
999+
'LJ_TTAB': dump_lj_gco_tab,
1000+
'LJ_TUDATA': dump_lj_gco_udata,
9901001
}
9911002

9921003

1004+
tv_dumpers = {
1005+
'LJ_TNIL': dump_lj_tv_nil,
1006+
'LJ_TFALSE': dump_lj_tv_false,
1007+
'LJ_TTRUE': dump_lj_tv_true,
1008+
'LJ_TLIGHTUD': dump_lj_tv_lightud,
1009+
'LJ_TSTR': dump_lj_tv_str, # noqa: F821 # Generated.
1010+
'LJ_TUPVAL': dump_lj_tv_upval, # noqa: F821 # Generated.
1011+
'LJ_TTHREAD': dump_lj_tv_thread, # noqa: F821 # Generated.
1012+
'LJ_TPROTO': dump_lj_tv_proto, # noqa: F821 # Generated.
1013+
'LJ_TFUNC': dump_lj_tv_func, # noqa: F821 # Generated.
1014+
'LJ_TTRACE': dump_lj_tv_trace, # noqa: F821 # Generated.
1015+
'LJ_TCDATA': dump_lj_tv_cdata, # noqa: F821 # Generated.
1016+
'LJ_TTAB': dump_lj_tv_tab, # noqa: F821 # Generated.
1017+
'LJ_TUDATA': dump_lj_tv_udata, # noqa: F821 # Generated.
1018+
'LJ_TNUMX': dump_lj_tv_numx,
1019+
}
1020+
1021+
1022+
def dump_gcobj(gcobj):
1023+
return gco_dumpers.get(
1024+
typenames(i2notu32(gcobj['gch']['gct'])), dump_lj_gco_invalid
1025+
)(gcobj)
1026+
1027+
9931028
def dump_tvalue(tvalue):
994-
return dumpers.get(typenames(itypemap(tvalue)), dump_lj_invalid)(tvalue)
1029+
return tv_dumpers.get(
1030+
typenames(itypemap(tvalue)),
1031+
dump_lj_tv_invalid # noqa: F821 # Generated.
1032+
)(tvalue)
9951033

9961034

9971035
def dump_framelink_slot_address(fr):
@@ -1011,7 +1049,7 @@ def dump_framelink(L, fr):
10111049
p='P' if frame_typep(fr) & FRAME_P else ''
10121050
),
10131051
d=dbg.cast('TValue *', fr) - dbg.cast('TValue *', frame_prev(fr)),
1014-
f=dump_lj_tfunc(fr - LJ_FR2),
1052+
f=dump_lj_tv_func(fr - LJ_FR2), # noqa: F821 # Generated.
10151053
)
10161054

10171055

@@ -1142,6 +1180,35 @@ def execute(self, arg):
11421180
))
11431181

11441182

1183+
class LJDumpGCobj(dbg.LJBase):
1184+
'''
1185+
lj-gco <GCobj *>
1186+
1187+
The command receives a pointer to <GCobj> (GCobj address) and dumps
1188+
the type and some info related to it.
1189+
1190+
* LJ_TSTR: string <string payload> @ <gcr>
1191+
* LJ_TUPVAL: upvalue @ <gcr>
1192+
* LJ_TTHREAD: thread @ <gcr>
1193+
* LJ_TPROTO: proto @ <gcr>
1194+
* LJ_TFUNC: <LFUNC|CFUNC|FFUNC>
1195+
<LFUNC>: Lua function @ <gcr>, <nupvals> upvalues, <chunk:line>
1196+
<CFUNC>: C function <mcode address>
1197+
<FFUNC>: fast function #<ffid>
1198+
* LJ_TTRACE: trace <traceno> @ <gcr>
1199+
* LJ_TCDATA: cdata @ <gcr>
1200+
* LJ_TTAB: table @ <gcr> (asize: <asize>, hmask: <hmask>)
1201+
* LJ_TUDATA: userdata @ <gcr>
1202+
1203+
Whether the type of the given address differs from the listed above, then
1204+
error message occurs.
1205+
'''
1206+
1207+
def execute(self, arg):
1208+
gcobj = dbg.cast('GCobj *', dbg.eval(arg))
1209+
dbg.write('{}\n'.format(dump_gcobj(gcobj)))
1210+
1211+
11451212
class LJDumpStack(dbg.LJBase):
11461213
'''
11471214
lj-stack [<lua_State *>]
@@ -1303,6 +1370,7 @@ def load(event=None):
13031370
dbg.initialize_extension({
13041371
'lj-arch': LJDumpArch,
13051372
'lj-gc': LJGC,
1373+
'lj-gco': LJDumpGCobj,
13061374
'lj-stack': LJDumpStack,
13071375
'lj-state': LJState,
13081376
'lj-str': LJDumpString,

0 commit comments

Comments
 (0)