1# DExTer : Debugging Experience Tester
2# ~~~~~~   ~         ~~         ~   ~~
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7
8from collections import namedtuple
9from ctypes import *
10from functools import partial
11
12from .utils import *
13
14Symbol = namedtuple("Symbol", ["num", "name", "type", "value"])
15
16class IDebugSymbolGroup2(Structure):
17  pass
18
19class IDebugSymbolGroup2Vtbl(Structure):
20  wrp = partial(WINFUNCTYPE, c_long, POINTER(IDebugSymbolGroup2))
21  ids_getnumbersymbols = wrp(c_ulong_p)
22  ids_getsymbolname = wrp(c_ulong, c_char_p, c_ulong, c_ulong_p)
23  ids_getsymboltypename = wrp(c_ulong, c_char_p, c_ulong, c_ulong_p)
24  ids_getsymbolvaluetext = wrp(c_ulong, c_char_p, c_ulong, c_ulong_p)
25  _fields_ = [
26      ("QueryInterface", c_void_p),
27      ("AddRef", c_void_p),
28      ("Release", c_void_p),
29      ("GetNumberSymbols", ids_getnumbersymbols),
30      ("AddSymbol", c_void_p),
31      ("RemoveSymbolByName", c_void_p),
32      ("RemoveSymbolByIndex", c_void_p),
33      ("GetSymbolName", ids_getsymbolname),
34      ("GetSymbolParameters", c_void_p),
35      ("ExpandSymbol", c_void_p),
36      ("OutputSymbols", c_void_p),
37      ("WriteSymbol", c_void_p),
38      ("OutputAsType", c_void_p),
39      ("AddSymbolWide", c_void_p),
40      ("RemoveSymbolByNameWide", c_void_p),
41      ("GetSymbolNameWide", c_void_p),
42      ("WritesymbolWide", c_void_p),
43      ("OutputAsTypeWide", c_void_p),
44      ("GetSymbolTypeName", ids_getsymboltypename),
45      ("GetSymbolTypeNameWide", c_void_p),
46      ("GetSymbolSize", c_void_p),
47      ("GetSymbolOffset", c_void_p),
48      ("GetSymbolRegister", c_void_p),
49      ("GetSymbolValueText", ids_getsymbolvaluetext),
50      ("GetSymbolValueTextWide", c_void_p),
51      ("GetSymbolEntryInformation", c_void_p)
52    ]
53
54IDebugSymbolGroup2._fields_ = [("lpVtbl", POINTER(IDebugSymbolGroup2Vtbl))]
55
56class SymbolGroup(object):
57  def __init__(self, symgroup):
58    self.symgroup = symgroup.contents
59    self.vt = self.symgroup.lpVtbl.contents
60    self.ulong = c_ulong()
61
62  def GetNumberSymbols(self):
63    res = self.vt.GetNumberSymbols(self.symgroup, byref(self.ulong))
64    aborter(res, "GetNumberSymbols")
65    return self.ulong.value
66
67  def GetSymbolName(self, idx):
68    buf = create_string_buffer(256)
69    res = self.vt.GetSymbolName(self.symgroup, idx, buf, 255, byref(self.ulong))
70    aborter(res, "GetSymbolName")
71    thelen = self.ulong.value
72    return string_at(buf).decode("ascii")
73
74  def GetSymbolTypeName(self, idx):
75    buf = create_string_buffer(256)
76    res = self.vt.GetSymbolTypeName(self.symgroup, idx, buf, 255, byref(self.ulong))
77    aborter(res, "GetSymbolTypeName")
78    thelen = self.ulong.value
79    return string_at(buf).decode("ascii")
80
81  def GetSymbolValueText(self, idx, handleserror=False):
82    buf = create_string_buffer(256)
83    res = self.vt.GetSymbolValueText(self.symgroup, idx, buf, 255, byref(self.ulong))
84    if res != 0 and handleserror:
85      return None
86    aborter(res, "GetSymbolTypeName")
87    thelen = self.ulong.value
88    return string_at(buf).decode("ascii")
89
90  def get_symbol(self, idx):
91    name = self.GetSymbolName(idx)
92    thetype = self.GetSymbolTypeName(idx)
93    value = self.GetSymbolValueText(idx)
94    return Symbol(idx, name, thetype, value)
95
96  def get_all_symbols(self):
97    num_syms = self.GetNumberSymbols()
98    return list(map(self.get_symbol, list(range(num_syms))))
99