diff options
author | Richard Samuels <richard.l.samuels@gmail.com> | 2020-08-18 09:26:49 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-08-21 19:36:09 +0000 |
commit | 217ce7d8b20dae3c24e36029a880a6f9fa954a05 (patch) | |
tree | e06ad6da5236d707d0f26bb484c176483afec6fa /buildscripts | |
parent | de3f9cdede48b8c04683ccfc3f1913f38cc29e52 (diff) | |
download | mongo-217ce7d8b20dae3c24e36029a880a6f9fa954a05.tar.gz |
SERVER-50354 Fix mongodb-javascript-stack gdb command to allow printing stacktraces
Diffstat (limited to 'buildscripts')
-rw-r--r-- | buildscripts/gdb/mongo.py | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/buildscripts/gdb/mongo.py b/buildscripts/gdb/mongo.py index 30fa6961a79..2a48fa9091c 100644 --- a/buildscripts/gdb/mongo.py +++ b/buildscripts/gdb/mongo.py @@ -655,6 +655,14 @@ MongoDBUniqueStack() class MongoDBJavaScriptStack(gdb.Command): """Print the JavaScript stack from a MongoDB process.""" + # Looking to test your changes to this? Really easy! + # 1. install-core to build the mongo shell binary (mongo) + # 2. launch it: ./path/to/bin/mongo --nodb + # 3. in the shell, run: sleep(99999999999). (do not use --eval) + # 4. ps ax | grep nodb to find the PID + # 5. gdb -p <PID>. + # 6. Run this command, mongodb-javascript-stack + def __init__(self): """Initialize MongoDBJavaScriptStack.""" RegisterMongoCommand.register(self, "mongodb-javascript-stack", gdb.COMMAND_STATUS) @@ -670,6 +678,24 @@ class MongoDBJavaScriptStack(gdb.Command): print("No JavaScript stack print done for: %s" % (main_binary_name)) @staticmethod + def atomic_get_ptr(atomic_scope: gdb.Value): + """Fetch the underlying pointer from std::atomic.""" + + # Awkwardly, the gdb.Value type does not support a check like + # `'_M_b' in atomic_scope`, so exceptions for flow control it is. :| + try: + # reach into std::atomic and grab the pointer. This is for libc++ + return atomic_scope['_M_b']['_M_p'] + except gdb.error: + # Worst case scenario: try and use .load(), but it's probably + # inlined. parse_and_eval required because you can't call methods + # in gdb on the Python API + return gdb.parse_and_eval( + f"((std::atomic<mongo::mozjs::MozJSImplScope*> *)({atomic_scope.address}))->load()") + + return None + + @staticmethod def javascript_stack(): """GDB in-process python supplement.""" @@ -690,13 +716,29 @@ class MongoDBJavaScriptStack(gdb.Command): continue try: - if gdb.parse_and_eval( - 'mongo::mozjs::kCurrentScope && mongo::mozjs::kCurrentScope->_inOp'): - gdb.execute('thread', from_tty=False, to_string=False) - gdb.execute( - 'printf "%s\\n", ' + - 'mongo::mozjs::kCurrentScope->buildStackString().c_str()', from_tty=False, - to_string=False) + # The following block is roughly equivalent to this: + # namespace mongo::mozjs { + # std::atomic<MozJSImplScope*> kCurrentScope = ...; + # } + # if (!scope || scope->_inOp == 0) { continue; } + # print(scope->buildStackString()->c_str()); + atomic_scope = gdb.parse_and_eval("mongo::mozjs::kCurrentScope") + ptr = MongoDBJavaScriptStack.atomic_get_ptr(atomic_scope) + if not ptr: + continue + + scope = ptr.dereference() + if scope['_inOp'] == 0: + continue + + gdb.execute('thread', from_tty=False, to_string=False) + # gdb continues to not support calling methods through Python, + # so work around it by casting the raw ptr back to its type, + # and calling the method through execute darkness + gdb.execute( + f'printf "%s\\n", ((mongo::mozjs::MozJSImplScope*)({ptr}))->buildStackString().c_str()', + from_tty=False, to_string=False) + except gdb.error as err: print("Ignoring GDB error '%s' in javascript_stack" % str(err)) continue |