duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

ryml-gdbtypes.py (12652B)


      1 # To make this file known to Qt Creator using:
      2 # Tools > Options > Debugger > Locals & Expressions > Extra Debugging Helpers
      3 # Any contents here will be picked up by GDB, LLDB, and CDB based
      4 # debugging in Qt Creator automatically.
      5 
      6 
      7 # Example to display a simple type
      8 # template<typename U, typename V> struct MapNode
      9 # {
     10 #     U key;
     11 #     V data;
     12 # }
     13 #
     14 # def qdump__MapNode(d, value):
     15 #    d.putValue("This is the value column contents")
     16 #    d.putExpandable()
     17 #    if d.isExpanded():
     18 #        with Children(d):
     19 #            # Compact simple case.
     20 #            d.putSubItem("key", value["key"])
     21 #            # Same effect, with more customization possibilities.
     22 #            with SubItem(d, "data")
     23 #                d.putItem("data", value["data"])
     24 
     25 # Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
     26 # for more details or look at qttypes.py, stdtypes.py, boosttypes.py
     27 # for more complex examples.
     28 
     29 # to try parsing:
     30 # env PYTHONPATH=/usr/share/qtcreator/debugger/ python src/ryml-gdbtypes.py
     31 
     32 
     33 import dumper
     34 #from dumper import Dumper, Value, Children, SubItem
     35 #from dumper import SubItem, Children
     36 from dumper import *
     37 
     38 import sys
     39 import os
     40 
     41 
     42 # -----------------------------------------------------------------------------
     43 # -----------------------------------------------------------------------------
     44 # -----------------------------------------------------------------------------
     45 
     46 # QtCreator makes it really hard to figure out problems in this code.
     47 # So here are some debugging utilities.
     48 
     49 
     50 # FIXME. this decorator is not working; find out why.
     51 def dbglog(func):
     52     """a decorator that logs entry and exit of functions"""
     53     if not _DBG:
     54         return func
     55     def func_wrapper(*args, **kwargs):
     56         _dbg_enter(func.__name__)
     57         ret = func(*args, **kwargs)
     58         _dbg_exit(func.__name__)
     59         return ret
     60     return func_wrapper
     61 
     62 
     63 _DBG = False
     64 _dbg_log = None
     65 _dbg_stack = 0
     66 def _dbg(*args, **kwargs):
     67     global _dbg_log, _dbg_stack
     68     if not _DBG:
     69         return
     70     if _dbg_log is None:
     71         filename = os.path.join(os.path.dirname(__file__), "dbg.txt")
     72         _dbg_log = open(filename, "w")
     73     kwargs['file'] = _dbg_log
     74     kwargs['flush'] = True
     75     print("  " * _dbg_stack, *args, **kwargs)
     76 
     77 
     78 def _dbg_enter(name):
     79     global _dbg_stack
     80     _dbg(name, "- enter")
     81     _dbg_stack += 1
     82 
     83 
     84 def _dbg_exit(name):
     85     global _dbg_stack
     86     _dbg_stack -= 1
     87     _dbg(name, "- exit!")
     88 
     89 
     90 
     91 # -----------------------------------------------------------------------------
     92 # -----------------------------------------------------------------------------
     93 # -----------------------------------------------------------------------------
     94 
     95 
     96 NPOS = 18446744073709551615
     97 MAX_SUBSTR_LEN_DISPLAY = 80
     98 MAX_SUBSTR_LEN_EXPAND = 1000
     99 
    100 
    101 def get_str_value(d, value, limit=0):
    102     # adapted from dumper.py::Dumper::putCharArrayValue()
    103     m_str = value["str"].pointer()
    104     m_len = value["len"].integer()
    105     if m_len == NPOS:
    106         _dbg("getstr... 1", m_len)
    107         m_str = "!!!!!<npos>!!!!!"
    108         m_len = len(m_str)
    109         return m_str, m_len
    110     if limit == 0:
    111         limit = d.displayStringLimit
    112     elided, shown = d.computeLimit(m_len, limit)
    113     mem = bytes(d.readRawMemory(m_str, shown))
    114     mem = mem.decode('utf8')
    115     return mem, m_len
    116 
    117 
    118 def __display_csubstr(d, value, limit=0):
    119     m_str, m_len = get_str_value(d, value)
    120     safe_len = min(m_len, MAX_SUBSTR_LEN_DISPLAY)
    121     disp = m_str[0:safe_len]
    122     # ensure the string escapes characters like \n\r\t etc
    123     disp = disp.encode('unicode_escape').decode('utf8')
    124     # WATCHOUT. quotes in the string will make qtcreator hang!!!
    125     disp = disp.replace('"', '\\"')
    126     disp = disp.replace('\'', '\\')
    127     if m_len <= MAX_SUBSTR_LEN_DISPLAY:
    128         d.putValue(f"[{m_len}] '{disp}'")
    129     else:
    130         d.putValue(f"[{m_len}] '{disp}'...")
    131     return m_str, m_len
    132 
    133 
    134 def qdump__c4__csubstr(d, value):
    135     m_str, m_len = __display_csubstr(d, value)
    136     d.putExpandable()
    137     if d.isExpanded():
    138         with Children(d):
    139             safe_len = min(m_len, MAX_SUBSTR_LEN_EXPAND)
    140             for i in range(safe_len):
    141                 ct = d.createType('char')
    142                 d.putSubItem(safe_len, d.createValue(value["str"].pointer() + i, ct))
    143             d.putSubItem("len", value["len"])
    144             d.putPtrItem("str", value["str"].pointer())
    145 
    146 
    147 def qdump__c4__substr(d, value):
    148     qdump__c4__csubstr(d, value)
    149 
    150 
    151 def qdump__c4__basic_substring(d, value):
    152     qdump__c4__csubstr(d, value)
    153 
    154 
    155 def qdump__c4__yml__NodeScalar(d, value):
    156     alen = value["anchor"]["len"].integer()
    157     tlen = value["tag"   ]["len"].integer()
    158     m_str, m_len = get_str_value(d, value["scalar"])
    159     if alen == 0 and tlen == 0:
    160         d.putValue(f'\'{m_str}\'')
    161     elif alen == 0 and tlen > 0:
    162         d.putValue(f'\'{m_str}\' [Ta]')
    163     elif alen > 0 and tlen == 0:
    164         d.putValue(f'\'{m_str}\' [tA]')
    165     elif alen > 0 and tlen > 0:
    166         d.putValue(f'\'{m_str}\' [TA]')
    167     d.putExpandable()
    168     if d.isExpanded():
    169         with Children(d):
    170             d.putSubItem("[scalar]", value["scalar"])
    171             if tlen > 0:
    172                 d.putSubItem("[tag]", value["tag"])
    173             if alen > 0:
    174                 d.putSubItem("[anchor or ref]", value["anchor"])
    175 
    176 
    177 def _format_enum_value(int_value, enum_map):
    178     str_value = enum_map.get(int_value, None)
    179     display = f'{int_value}' if str_value is None else f'{str_value} ({int_value})'
    180     return display
    181 
    182 
    183 def _format_bitmask_value(int_value, enum_map):
    184     str_value = enum_map.get(int_value, None)
    185     if str_value:
    186         return f'{str_value} ({int_value})'
    187     else:
    188         out = ""
    189         orig = int_value
    190         # do in reverse to get compound flags first
    191         for k, v in reversed(enum_map.items()):
    192             if (k != 0):
    193                 if (int_value & k) == k:
    194                     if len(out) > 0:
    195                         out += '|'
    196                     out += v
    197                     int_value &= ~k
    198             else:
    199                 if len(out) == 0 and int_value == 0:
    200                     return v
    201         if out == "":
    202             return f'{int_value}'
    203         return f"{out} ({orig})"
    204 
    205 
    206 def _c4bit(*ints):
    207     ret = 0
    208     for i in ints:
    209         ret |= 1 << i
    210     return ret
    211 
    212 
    213 node_types = {
    214     0: "NOTYPE",
    215     _c4bit(0): "VAL"     ,
    216     _c4bit(1): "KEY"     ,
    217     _c4bit(2): "MAP"     ,
    218     _c4bit(3): "SEQ"     ,
    219     _c4bit(4): "DOC"     ,
    220     _c4bit(5,3): "STREAM",
    221     _c4bit(6): "KEYREF"  ,
    222     _c4bit(7): "VALREF"  ,
    223     _c4bit(8): "KEYANCH" ,
    224     _c4bit(9): "VALANCH" ,
    225     _c4bit(10): "KEYTAG" ,
    226     _c4bit(11): "VALTAG" ,
    227     _c4bit(12): "VALQUO" ,
    228     _c4bit(13): "KEYQUO" ,
    229     _c4bit(1,0): "KEYVAL",
    230     _c4bit(1,3): "KEYSEQ",
    231     _c4bit(1,2): "KEYMAP",
    232     _c4bit(4,2): "DOCMAP",
    233     _c4bit(4,3): "DOCSEQ",
    234     _c4bit(4,0): "DOCVAL",
    235     #
    236     _c4bit(14): "STYLE_FLOW_SL",
    237     _c4bit(15): "STYLE_FLOW_ML",
    238     _c4bit(16): "STYLE_BLOCK",
    239     #
    240     _c4bit(17): "KEY_LITERAL",
    241     _c4bit(18): "VAL_LITERAL",
    242     _c4bit(19): "KEY_FOLDED",
    243     _c4bit(20): "VAL_FOLDED",
    244     _c4bit(21): "KEY_SQUO",
    245     _c4bit(22): "VAL_SQUO",
    246     _c4bit(23): "KEY_DQUO",
    247     _c4bit(24): "VAL_DQUO",
    248     _c4bit(25): "KEY_PLAIN",
    249     _c4bit(26): "VAL_PLAIN",
    250 }
    251 node_types_rev = {v: k for k, v in node_types.items()}
    252 
    253 
    254 def _node_type_has_all(node_type_value, type_name):
    255     exp = node_types_rev[type_name]
    256     return (node_type_value & exp) == exp
    257 
    258 
    259 def _node_type_has_any(node_type_value, type_name):
    260     exp = node_types_rev[type_name]
    261     return (node_type_value & exp) != 0
    262 
    263 
    264 def qdump__c4__yml__NodeType_e(d, value):
    265     v = _format_bitmask_value(value.integer(), node_types)
    266     d.putValue(v)
    267 
    268 
    269 def qdump__c4__yml__NodeType(d, value):
    270     qdump__c4__yml__NodeType_e(d, value["type"])
    271 
    272 
    273 def qdump__c4__yml__NodeData(d, value):
    274     d.putValue("wtf")
    275     ty = _format_bitmask_value(value.integer(), node_types)
    276     t = value["m_type"]["type"].integer()
    277     k = value["m_key"]["scalar"]
    278     v = value["m_val"]["scalar"]
    279     sk, lk = get_str_value(d, k)
    280     sv, lv = get_str_value(d, v)
    281     if _node_type_has_all(t, "KEYVAL"):
    282         d.putValue(f"'{sk}': '{sv}'    {ty}")
    283     elif _node_type_has_any(t, "KEY"):
    284         d.putValue(f"'{sk}':    {ty}")
    285     elif _node_type_has_any(t, "VAL"):
    286         d.putValue(f"'{sv}'    {ty}")
    287     else:
    288         d.putValue(f"{ty}")
    289     d.putExpandable()
    290     if d.isExpanded():
    291         with Children(d):
    292             d.putSubItem("m_type", value["m_type"])
    293             # key
    294             if _node_type_has_any(t, "KEY"):
    295                 d.putSubItem("m_key", value["m_key"])
    296             if _node_type_has_any(t, "KEYREF"):
    297                 with SubItem(d, "m_key.ref"):
    298                     s_, _ = get_str_value(d, value["m_key"]["anchor"])
    299                     d.putValue(f"'{s_}'")
    300             if _node_type_has_any(t, "KEYANCH"):
    301                 with SubItem(d, "m_key.anchor"):
    302                     s_, _ = get_str_value(d, value["m_key"]["anchor"])
    303                     d.putValue(f"'{s_}'")
    304             if _node_type_has_any(t, "KEYTAG"):
    305                 with SubItem(d, "m_key.tag"):
    306                     s_, _ = get_str_value(d, value["m_key"]["tag"])
    307                     d.putValue(f"'{s_}'")
    308             # val
    309             if _node_type_has_any(t, "VAL"):
    310                 d.putSubItem("m_val", value["m_val"])
    311             if _node_type_has_any(t, "VALREF"):
    312                 with SubItem(d, "m_val.ref"):
    313                     s_, _ = get_str_value(d, value["m_val"]["anchor"])
    314                     d.putValue(f"'{s_}'")
    315             if _node_type_has_any(t, "VALANCH"):
    316                 with SubItem(d, "m_val.anchor"):
    317                     s_, _ = get_str_value(d, value["m_val"]["anchor"])
    318                     d.putValue(f"'{s_}'")
    319             if _node_type_has_any(t, "VALTAG"):
    320                 with SubItem(d, "m_val.tag"):
    321                     s_, _ = get_str_value(d, value["m_val"]["tag"])
    322                     d.putValue(f"'{s_}'")
    323             # hierarchy
    324             _dump_node_index(d, "m_parent", value)
    325             _dump_node_index(d, "m_first_child", value)
    326             _dump_node_index(d, "m_last_child", value)
    327             _dump_node_index(d, "m_next_sibling", value)
    328             _dump_node_index(d, "m_prev_sibling", value)
    329 
    330 
    331 def _dump_node_index(d, name, value):
    332     if int(value[name].integer()) == NPOS:
    333         pass
    334         #with SubItem(d, name):
    335         #    d.putValue("-")
    336     else:
    337         d.putSubItem(name, value[name])
    338 
    339 
    340 # c4::yml::Tree
    341 def qdump__c4__yml__Tree(d, value):
    342     m_size = value["m_size"].integer()
    343     m_cap = value["m_cap"].integer()
    344     d.putExpandable()
    345     if d.isExpanded():
    346         #d.putArrayData(value["m_buf"], m_size, value["m_buf"].dereference())
    347         with Children(d):
    348             with SubItem(d, f"[nodes]"):
    349                 d.putItemCount(m_size)
    350                 d.putArrayData(value["m_buf"].pointer(), m_size, value["m_buf"].type.dereference())
    351             d.putPtrItem("m_buf", value["m_buf"].pointer())
    352             d.putIntItem("m_size", value["m_size"])
    353             d.putIntItem("m_cap (capacity)", value["m_cap"])
    354             d.putIntItem("[slack]", m_cap - m_size)
    355             d.putIntItem("m_free_head", value["m_free_head"])
    356             d.putIntItem("m_free_tail", value["m_free_tail"])
    357             d.putSubItem("m_arena", value["m_arena"])
    358 
    359 
    360 def qdump__c4__yml__detail__stack(d, value):
    361     T = value.type[0]
    362     N = value.type[0]
    363     m_size = value["m_size"].integer()
    364     m_capacity = value["m_capacity"].integer()
    365     d.putItemCount(m_size)
    366     if d.isExpanded():
    367         with Children(d):
    368             with SubItem(d, f"[nodes]"):
    369                 d.putItemCount(m_size)
    370                 d.putArrayData(value["m_stack"].pointer(), m_size, T)
    371             d.putIntItem("m_size", value["m_size"])
    372             d.putIntItem("m_capacity", value["m_capacity"])
    373             #d.putIntItem("[small capacity]", N)
    374             d.putIntItem("[is large]", value["m_buf"].address() == value["m_stack"].pointer())
    375             d.putPtrItem("m_stack", value["m_stack"].pointer())
    376             d.putPtrItem("m_buf", value["m_buf"].address())
    377 
    378 
    379 def qdump__c4__yml__detail__ReferenceResolver__refdata(d, value):
    380     node = value["node"].integer()
    381     ty = _format_bitmask_value(value["type"].integer(), node_types)
    382     d.putValue(f'{node}   {ty}')
    383     d.putExpandable()
    384     if d.isExpanded():
    385         with Children(d):
    386             d.putSubItem("type", value["type"])
    387             d.putSubItem("node", value["node"])
    388             _dump_node_index(d, "prev_anchor", value)
    389             _dump_node_index(d, "target", value)
    390             _dump_node_index(d, "parent_ref", value)
    391             _dump_node_index(d, "parent_ref_sibling", value)