Skip to content

Commit 04811c3

Browse files
Starting files for testing
1 parent 3a8c02f commit 04811c3

File tree

6 files changed

+642
-0
lines changed

6 files changed

+642
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin/*
2+
!bin/nim*.py

.vscode/launch.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Debug Nim Project",
9+
"type": "gdb",
10+
"request": "launch",
11+
"target": "main",
12+
"cwd": "${workspaceRoot}",
13+
"valuesFormatting": "parseText"
14+
}
15+
]
16+
}

.vscode/tasks.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// See https://go.microsoft.com/fwlink/?LinkId=733558
3+
// for the documentation about the tasks.json format
4+
"version": "2.0.0",
5+
"tasks": [
6+
{
7+
"label": "Build Nim Project",
8+
"type": "shell",
9+
"command": "nim c -d:debug --debugger:native main.nim",
10+
"group": {
11+
"kind": "build",
12+
"isDefault": true
13+
}
14+
}
15+
]
16+
}

bin/nim.py

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
2+
import gdb
3+
import re
4+
5+
#################################################################################################
6+
##### Type pretty printers
7+
#################################################################################################
8+
9+
class NimTypePrinter(gdb.types.TypePrinter):
10+
"Nim type printer, one printer for all Nim types"
11+
12+
type_hash_regex = re.compile("^(.+?)_([A-Za-z0-9]+)$")
13+
14+
type_map_static = {
15+
'NI': 'int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', 'NI64': 'in64',
16+
'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', 'NU64': 'uint64',
17+
'NF': 'float', 'NF32': 'float32', 'NF32': 'float64',
18+
'NIM_BOOL': 'bool', 'NIM_CHAR': 'char', 'NCSTRING': 'cstring',
19+
'NimStringDesc': 'string'
20+
}
21+
22+
def __init__ (self):
23+
super (NimTypePrinter, self).__init__ ("NimTypePrinter")
24+
25+
@staticmethod
26+
def rti(type_name):
27+
"Get static const TNimType variable, should be available for every non trivial Nim type"
28+
29+
m = NimTypePrinter.type_hash_regex.match(type_name)
30+
if m is not None:
31+
try:
32+
return gdb.parse_and_eval("NTI_" + m.group(2) + "_")
33+
except:
34+
return None
35+
36+
def instantiate(self):
37+
return self._recognizer()
38+
39+
class _recognizer(object):
40+
41+
def recognize(self, type_obj):
42+
43+
tname = ""
44+
if type_obj.tag is not None:
45+
tname = type_obj.tag
46+
elif type_obj.name is not None:
47+
tname = type_obj.name
48+
else:
49+
return None
50+
51+
result = NimTypePrinter.type_map_static.get(tname, None)
52+
if result is not None:
53+
return result
54+
55+
rti = NimTypePrinter.rti(tname)
56+
if rti is not None:
57+
return str(rti['name'])
58+
59+
return None
60+
61+
nimobjfile = gdb.current_objfile() or gdb.objfiles()[0]
62+
nimobjfile.type_printers = []
63+
nimobjfile.type_printers = [NimTypePrinter()]
64+
65+
66+
#################################################################################################
67+
##### GDB Function, equivalent of Nim's $ operator
68+
#################################################################################################
69+
70+
class DollarPrintFunction (gdb.Function):
71+
"Nim's equivalent of $ operator as a gdb function, available in expressions `print $dollar(myvalue)"
72+
73+
_gdb_dollar_functions = gdb.execute("info functions dollar__", True, True)
74+
dollar_functions = re.findall('NimStringDesc \*(dollar__[A-z0-9_]+?)\(([^,)]*)\);', _gdb_dollar_functions)
75+
76+
def __init__ (self):
77+
super (DollarPrintFunction, self).__init__("dollar")
78+
79+
@staticmethod
80+
def invoke_static(arg):
81+
82+
for func, arg_typ in DollarPrintFunction.dollar_functions:
83+
84+
if arg.type.name == arg_typ:
85+
func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value()
86+
return func_value(arg)
87+
88+
if arg.type.name + " *" == arg_typ:
89+
func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value()
90+
return func_value(arg.address)
91+
92+
raise ValueError("No suitable Nim $ operator found for type: " + arg.type.name)
93+
94+
def invoke(self, arg):
95+
return self.invoke_static(arg)
96+
97+
DollarPrintFunction()
98+
99+
100+
#################################################################################################
101+
##### GDB Command, equivalent of Nim's $ operator
102+
#################################################################################################
103+
104+
class DollarPrintCmd (gdb.Command):
105+
"""Dollar print command for Nim, `$ expr` will invoke Nim's $ operator"""
106+
107+
def __init__ (self):
108+
super (DollarPrintCmd, self).__init__ ("$", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION)
109+
110+
def invoke (self, arg, from_tty):
111+
param = gdb.parse_and_eval(arg)
112+
gdb.write(str(DollarPrintFunction.invoke_static(param)) + "\n", gdb.STDOUT)
113+
114+
DollarPrintCmd()
115+
116+
117+
#################################################################################################
118+
##### Value pretty printers
119+
#################################################################################################
120+
121+
class NimBoolPrinter:
122+
123+
pattern = re.compile(r'^NIM_BOOL$')
124+
125+
def __init__(self, val):
126+
self.val = val
127+
128+
def display_hint(self):
129+
return 'bool'
130+
131+
def to_string(self):
132+
if self.val == 0:
133+
return "false"
134+
else:
135+
return "true"
136+
137+
################################################################
138+
139+
class NimStringPrinter:
140+
141+
pattern = re.compile(r'^NimStringDesc \*$')
142+
143+
def __init__(self, val):
144+
self.val = val
145+
146+
def display_hint(self):
147+
return 'string'
148+
149+
def to_string(self):
150+
if self.val:
151+
l = int(self.val['Sup']['len'])
152+
return self.val['data'][0].address.string("utf-8", "ignore", l)
153+
else:
154+
return "<nil>"
155+
156+
157+
################################################################
158+
159+
class NimEnumPrinter:
160+
161+
pattern = re.compile(r'^tyEnum_(.+?)_([A-Za-z0-9]+)$')
162+
163+
reprEnum = gdb.lookup_global_symbol("reprEnum", gdb.SYMBOL_FUNCTIONS_DOMAIN).value()
164+
165+
def __init__(self, val):
166+
self.val = val
167+
if self.reprEnum is None:
168+
raise ValueError("reprEnum function symbol is not found, can't display Nim enum. reprEnum was likely removed by dead code elimination")
169+
170+
def display_hint(self):
171+
return 'enum'
172+
173+
def to_string(self):
174+
try:
175+
m = self.pattern.match(str(self.val.type))
176+
nti = gdb.parse_and_eval("NTI_" + m.group(2) + "_").address
177+
return self.reprEnum(self.val, nti)
178+
except Exception as e:
179+
gdb.write("reprEnum exception: " + str(e) + "\n", gdb.STDERR)
180+
181+
182+
################################################################
183+
184+
class NimSetPrinter:
185+
186+
pattern = re.compile(r'^tySet_(.+?)_([A-Za-z0-9]+)$')
187+
188+
def __init__(self, val):
189+
self.val = val
190+
191+
def to_string(self):
192+
try:
193+
return DollarPrintFunction.invoke_static(self.val)
194+
except:
195+
gdb.write("RTI information not found for set, likely removed by dead code elimination: " + str(self.val.type) + "\n", gdb.STDERR)
196+
197+
198+
################################################################
199+
200+
class NimSeqPrinter:
201+
202+
pattern = re.compile(r'^tySequence_.*$')
203+
204+
def __init__(self, val):
205+
self.val = val
206+
207+
def display_hint(self):
208+
return 'array'
209+
210+
def to_string(self):
211+
return 'seq'
212+
213+
def children(self):
214+
if not self.val:
215+
yield ("seq", "<nil>")
216+
raise StopIteration
217+
218+
len = int(self.val['Sup']['len'])
219+
for i in range(len):
220+
yield ('[{0}]'.format(i), self.val["data"][i])
221+
222+
################################################################
223+
224+
class NimObjectPrinter:
225+
226+
pattern = re.compile(r'^tyObject_.*$')
227+
228+
def __init__(self, val):
229+
self.val = val
230+
231+
def display_hint(self):
232+
return 'object'
233+
234+
def to_string(self):
235+
return str(self.val.type)
236+
237+
def children(self):
238+
if not self.val:
239+
yield "object", "<nil>"
240+
raise StopIteration
241+
242+
for (i, field) in enumerate(self.val.type.fields()):
243+
if field.type.code == gdb.TYPE_CODE_UNION:
244+
yield _union_field
245+
else:
246+
yield (field.name, self.val[field])
247+
248+
def _union_field(self, i, field):
249+
rti = NimTypePrinter.rti(self.val.type.name)
250+
if rti is None:
251+
return (field.name, "UNION field can't be displayed without RTI")
252+
253+
node_sons = rti['node'].dereference()['sons']
254+
prev_field = self.val.type.fields()[i - 1]
255+
256+
descriminant_node = None
257+
for i in range(int(node['len'])):
258+
son = node_sons[i].dereference()
259+
if son['name'].string("utf-8", "ignore") == str(prev_field.name):
260+
descriminant_node = son
261+
break
262+
if descriminant_node is None:
263+
raise ValueError("Can't find union descriminant field in object RTI")
264+
265+
if descriminant_node is None: raise ValueError("Can't find union field in object RTI")
266+
union_node = descriminant_node['sons'][int(self.val[prev_field])].dereference()
267+
union_val = self.val[field]
268+
269+
for f1 in union_val.type.fields():
270+
for f2 in union_val[f1].type.fields():
271+
if str(f2.name) == union_node['name'].string("utf-8", "ignore"):
272+
return (str(f2.name), union_val[f1][f2])
273+
274+
raise ValueError("RTI is absent or incomplete, can't find union definition in RTI")
275+
276+
277+
################################################################
278+
279+
def makematcher(klass):
280+
def matcher(val):
281+
try:
282+
if klass.pattern.match(str(val.type)):
283+
return klass(val)
284+
except Exception, e:
285+
print("Nim matcher exception: ", str(e))
286+
return matcher
287+
288+
nimobjfile.pretty_printers = []
289+
nimobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')])
290+

0 commit comments

Comments
 (0)