Skip to content

Commit 0e10d91

Browse files
Matheus MarchiniMatheus Marchini
authored andcommitted
src, tools: add debug symbols for node internals
Before these changes, only V8 added debug symbols to Node's binary, limiting the possibilities for debugger's developers to add some features that rely on investigating Node's internal structures. These changes are a first steps towards empowering debug tools to navigate Node's internals strucutres. One example of what can be achieved with this is shown at nodejs/llnode#122 (a command which prints information about handles and requests on the queue for a core dump file). Node debug symbols are prefixed with node_dbg_. Ref: nodejs/llnode#122 Ref: nodejs/post-mortem#46
1 parent d9d46e7 commit 0e10d91

File tree

2 files changed

+182
-1
lines changed

2 files changed

+182
-1
lines changed

node.gyp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170

171171
'dependencies': [
172172
'node_js2c#host',
173+
'node_postmortem_metadata#host',
173174
'deps/nghttp2/nghttp2.gyp:nghttp2'
174175
],
175176

@@ -294,6 +295,7 @@
294295
# node.gyp is added to the project by default.
295296
'common.gypi',
296297
'<(SHARED_INTERMEDIATE_DIR)/node_javascript.cc',
298+
'<(SHARED_INTERMEDIATE_DIR)/node-debug-support.cc',
297299
],
298300

299301
'defines': [
@@ -742,7 +744,29 @@
742744
'ldflags': [ '-I<(SHARED_INTERMEDIATE_DIR)' ]
743745
}],
744746
]
745-
}
747+
},
748+
{
749+
'target_name': 'node_postmortem_metadata',
750+
'type': 'none',
751+
'toolsets': ['host'],
752+
'actions': [
753+
{
754+
'action_name': 'gen-postmortem-metadata',
755+
'process_outputs_as_sources': 1,
756+
'inputs': [
757+
'./tools/gen-postmortem-metadata.py',
758+
],
759+
'outputs': [
760+
'<(SHARED_INTERMEDIATE_DIR)/node-debug-support.cc',
761+
],
762+
'action': [
763+
'python',
764+
'./tools/gen-postmortem-metadata.py',
765+
'<@(_outputs)',
766+
]
767+
}
768+
]
769+
},
746770
], # end targets
747771

748772
'conditions': [

tools/gen-postmortem-metadata.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#!/usr/bin/env python
2+
3+
#
4+
# gen-postmortem-metadata.py output_file.cc
5+
#
6+
# Creates debugging symbols to help naviage Node's internals using post-mortem
7+
# debugging tools.
8+
#
9+
10+
import sys
11+
12+
13+
class DebugSymbol(object):
14+
type_ = 'int'
15+
_prefix = 'nodedbg_'
16+
17+
def __init__(self, name, value, headers=[], type_=None):
18+
self.name = name
19+
self.value = value
20+
self.headers = headers
21+
self.type_ = type_ or DebugSymbol.type_
22+
23+
@classmethod
24+
def get_headers(cls, debug_symbols):
25+
'''
26+
Return a list of headers without duplicates, preserving the order they were
27+
declared
28+
'''
29+
seen = set()
30+
headers = [debug_symbol.headers for debug_symbol in debug_symbols]
31+
headers = sum(headers, [])
32+
33+
result = []
34+
for h in headers:
35+
if not h in seen:
36+
seen.add(h)
37+
result.append(h)
38+
39+
return result
40+
41+
def __str__(self):
42+
return '{type} {prefix}{name} = {value};'.format(
43+
type=self.type_,
44+
prefix=self._prefix,
45+
name=self.name,
46+
value=self.value,
47+
)
48+
49+
50+
debug_symbols = [
51+
DebugSymbol(
52+
name='environment_context_idx_embedder_data',
53+
value='Environment::kContextEmbedderDataIndex',
54+
headers=['env.h'],
55+
type_='int',
56+
),
57+
DebugSymbol(
58+
name='class__BaseObject__persistent_handle',
59+
value='offsetof(BaseObject, persistent_handle_)',
60+
headers=['base-object.h', 'base-object-inl.h'],
61+
type_='size_t',
62+
),
63+
DebugSymbol(
64+
name='class__Environment__handleWrapQueue',
65+
value='offsetof(Environment, handle_wrap_queue_)',
66+
headers=['env.h'],
67+
type_='size_t',
68+
),
69+
DebugSymbol(
70+
name='class__HandleWrap__node',
71+
value='offsetof(HandleWrap, handle_wrap_queue_)',
72+
headers=['handle_wrap.h'],
73+
type_='size_t',
74+
),
75+
DebugSymbol(
76+
name='class__HandleWrapQueue__headOffset',
77+
value='offsetof(Environment::HandleWrapQueue, head_)',
78+
headers=['env.h'],
79+
type_='size_t',
80+
),
81+
DebugSymbol(
82+
name='class__HandleWrapQueue__nextOffset',
83+
value='offsetof(ListNode<HandleWrap>, next_)',
84+
headers=['handle_wrap.h', 'util.h'],
85+
type_='size_t',
86+
),
87+
DebugSymbol(
88+
name='class__Environment__reqWrapQueue',
89+
value='offsetof(Environment, req_wrap_queue_)',
90+
headers=['env.h'],
91+
type_='size_t',
92+
),
93+
DebugSymbol(
94+
name='class__ReqWrap__node',
95+
value='offsetof(ReqWrap<uv_req_t>, req_wrap_queue_)',
96+
headers=['req-wrap.h'],
97+
type_='size_t',
98+
),
99+
DebugSymbol(
100+
name='class__ReqWrapQueue__headOffset',
101+
value='offsetof(Environment::ReqWrapQueue, head_)',
102+
headers=['env.h'],
103+
type_='size_t',
104+
),
105+
DebugSymbol(
106+
name='class__ReqWrapQueue__nextOffset',
107+
value='offsetof(ListNode<ReqWrap<uv_req_t>>, next_)',
108+
headers=['req-wrap.h', 'util.h'],
109+
type_='size_t',
110+
),
111+
]
112+
113+
114+
template = '''
115+
/*
116+
* This file is generated by {filename}. Do not edit directly.
117+
*/
118+
119+
#define _ALLOW_KEYWORD_MACROS 1
120+
#define private public
121+
#define protected public
122+
123+
{includes}
124+
125+
using namespace node;
126+
127+
extern "C" {{
128+
{symbols}
129+
}}
130+
131+
#undef private
132+
#undef protected
133+
#undef _ALLOW_KEYWORD_MACROS
134+
'''
135+
136+
137+
def create_symbols_file():
138+
out = file(sys.argv[1], 'w')
139+
headers = DebugSymbol.get_headers(debug_symbols)
140+
includes = ['#include "{0}"'.format(header) for header in headers]
141+
includes = '\n'.join(includes)
142+
143+
symbols = '\n'.join([str(symbol) for symbol in debug_symbols])
144+
145+
out.write(template.format(
146+
filename=sys.argv[0],
147+
includes=includes,
148+
symbols=symbols,
149+
))
150+
151+
152+
if len(sys.argv) < 2:
153+
print('usage: {0} output.cc'.format(sys.argv[0]))
154+
sys.exit(2)
155+
156+
157+
create_symbols_file()

0 commit comments

Comments
 (0)