Made generated prettyasserts more debuggable
The main star of the show is the adoption of __builtin_trap() for aborting on assert failure. I discovered this GCC/Clang extension recently and it integrates much, _much_ better with GDB. With stdlib's abort(), GDB drops you off in several layers of internal stdlib functions, which is a pain to navigate out of to get to where the assert actually happened. With __builtin_trap(), GDB stops immediately, making debugging quick and easy. This is great! The pain of debugging needs to come from understanding the error, not just getting to it. --- Also tweaked a few things with the internal print functions to make reading the generated source easier, though I realize this is a rare thing to do.
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
|
||||||
// some helpers
|
// some helpers
|
||||||
|
|||||||
@@ -1366,13 +1366,6 @@ def run(runner, bench_ids=[], **args):
|
|||||||
'-ex', 'break %s:%d' % (path, lineno),
|
'-ex', 'break %s:%d' % (path, lineno),
|
||||||
'-ex', 'run',
|
'-ex', 'run',
|
||||||
'--args']
|
'--args']
|
||||||
elif failure.assert_ is not None:
|
|
||||||
cmd[:0] = args['gdb_path'] + [
|
|
||||||
'-q',
|
|
||||||
'-ex', 'run',
|
|
||||||
'-ex', 'frame function raise',
|
|
||||||
'-ex', 'up 2',
|
|
||||||
'--args']
|
|
||||||
else:
|
else:
|
||||||
cmd[:0] = args['gdb_path'] + [
|
cmd[:0] = args['gdb_path'] + [
|
||||||
'-q',
|
'-q',
|
||||||
|
|||||||
+23
-24
@@ -13,12 +13,6 @@
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# NOTE the use of macros here helps keep a consistent stack depth which
|
|
||||||
# tools may rely on.
|
|
||||||
#
|
|
||||||
# If compilation errors are noisy consider using -ftrack-macro-expansion=0.
|
|
||||||
#
|
|
||||||
|
|
||||||
LIMIT = 16
|
LIMIT = 16
|
||||||
|
|
||||||
CMP = {
|
CMP = {
|
||||||
@@ -65,28 +59,27 @@ def write_header(f, limit=LIMIT):
|
|||||||
f.writeln("#include <inttypes.h>")
|
f.writeln("#include <inttypes.h>")
|
||||||
f.writeln("#include <stdio.h>")
|
f.writeln("#include <stdio.h>")
|
||||||
f.writeln("#include <string.h>")
|
f.writeln("#include <string.h>")
|
||||||
f.writeln("#include <signal.h>")
|
|
||||||
# give source a chance to define feature macros
|
# give source a chance to define feature macros
|
||||||
f.writeln("#undef _FEATURES_H")
|
f.writeln("#undef _FEATURES_H")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
|
|
||||||
# write print macros
|
# write print macros
|
||||||
f.writeln("__attribute__((unused))")
|
f.writeln("__attribute__((unused))")
|
||||||
f.writeln("static void __pretty_assert_print_bool(")
|
f.writeln("static void __pretty_assert_bool(")
|
||||||
f.writeln(" const void *v, size_t size) {")
|
f.writeln(" const void *v, size_t size) {")
|
||||||
f.writeln(" (void)size;")
|
f.writeln(" (void)size;")
|
||||||
f.writeln(" printf(\"%s\", *(const bool*)v ? \"true\" : \"false\");")
|
f.writeln(" printf(\"%s\", *(const bool*)v ? \"true\" : \"false\");")
|
||||||
f.writeln("}")
|
f.writeln("}")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln("__attribute__((unused))")
|
f.writeln("__attribute__((unused))")
|
||||||
f.writeln("static void __pretty_assert_print_int(")
|
f.writeln("static void __pretty_assert_int(")
|
||||||
f.writeln(" const void *v, size_t size) {")
|
f.writeln(" const void *v, size_t size) {")
|
||||||
f.writeln(" (void)size;")
|
f.writeln(" (void)size;")
|
||||||
f.writeln(" printf(\"%\"PRIiMAX, *(const intmax_t*)v);")
|
f.writeln(" printf(\"%\"PRIiMAX, *(const intmax_t*)v);")
|
||||||
f.writeln("}")
|
f.writeln("}")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln("__attribute__((unused))")
|
f.writeln("__attribute__((unused))")
|
||||||
f.writeln("static void __pretty_assert_print_mem(")
|
f.writeln("static void __pretty_assert_mem(")
|
||||||
f.writeln(" const void *v, size_t size) {")
|
f.writeln(" const void *v, size_t size) {")
|
||||||
f.writeln(" const uint8_t *v_ = v;")
|
f.writeln(" const uint8_t *v_ = v;")
|
||||||
f.writeln(" printf(\"\\\"\");")
|
f.writeln(" printf(\"\\\"\");")
|
||||||
@@ -104,13 +97,13 @@ def write_header(f, limit=LIMIT):
|
|||||||
f.writeln("}")
|
f.writeln("}")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln("__attribute__((unused))")
|
f.writeln("__attribute__((unused))")
|
||||||
f.writeln("static void __pretty_assert_print_str(")
|
f.writeln("static void __pretty_assert_str(")
|
||||||
f.writeln(" const void *v, size_t size) {")
|
f.writeln(" const void *v, size_t size) {")
|
||||||
f.writeln(" __pretty_assert_print_mem(v, size);")
|
f.writeln(" __pretty_assert_mem(v, size);")
|
||||||
f.writeln("}")
|
f.writeln("}")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln("__attribute__((unused, noinline))")
|
f.writeln("__attribute__((unused))")
|
||||||
f.writeln("static void __pretty_assert_fail(")
|
f.writeln("static void __pretty_assert_print(")
|
||||||
f.writeln(" const char *file, int line,")
|
f.writeln(" const char *file, int line,")
|
||||||
f.writeln(" void (*type_print_cb)(const void*, size_t),")
|
f.writeln(" void (*type_print_cb)(const void*, size_t),")
|
||||||
f.writeln(" const char *cmp,")
|
f.writeln(" const char *cmp,")
|
||||||
@@ -122,7 +115,6 @@ def write_header(f, limit=LIMIT):
|
|||||||
f.writeln(" type_print_cb(rh, rsize);")
|
f.writeln(" type_print_cb(rh, rsize);")
|
||||||
f.writeln(" printf(\"\\n\");")
|
f.writeln(" printf(\"\\n\");")
|
||||||
f.writeln(" fflush(NULL);")
|
f.writeln(" fflush(NULL);")
|
||||||
f.writeln(" raise(SIGABRT);")
|
|
||||||
f.writeln("}")
|
f.writeln("}")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
|
|
||||||
@@ -133,57 +125,64 @@ def write_header(f, limit=LIMIT):
|
|||||||
f.writeln(" bool _lh = !!(lh); \\")
|
f.writeln(" bool _lh = !!(lh); \\")
|
||||||
f.writeln(" bool _rh = !!(rh); \\")
|
f.writeln(" bool _rh = !!(rh); \\")
|
||||||
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
||||||
f.writeln(" __pretty_assert_fail( \\")
|
f.writeln(" __pretty_assert_print( \\")
|
||||||
f.writeln(" __FILE__, __LINE__, \\")
|
f.writeln(" __FILE__, __LINE__, \\")
|
||||||
f.writeln(" __pretty_assert_print_bool, \"%s\", \\"
|
f.writeln(" __pretty_assert_bool, \"%s\", \\"
|
||||||
% cmp)
|
% cmp)
|
||||||
f.writeln(" &_lh, 0, \\")
|
f.writeln(" &_lh, 0, \\")
|
||||||
f.writeln(" &_rh, 0); \\")
|
f.writeln(" &_rh, 0); \\")
|
||||||
|
f.writeln(" __builtin_trap(); \\")
|
||||||
f.writeln(" } \\")
|
f.writeln(" } \\")
|
||||||
f.writeln("} while (0)")
|
f.writeln("} while (0)")
|
||||||
|
f.writeln()
|
||||||
for op, cmp in sorted(CMP.items()):
|
for op, cmp in sorted(CMP.items()):
|
||||||
f.writeln("#define __PRETTY_ASSERT_INT_%s(lh, rh) do { \\"
|
f.writeln("#define __PRETTY_ASSERT_INT_%s(lh, rh) do { \\"
|
||||||
% cmp.upper())
|
% cmp.upper())
|
||||||
f.writeln(" __typeof__(rh) _lh = lh; \\")
|
f.writeln(" __typeof__(rh) _lh = lh; \\")
|
||||||
f.writeln(" __typeof__(rh) _rh = rh; \\")
|
f.writeln(" __typeof__(rh) _rh = rh; \\")
|
||||||
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
||||||
f.writeln(" __pretty_assert_fail( \\")
|
f.writeln(" __pretty_assert_print( \\")
|
||||||
f.writeln(" __FILE__, __LINE__, \\")
|
f.writeln(" __FILE__, __LINE__, \\")
|
||||||
f.writeln(" __pretty_assert_print_int, \"%s\", \\"
|
f.writeln(" __pretty_assert_int, \"%s\", \\"
|
||||||
% cmp)
|
% cmp)
|
||||||
f.writeln(" &(intmax_t){(intmax_t)_lh}, 0, \\")
|
f.writeln(" &(intmax_t){(intmax_t)_lh}, 0, \\")
|
||||||
f.writeln(" &(intmax_t){(intmax_t)_rh}, 0); \\")
|
f.writeln(" &(intmax_t){(intmax_t)_rh}, 0); \\")
|
||||||
|
f.writeln(" __builtin_trap(); \\")
|
||||||
f.writeln(" } \\")
|
f.writeln(" } \\")
|
||||||
f.writeln("} while (0)")
|
f.writeln("} while (0)")
|
||||||
|
f.writeln()
|
||||||
for op, cmp in sorted(CMP.items()):
|
for op, cmp in sorted(CMP.items()):
|
||||||
f.writeln("#define __PRETTY_ASSERT_MEM_%s(lh, rh, size) do { \\"
|
f.writeln("#define __PRETTY_ASSERT_MEM_%s(lh, rh, size) do { \\"
|
||||||
% cmp.upper())
|
% cmp.upper())
|
||||||
f.writeln(" const void *_lh = lh; \\")
|
f.writeln(" const void *_lh = lh; \\")
|
||||||
f.writeln(" const void *_rh = rh; \\")
|
f.writeln(" const void *_rh = rh; \\")
|
||||||
f.writeln(" if (!(memcmp(_lh, _rh, size) %s 0)) { \\" % op)
|
f.writeln(" if (!(memcmp(_lh, _rh, size) %s 0)) { \\" % op)
|
||||||
f.writeln(" __pretty_assert_fail( \\")
|
f.writeln(" __pretty_assert_print( \\")
|
||||||
f.writeln(" __FILE__, __LINE__, \\")
|
f.writeln(" __FILE__, __LINE__, \\")
|
||||||
f.writeln(" __pretty_assert_print_mem, \"%s\", \\"
|
f.writeln(" __pretty_assert_mem, \"%s\", \\"
|
||||||
% cmp)
|
% cmp)
|
||||||
f.writeln(" _lh, size, \\")
|
f.writeln(" _lh, size, \\")
|
||||||
f.writeln(" _rh, size); \\")
|
f.writeln(" _rh, size); \\")
|
||||||
|
f.writeln(" __builtin_trap(); \\")
|
||||||
f.writeln(" } \\")
|
f.writeln(" } \\")
|
||||||
f.writeln("} while (0)")
|
f.writeln("} while (0)")
|
||||||
|
f.writeln()
|
||||||
for op, cmp in sorted(CMP.items()):
|
for op, cmp in sorted(CMP.items()):
|
||||||
f.writeln("#define __PRETTY_ASSERT_STR_%s(lh, rh) do { \\"
|
f.writeln("#define __PRETTY_ASSERT_STR_%s(lh, rh) do { \\"
|
||||||
% cmp.upper())
|
% cmp.upper())
|
||||||
f.writeln(" const char *_lh = lh; \\")
|
f.writeln(" const char *_lh = lh; \\")
|
||||||
f.writeln(" const char *_rh = rh; \\")
|
f.writeln(" const char *_rh = rh; \\")
|
||||||
f.writeln(" if (!(strcmp(_lh, _rh) %s 0)) { \\" % op)
|
f.writeln(" if (!(strcmp(_lh, _rh) %s 0)) { \\" % op)
|
||||||
f.writeln(" __pretty_assert_fail( \\")
|
f.writeln(" __pretty_assert_print( \\")
|
||||||
f.writeln(" __FILE__, __LINE__, \\")
|
f.writeln(" __FILE__, __LINE__, \\")
|
||||||
f.writeln(" __pretty_assert_print_str, \"%s\", \\"
|
f.writeln(" __pretty_assert_str, \"%s\", \\"
|
||||||
% cmp)
|
% cmp)
|
||||||
f.writeln(" _lh, strlen(_lh), \\")
|
f.writeln(" _lh, strlen(_lh), \\")
|
||||||
f.writeln(" _rh, strlen(_rh)); \\")
|
f.writeln(" _rh, strlen(_rh)); \\")
|
||||||
|
f.writeln(" __builtin_trap(); \\")
|
||||||
f.writeln(" } \\")
|
f.writeln(" } \\")
|
||||||
f.writeln("} while (0)")
|
f.writeln("} while (0)")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln()
|
f.writeln()
|
||||||
|
|
||||||
def mkassert(type, cmp, lh, rh, size=None):
|
def mkassert(type, cmp, lh, rh, size=None):
|
||||||
|
|||||||
@@ -1375,13 +1375,6 @@ def run(runner, test_ids=[], **args):
|
|||||||
'-ex', 'ignore 1 %d' % powerlosses,
|
'-ex', 'ignore 1 %d' % powerlosses,
|
||||||
'-ex', 'run',
|
'-ex', 'run',
|
||||||
'--args']
|
'--args']
|
||||||
elif failure.assert_ is not None:
|
|
||||||
cmd[:0] = args['gdb_path'] + [
|
|
||||||
'-q',
|
|
||||||
'-ex', 'run',
|
|
||||||
'-ex', 'frame function raise',
|
|
||||||
'-ex', 'up 2',
|
|
||||||
'--args']
|
|
||||||
else:
|
else:
|
||||||
cmd[:0] = args['gdb_path'] + [
|
cmd[:0] = args['gdb_path'] + [
|
||||||
'-q',
|
'-q',
|
||||||
|
|||||||
Reference in New Issue
Block a user