diff --git a/node.gyp b/node.gyp index 1c3e29147140e7..84081b97ab4e65 100644 --- a/node.gyp +++ b/node.gyp @@ -172,6 +172,7 @@ 'dependencies': [ 'node_js2c#host', + 'node_postmortem_metadata#host', 'deps/nghttp2/nghttp2.gyp:nghttp2' ], @@ -295,6 +296,7 @@ # node.gyp is added to the project by default. 'common.gypi', '<(SHARED_INTERMEDIATE_DIR)/node_javascript.cc', + '<(SHARED_INTERMEDIATE_DIR)/node-debug-support.cc', ], 'defines': [ @@ -743,7 +745,29 @@ 'ldflags': [ '-I<(SHARED_INTERMEDIATE_DIR)' ] }], ] - } + }, + { + 'target_name': 'node_postmortem_metadata', + 'type': 'none', + 'toolsets': ['host'], + 'actions': [ + { + 'action_name': 'gen-postmortem-metadata', + 'process_outputs_as_sources': 1, + 'inputs': [ + './tools/gen-postmortem-metadata.py', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/node-debug-support.cc', + ], + 'action': [ + 'python', + './tools/gen-postmortem-metadata.py', + '<@(_outputs)', + ] + } + ] + }, ], # end targets 'conditions': [ diff --git a/tools/gen-postmortem-metadata.py b/tools/gen-postmortem-metadata.py new file mode 100644 index 00000000000000..ed8ee04fd3614e --- /dev/null +++ b/tools/gen-postmortem-metadata.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python + +# +# gen-postmortem-metadata.py output_file.cc +# +# Creates debugging symbols to help naviage Node's internals using post-mortem +# debugging tools. +# + +import sys + + +class DebugSymbol(object): + type_ = 'int' + _prefix = 'nodedbg_' + + def __init__(self, name, value, headers=[], type_=None): + self.name = name + self.value = value + self.headers = headers + self.type_ = type_ or DebugSymbol.type_ + + @classmethod + def get_headers(cls, debug_symbols): + ''' + Return a list of headers without duplicates, preserving the order they were + declared + ''' + seen = set() + headers = [debug_symbol.headers for debug_symbol in debug_symbols] + headers = sum(headers, []) + + result = [] + for h in headers: + if not h in seen: + seen.add(h) + result.append(h) + + return result + + def __str__(self): + return '{type} {prefix}{name} = {value};'.format( + type=self.type_, + prefix=self._prefix, + name=self.name, + value=self.value, + ) + + +debug_symbols = [ + DebugSymbol( + name='environment_context_idx_embedder_data', + value='Environment::kContextEmbedderDataIndex', + headers=['env.h'], + type_='int', + ), + DebugSymbol( + name='class__BaseObject__persistent_handle', + value='offsetof(BaseObject, persistent_handle_)', + headers=['base-object.h', 'base-object-inl.h'], + type_='size_t', + ), + DebugSymbol( + name='class__Environment__handleWrapQueue', + value='offsetof(Environment, handle_wrap_queue_)', + headers=['env.h'], + type_='size_t', + ), + DebugSymbol( + name='class__HandleWrap__node', + value='offsetof(HandleWrap, handle_wrap_queue_)', + headers=['handle_wrap.h'], + type_='size_t', + ), + DebugSymbol( + name='class__HandleWrapQueue__headOffset', + value='offsetof(Environment::HandleWrapQueue, head_)', + headers=['env.h'], + type_='size_t', + ), + DebugSymbol( + name='class__HandleWrapQueue__nextOffset', + value='offsetof(ListNode, next_)', + headers=['handle_wrap.h', 'util.h'], + type_='size_t', + ), + DebugSymbol( + name='class__Environment__reqWrapQueue', + value='offsetof(Environment, req_wrap_queue_)', + headers=['env.h'], + type_='size_t', + ), + DebugSymbol( + name='class__ReqWrap__node', + value='offsetof(ReqWrap, req_wrap_queue_)', + headers=['req-wrap.h'], + type_='size_t', + ), + DebugSymbol( + name='class__ReqWrapQueue__headOffset', + value='offsetof(Environment::ReqWrapQueue, head_)', + headers=['env.h'], + type_='size_t', + ), + DebugSymbol( + name='class__ReqWrapQueue__nextOffset', + value='offsetof(ListNode>, next_)', + headers=['req-wrap.h', 'util.h'], + type_='size_t', + ), +] + + +template = ''' +/* + * This file is generated by {filename}. Do not edit directly. + */ + +#define _ALLOW_KEYWORD_MACROS 1 +#define private public +#define protected public + +{includes} + +using namespace node; + +extern "C" {{ +{symbols} +}} + +#undef private +#undef protected +#undef _ALLOW_KEYWORD_MACROS +''' + + +def create_symbols_file(): + out = file(sys.argv[1], 'w') + headers = DebugSymbol.get_headers(debug_symbols) + includes = ['#include "{0}"'.format(header) for header in headers] + includes = '\n'.join(includes) + + symbols = '\n'.join([str(symbol) for symbol in debug_symbols]) + + out.write(template.format( + filename=sys.argv[0], + includes=includes, + symbols=symbols, + )) + + +if len(sys.argv) < 2: + print('usage: {0} output.cc'.format(sys.argv[0])) + sys.exit(2) + + +create_symbols_file()