Skip to content

Commit 96da1a4

Browse files
committed
Initial code commit
1 parent f7156ca commit 96da1a4

File tree

9 files changed

+1255
-0
lines changed

9 files changed

+1255
-0
lines changed

Diff for: .gitignore

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Created by .ignore support plugin (hsz.mobi)
2+
### Python template
3+
# Byte-compiled / optimized / DLL files
4+
__pycache__/
5+
*.py[cod]
6+
*$py.class
7+
8+
# C extensions
9+
*.so
10+
11+
# Distribution / packaging
12+
.Python
13+
build/
14+
develop-eggs/
15+
dist/
16+
downloads/
17+
eggs/
18+
.eggs/
19+
lib/
20+
lib64/
21+
parts/
22+
sdist/
23+
var/
24+
wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
.hypothesis/
50+
.pytest_cache/
51+
52+
# Translations
53+
*.mo
54+
*.pot
55+
56+
# Django stuff:
57+
*.log
58+
local_settings.py
59+
db.sqlite3
60+
61+
# Flask stuff:
62+
instance/
63+
.webassets-cache
64+
65+
# Scrapy stuff:
66+
.scrapy
67+
68+
# Sphinx documentation
69+
docs/_build/
70+
71+
# PyBuilder
72+
target/
73+
74+
# Jupyter Notebook
75+
.ipynb_checkpoints
76+
77+
# pyenv
78+
.python-version
79+
80+
# celery beat schedule file
81+
celerybeat-schedule
82+
83+
# SageMath parsed files
84+
*.sage.py
85+
86+
# Environments
87+
.env
88+
.venv
89+
env/
90+
venv/
91+
ENV/
92+
env.bak/
93+
venv.bak/
94+
95+
# Spyder project settings
96+
.spyderproject
97+
.spyproject
98+
99+
# Rope project settings
100+
.ropeproject
101+
102+
# mkdocs documentation
103+
/site
104+
105+
# mypy
106+
.mypy_cache/
107+
108+
.idea

Diff for: src/gdb_api.py

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import os
2+
import sys
3+
from typing import Tuple
4+
5+
import gdb
6+
import gdb.printing
7+
import gdb.types
8+
from gdb.printing import PrettyPrinter
9+
10+
import natvis
11+
import parser
12+
13+
14+
def format_type(type, force_name: str = None) -> Tuple[str, str]:
15+
if type.code == gdb.TYPE_CODE_PTR:
16+
target_pre, target_post = format_type(type.target())
17+
return target_pre + "*", target_post
18+
elif type.code == gdb.TYPE_CODE_ARRAY:
19+
base = type.target()
20+
size = int(type.sizeof / base.sizeof)
21+
22+
target_pre, target_post = format_type(type.target())
23+
24+
return target_pre, target_post + "[" + str(size) + "]"
25+
elif type.code == gdb.TYPE_CODE_STRUCT or type.code == gdb.TYPE_CODE_UNION:
26+
if type.code == gdb.TYPE_CODE_STRUCT:
27+
out = "struct"
28+
else:
29+
out = "union"
30+
31+
if force_name is not None:
32+
out += " " + force_name
33+
34+
out += " {\n"
35+
for f in type.fields():
36+
pre, post = format_type(f.type)
37+
out += "\n".join(" " + x for x in pre.splitlines())
38+
39+
out += (" " + f.name if f.name is not None else "") + post + ";\n"
40+
out += "}"
41+
42+
return out, ""
43+
elif type.code == gdb.TYPE_CODE_TYPEDEF:
44+
return format_type(type.target(), force_name)
45+
else:
46+
return type.name or "", ""
47+
48+
49+
def stringify_type(type, type_name: str = None):
50+
pre, post = format_type(type, type_name)
51+
52+
return pre + post + ";"
53+
54+
55+
class NatvisPrinter:
56+
def __init__(self, type: natvis.NatvisType, val):
57+
self.val = val
58+
self.type = type
59+
self.c_type = stringify_type(self.val.type, "val_type")
60+
61+
def check_condition(self, cond: str) -> bool:
62+
if cond is None:
63+
return True
64+
65+
return bool(self._get_value(cond))
66+
67+
def _get_value(self, expression):
68+
val = parser.evaluate_expression(self.val, self.c_type, expression)
69+
if val is not None:
70+
return val
71+
else:
72+
# Return the expression as a string in case the execution failed
73+
return "{" + expression + "}"
74+
75+
def children(self):
76+
for item in self.type.expand_items:
77+
if self.check_condition(item.condition):
78+
yield item.name, self._get_value(item.expression.base_expression)
79+
80+
def to_string(self):
81+
for string in self.type.display_parsers:
82+
if self.check_condition(string.condition):
83+
display_args = []
84+
for code in string.parser.code_parts:
85+
display_args.append(str(self._get_value(code.base_expression)))
86+
return string.parser.template_string.format(*display_args)
87+
88+
return "No visualizer available"
89+
90+
91+
class NatvisPrettyPrinter(PrettyPrinter):
92+
def __init__(self, name, subprinters=None):
93+
super().__init__(name, subprinters)
94+
self.manager = natvis.NatvisManager()
95+
96+
def __call__(self, val):
97+
type = gdb.types.get_basic_type(val.type)
98+
if not type:
99+
type = val.type
100+
if not type:
101+
return None
102+
if type.name is None:
103+
# We can't handle unnamed types
104+
return None
105+
106+
symbol = gdb.lookup_symbol(type.name)
107+
108+
if symbol is None:
109+
return None
110+
111+
symbtab = symbol[0].symtab
112+
113+
filename = symbtab.filename
114+
115+
natvis_type = self.manager.lookup_type(type.name, filename)
116+
117+
if natvis_type is None:
118+
return None
119+
120+
return NatvisPrinter(natvis_type, val)
121+
122+
123+
def add_natvis_printers():
124+
if os.environ.get("GDB_NATVIS_DEBUG") is not None:
125+
import pydevd as pydevd
126+
pydevd.settrace('localhost', port=41879, stdoutToServer=True, stderrToServer=True, suspend=False)
127+
128+
gdb.printing.register_pretty_printer(gdb.current_objfile(), NatvisPrettyPrinter("Natvis"))

Diff for: src/logger.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This exposes a function which writes to the GDB log if available and to stdout otherwise
2+
try:
3+
import gdb
4+
5+
6+
def log_message(msg: str):
7+
gdb.write(msg + "\n", gdb.STDLOG)
8+
except ImportError:
9+
def log_message(msg: str):
10+
print(msg)

0 commit comments

Comments
 (0)