Skip to content

Commit 3794d21

Browse files
committed
Explain: Don't rely on symbol information for uncaught exceptions.
We can retrieve this using the layout of the structure as it's part of the ABI. That means we can be independent of debug information for the C++ runtime.
1 parent fbcebde commit 3794d21

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

explain/explain.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,29 @@ def cpp_get_uncaught_exceptions() -> int:
227227
"""
228228
Return the current number of uncaught exceptions on the current thread.
229229
"""
230-
try:
231-
return int(gdb.parse_and_eval("__cxa_get_globals()->uncaught_exceptions"))
232-
except gdb.error:
233-
# Fall back to alternate spelling which has also been observed.
234-
return int(gdb.parse_and_eval("__cxa_get_globals()->uncaughtExceptions"))
230+
# Get a pointer to the base of the C++ runtime's per-thread globals.
231+
cxa_globals = gdb.parse_and_eval("(char *)__cxa_get_globals()")
232+
233+
# The globals structure contains a pointer, followed by an unsigned int that stores the current
234+
# count of uncaught exceptions.
235+
#
236+
# See https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-data for more details.
237+
#
238+
# Mark saw the naming for the "uncaughtExceptions" field appear to vary but has not been able to
239+
# reproduce this. However, the names are not always available at all if debug symbols are not
240+
# present.
241+
#
242+
# Since this is part of the ABI we can calculate the address to look up the current uncaught
243+
# exception count, rather than rely on symbols.
244+
245+
void_ptr_type = gdb.lookup_type("void").pointer()
246+
unsigned_int_type = gdb.lookup_type("unsigned int")
247+
248+
# The globals structure contains pointer followed by the unsigned int we are looking for. We can
249+
# calculate a pointer to that unsigned int member.
250+
uncaught_ptr = (cxa_globals + void_ptr_type.sizeof).cast(unsigned_int_type.pointer())
251+
252+
return int(uncaught_ptr.dereference())
235253

236254

237255
def cpp_exception_state_present() -> bool:

0 commit comments

Comments
 (0)