From 3cf55f763ef8c75e8e8c11fca3c3e564668aee52 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Sat, 8 Nov 2014 17:53:18 -0800 Subject: Make it easier to debug scripts, especially from coredumps --- src/map/script-parse.py | 553 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 src/map/script-parse.py (limited to 'src/map/script-parse.py') diff --git a/src/map/script-parse.py b/src/map/script-parse.py new file mode 100644 index 0000000..de27d57 --- /dev/null +++ b/src/map/script-parse.py @@ -0,0 +1,553 @@ +class ScriptBuffer(object): + __slots__ = ('_value') + name = 'tmwa::ScriptBuffer' + enabled = True + + def __init__(self, value): + self._value = value + + def to_string(self): + return self._value['debug_name'] + + def get_com(self, b, i, r, labels_dict): + # see script-parse-internal.hpp:ByteCode and script-call.cpp:get_com + ops = ''' + NOP, POS, INT, PARAM, FUNC, STR, ARG, + VARIABLE, EOL, + LOR, LAND, LE, LT, GE, GT, EQ, NE, + XOR, OR, AND, ADD, SUB, MUL, DIV, MOD, + NEG, LNOT, NOT, R_SHIFT, L_SHIFT, + FUNC_REF, + '''.replace(',', '').split() + ci = int(b[i]) + if ci >= 0x80: + rv = 0 + sh = 0 + # Because of how the python iterator up a frame consumed the i already, + # have to manually unroll the first iteration of the C loop. + # TODO itertools.chain([i], r) or something? + if True: + if True: + rv += (ci & 0x7f) << sh + sh += 6 + if ci >= 0xc0: + while True: + i = next(r) + ci = int(b[i]) + + rv += (ci & 0x7f) << sh + sh += 6 + if not (ci >= 0xc0): + break + return 'INT %d' % rv + + cs = ops[ci] + if cs in {'POS', 'VARIABLE', 'FUNC_REF', 'PARAM'}: + ai = 0 + ai |= (int(b[next(r)]) << 0) + ai |= (int(b[next(r)]) << 8) + ai |= (int(b[next(r)]) << 16) + if cs == 'POS': + ln = labels_dict.get(ai) + if ln is not None: + return 'POS %d %s' % (ai, ln[0]) + elif cs == 'VARIABLE': + global rstring_disable_children + rstring_disable_children = True + try: + rv = 'VARIABLE %s' % gdb.parse_and_eval('tmwa::variable_names.names._M_impl._M_start[{ai}]'.format(ai=ai)) + finally: + rstring_disable_children = False + return rv + elif cs == 'FUNC_REF': + return 'FUNC_REF %s' % gdb.parse_and_eval('tmwa::builtin_functions[{ai}].name'.format(ai=ai)) + elif cs == 'PARAM': + # https://sourceware.org/bugzilla/show_bug.cgi?id=17568 + try: + # this should work + SP = gdb.lookup_type('tmwa::SP') + except gdb.error: + # this should not work + SP = gdb.parse_and_eval('tmwa::SP').type + return 'PARAM %s' % gdb.Value(ai).cast(SP) + else: + assert False + return '%s %d' % (cs, ai) + elif cs == 'STR': + buf = bytearray() + while True: + i = next(r) + ci = int(b[i]) + if ci == 0: + break + buf.append(ci) + return 'STR "%s"' % str(buf).replace('\\', '\\\\').replace('"', '\\"') + elif cs == 'EOL': + return cs + '\n' + return cs + + def children(self): + labels = self._value['debug_labels'] + labels_begin = labels['_M_impl']['_M_start'] + labels_end = labels['_M_impl']['_M_finish'] + labels_size = int(labels_end - labels_begin) + labels_list = [labels_begin[i] for i in range(labels_size)] + labels_dict = {} + char_ptr = gdb.lookup_type('char').pointer() + for e in labels_list: + offset = int(e['second']) + label_name = str(e['first'].address.cast(char_ptr)) + labels_dict.setdefault(offset, []).append(label_name) + code = self._value['script_buf'] + code_begin = code['_M_impl']['_M_start'] + code_end = code['_M_impl']['_M_finish'] + code_size = int(code_end - code_begin) + r = iter(range(code_size)) + for i in r: + buf = [] + for label in labels_dict.get(i, []): + if label.startswith('On'): + yield 'blah', 'event %s:' % label + else: + yield 'blah', 'label %s:' % label + c = self.get_com(code_begin, i, r, labels_dict) + yield 'blah', '%6d: %s' % (i, c) + + + def display_hint(self): + return 'array' + + src = ''' + { + end; + S_Sub: + return; + OnFoo: + callsub S_Sub; + setarray @a, + -1, 0, 1, + 0x0, 0x1, 0x2, + 0x1, 0x2, 0x3, + 0x3, 0x4, 0x5, + 0x7, 0x8, 0x9, + 0xf, 0x10, 0x11, + 0x1f, 0x20, 0x21, + 0x3f, 0x40, 0x41, + 0x7f, 0x80, 0x81, + 0xff, 0x100, 0x101, + 0x1ff, 0x200, 0x201, + 0x3ff, 0x400, 0x401, + 0x7ff, 0x800, 0x801, + 0xfff, 0x1000, 0x1001, + 0x1fff, 0x2000, 0x2001, + 0x3fff, 0x4000, 0x4001, + 0x7fff, 0x8000, 0x8001, + 0xffff, 0x10000, 0x10001, + 0x1ffff, 0x20000, 0x20001, + 0x3ffff, 0x40000, 0x40001, + 0x7ffff, 0x80000, 0x80001, + 0xfffff, 0x100000, 0x100001, + 0x1fffff, 0x200000, 0x200001, + 0x3fffff, 0x400000, 0x400001, + 0x7fffff, 0x800000, 0x800001, + 0xffffff, 0x1000000, 0x1000001, + 0x1ffffff, 0x2000000, 0x2000001, + 0x3ffffff, 0x4000000, 0x4000001, + 0x7ffffff, 0x8000000, 0x8000001, + 0xfffffff, 0x10000000, 0x10000001, + 0x1fffffff, 0x20000000, 0x20000001, + 0x3fffffff, 0x40000000, 0x40000001, + 0x7fffffff, 0x80000000, 0x80000001, + 0xffffffff; + set TEST_FAKE_PARAM_BASELEVEL, TEST_FAKE_CONSTANT; + set @s$, "hello"; + set @i, a || b; + set @i, a && b; + set @i, a <= b; + set @i, a < b; + set @i, a >= b; + set @i, a > b; + set @i, a == b; + set @i, a != b; + set @i, a ^ b; + set @i, a | b; + set @i, a & b; + set @i, a + b; + set @i, a - b; + set @i, a * b; + set @i, a / b; + set @i, a % b; + set @i, - b; + set @i, ! b; + set @i, ~ b; + set @i, a >> b; + set @i, a << b; + } + '''.replace('\n', ' ') + + asm = ''\ + +''' 0: FUNC_REF "end", + 4: ARG, + 5: FUNC, + 6: EOL + , + label "S_Sub":, + 7: FUNC_REF "return", + 11: ARG, + 12: FUNC, + 13: EOL + , + label "OnFoo":, + 14: FUNC_REF "callsub", + 18: ARG, + 19: POS 7 "S_Sub", + 23: FUNC, + 24: EOL + , + 25: FUNC_REF "setarray", + 29: ARG, + 30: VARIABLE "@a", + 34: INT 1, + 35: NEG, + 36: INT 0, + 37: INT 1, + 38: INT 0, + 39: INT 1, + 40: INT 2, + 41: INT 1, + 42: INT 2, + 43: INT 3, + 44: INT 3, + 45: INT 4, + 46: INT 5, + 47: INT 7, + 48: INT 8, + 49: INT 9, + 50: INT 15, + 51: INT 16, + 52: INT 17, + 53: INT 31, + 54: INT 32, + 55: INT 33, + 56: INT 63, + 57: INT 64, + 59: INT 65, + 61: INT 127, + 63: INT 128, + 65: INT 129, + 67: INT 255, + 69: INT 256, + 71: INT 257, + 73: INT 511, + 75: INT 512, + 77: INT 513, + 79: INT 1023, + 81: INT 1024, + 83: INT 1025, + 85: INT 2047, + 87: INT 2048, + 89: INT 2049, + 91: INT 4095, + 93: INT 4096, + 95: INT 4097, + 97: INT 8191, + 100: INT 8192, + 103: INT 8193, + 106: INT 16383, + 109: INT 16384, + 112: INT 16385, + 115: INT 32767, + 118: INT 32768, + 121: INT 32769, + 124: INT 65535, + 127: INT 65536, + 130: INT 65537, + 133: INT 131071, + 136: INT 131072, + 139: INT 131073, + 142: INT 262143, + 145: INT 262144, + 148: INT 262145, + 151: INT 524287, + 155: INT 524288, + 159: INT 524289, + 163: INT 1048575, + 167: INT 1048576, + 171: INT 1048577, + 175: INT 2097151, + 179: INT 2097152, + 183: INT 2097153, + 187: INT 4194303, + 191: INT 4194304, + 195: INT 4194305, + 199: INT 8388607, + 203: INT 8388608, + 207: INT 8388609, + 211: INT 16777215, + 215: INT 16777216, + 219: INT 16777217, + 223: INT 33554431, + 228: INT 33554432, + 233: INT 33554433, + 238: INT 67108863, + 243: INT 67108864, + 248: INT 67108865, + 253: INT 134217727, + 258: INT 134217728, + 263: INT 134217729, + 268: INT 268435455, + 273: INT 268435456, + 278: INT 268435457, + 283: INT 536870911, + 288: INT 536870912, + 293: INT 536870913, + 298: INT 1073741823, + 303: INT 1073741824, + 308: INT 1073741825, + 313: INT 2147483647, + 319: INT 2147483648, + 325: INT 2147483649, + 331: INT 4294967295, + 337: FUNC, + 338: EOL + , + 339: FUNC_REF "set", + 343: ARG, + 344: PARAM tmwa::SP::BASELEVEL, + 348: INT 42, + 349: FUNC, + 350: EOL + , + 351: FUNC_REF "set", + 355: ARG, + 356: VARIABLE "@s$", + 360: STR "hello", + 367: FUNC, + 368: EOL + , + 369: FUNC_REF "set", + 373: ARG, + 374: VARIABLE "@i", + 378: VARIABLE "a", + 382: VARIABLE "b", + 386: LOR, + 387: FUNC, + 388: EOL + , + 389: FUNC_REF "set", + 393: ARG, + 394: VARIABLE "@i", + 398: VARIABLE "a", + 402: VARIABLE "b", + 406: LAND, + 407: FUNC, + 408: EOL + , + 409: FUNC_REF "set", + 413: ARG, + 414: VARIABLE "@i", + 418: VARIABLE "a", + 422: VARIABLE "b", + 426: LE, + 427: FUNC, + 428: EOL + , + 429: FUNC_REF "set", + 433: ARG, + 434: VARIABLE "@i", + 438: VARIABLE "a", + 442: VARIABLE "b", + 446: LT, + 447: FUNC, + 448: EOL + , + 449: FUNC_REF "set", + 453: ARG, + 454: VARIABLE "@i", + 458: VARIABLE "a", + 462: VARIABLE "b", + 466: GE, + 467: FUNC, + 468: EOL + , + 469: FUNC_REF "set", + 473: ARG, + 474: VARIABLE "@i", + 478: VARIABLE "a", + 482: VARIABLE "b", + 486: GT, + 487: FUNC, + 488: EOL + , + 489: FUNC_REF "set", + 493: ARG, + 494: VARIABLE "@i", + 498: VARIABLE "a", + 502: VARIABLE "b", + 506: EQ, + 507: FUNC, + 508: EOL + , + 509: FUNC_REF "set", + 513: ARG, + 514: VARIABLE "@i", + 518: VARIABLE "a", + 522: VARIABLE "b", + 526: NE, + 527: FUNC, + 528: EOL + , + 529: FUNC_REF "set", + 533: ARG, + 534: VARIABLE "@i", + 538: VARIABLE "a", + 542: VARIABLE "b", + 546: XOR, + 547: FUNC, + 548: EOL + , + 549: FUNC_REF "set", + 553: ARG, + 554: VARIABLE "@i", + 558: VARIABLE "a", + 562: VARIABLE "b", + 566: OR, + 567: FUNC, + 568: EOL + , + 569: FUNC_REF "set", + 573: ARG, + 574: VARIABLE "@i", + 578: VARIABLE "a", + 582: VARIABLE "b", + 586: AND, + 587: FUNC, + 588: EOL + , + 589: FUNC_REF "set", + 593: ARG, + 594: VARIABLE "@i", + 598: VARIABLE "a", + 602: VARIABLE "b", + 606: ADD, + 607: FUNC, + 608: EOL + , + 609: FUNC_REF "set", + 613: ARG, + 614: VARIABLE "@i", + 618: VARIABLE "a", + 622: VARIABLE "b", + 626: SUB, + 627: FUNC, + 628: EOL + , + 629: FUNC_REF "set", + 633: ARG, + 634: VARIABLE "@i", + 638: VARIABLE "a", + 642: VARIABLE "b", + 646: MUL, + 647: FUNC, + 648: EOL + , + 649: FUNC_REF "set", + 653: ARG, + 654: VARIABLE "@i", + 658: VARIABLE "a", + 662: VARIABLE "b", + 666: DIV, + 667: FUNC, + 668: EOL + , + 669: FUNC_REF "set", + 673: ARG, + 674: VARIABLE "@i", + 678: VARIABLE "a", + 682: VARIABLE "b", + 686: MOD, + 687: FUNC, + 688: EOL + , + 689: FUNC_REF "set", + 693: ARG, + 694: VARIABLE "@i", + 698: VARIABLE "b", + 702: NEG, + 703: FUNC, + 704: EOL + , + 705: FUNC_REF "set", + 709: ARG, + 710: VARIABLE "@i", + 714: VARIABLE "b", + 718: LNOT, + 719: FUNC, + 720: EOL + , + 721: FUNC_REF "set", + 725: ARG, + 726: VARIABLE "@i", + 730: VARIABLE "b", + 734: NOT, + 735: FUNC, + 736: EOL + , + 737: FUNC_REF "set", + 741: ARG, + 742: VARIABLE "@i", + 746: VARIABLE "a", + 750: VARIABLE "b", + 754: R_SHIFT, + 755: FUNC, + 756: EOL + , + 757: FUNC_REF "set", + 761: ARG, + 762: VARIABLE "@i", + 766: VARIABLE "a", + 770: VARIABLE "b", + 774: L_SHIFT, + 775: FUNC, + 776: EOL + , + 777: NOP'''.replace(''' + ''', '\n') + + test_extra = (''' + #include "../compat/borrow.hpp" + #include "../io/line.hpp" + #include "../mmo/clif.t.hpp" + #include "../ast/script.hpp" + #include "../map/script-parse-internal.hpp" + + using tmwa::operator "" _s; + + static + const tmwa::ScriptBuffer& test_script_buffer(tmwa::LString source) + { + auto p = tmwa::add_strp("TEST_FAKE_PARAM_BASELEVEL"_s); + p->type = tmwa::StringCode::PARAM; + p->val = static_cast(tmwa::SP::BASELEVEL); + p = tmwa::add_strp("TEST_FAKE_CONSTANT"_s); + p->type = tmwa::StringCode::INT; + p->val = 42; + + tmwa::io::LineCharReader lr(tmwa::io::from_string, "