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, "