Author: Armin Rigo <ar...@tunes.org> Branch: reverse-debugger Changeset: r85306:1c3f6914ae95 Date: 2016-06-21 16:54 +0200 http://bitbucket.org/pypy/pypy/changeset/1c3f6914ae95/
Log: in-progress: tracking live objects diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py --- a/rpython/rlib/revdb.py +++ b/rpython/rlib/revdb.py @@ -17,6 +17,7 @@ CMD_MOREINFO = 5 ANSWER_TEXT = 20 ANSWER_MOREINFO = 21 +ANSWER_NEXTNID = 22 def stop_point(): @@ -31,6 +32,9 @@ def register_debug_command(command, lambda_func): """Register the extra RPython-implemented debug command.""" +def register_allocation_command(lambda_func): + """Register the extra RPython-implemented callback for allocation.""" + def send_answer(cmd, arg1=0, arg2=0, arg3=0, extra=""): """For RPython debug commands: writes an answer block to stdout""" llop.revdb_send_answer(lltype.Void, cmd, arg1, arg2, arg3, extra) @@ -38,6 +42,9 @@ def send_output(text): send_answer(ANSWER_TEXT, extra=text) +def send_nextnid(unique_id): + send_answer(ANSWER_NEXTNID, unique_id) + def current_time(): """For RPython debug commands: returns the current time.""" return llop.revdb_get_value(lltype.SignedLongLong, 'c') @@ -131,7 +138,12 @@ cmds = t.revdb_commands except AttributeError: cmds = t.revdb_commands = [] - cmds.append((command_num, func)) + for old_num, old_func in cmds: + if old_num == command_num: + assert old_func is func + break + else: + cmds.append((command_num, func)) s_func = self.bookkeeper.immutablevalue(func) s_ptr1 = llannotation.SomePtr(ll_ptrtype=_CMDPTR) s_str2 = annmodel.SomeString() @@ -140,3 +152,28 @@ def specialize_call(self, hop): hop.exception_cannot_occur() + + +class RegisterAllocationCommand(ExtRegistryEntry): + _about_ = register_allocation_command + + def compute_result_annotation(self, s_lambda_func): + from rpython.annotator import model as annmodel + from rpython.rtyper import llannotation + + lambda_func = s_lambda_func.const + t = self.bookkeeper.annotator.translator + if t.config.translation.reverse_debugger: + func = lambda_func() + try: + assert t.revdb_allocation_cmd is func + except AttributeError: + t.revdb_allocation_cmd = func + s_func = self.bookkeeper.immutablevalue(func) + s_int1 = annmodel.SomeInteger(knowntype=r_longlong) + s_ref2 = llannotation.lltype_to_annotation(llmemory.GCREF) + self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key, + s_func, [s_int1, s_ref2]) + + def specialize_call(self, hop): + hop.exception_cannot_occur() diff --git a/rpython/translator/revdb/gencsupp.py b/rpython/translator/revdb/gencsupp.py --- a/rpython/translator/revdb/gencsupp.py +++ b/rpython/translator/revdb/gencsupp.py @@ -1,5 +1,5 @@ import py -from rpython.rtyper.lltypesystem import lltype, rffi, rstr +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr from rpython.translator.c.support import cdecl from rpython.rlib import exports, revdb @@ -23,25 +23,31 @@ def prepare_database(db): - FUNCPTR = lltype.Ptr(lltype.FuncType([revdb._CMDPTR, - lltype.Ptr(rstr.STR)], lltype.Void)) + FUNCPTR = lltype.Ptr(lltype.FuncType([revdb._CMDPTR, lltype.Ptr(rstr.STR)], + lltype.Void)) + ALLOCFUNCPTR = lltype.Ptr(lltype.FuncType([rffi.LONGLONG, llmemory.GCREF], + lltype.Void)) bk = db.translator.annotator.bookkeeper cmds = getattr(db.translator, 'revdb_commands', []) - array_names = lltype.malloc(rffi.CArray(rffi.INT), len(cmds) + 1, - flavor='raw', immortal=True, zero=True) - array_funcs = lltype.malloc(rffi.CArray(FUNCPTR), len(cmds), - flavor='raw', immortal=True, zero=True) + S = lltype.Struct('RPY_REVDB_COMMANDS', + ('names', lltype.FixedSizeArray(rffi.INT, len(cmds) + 1)), + ('funcs', lltype.FixedSizeArray(FUNCPTR, len(cmds))), + ('alloc', ALLOCFUNCPTR)) + s = lltype.malloc(S, flavor='raw', immortal=True, zero=True) for i, (name, func) in enumerate(cmds): fnptr = lltype.getfunctionptr(bk.getdesc(func).getuniquegraph()) assert lltype.typeOf(fnptr) == FUNCPTR assert isinstance(name, int) and name != 0 - array_names[i] = rffi.cast(rffi.INT, name) - array_funcs[i] = fnptr + s.names[i] = rffi.cast(rffi.INT, name) + s.funcs[i] = fnptr - exports.EXPORTS_obj2name[array_names._as_obj()] = 'rpy_revdb_command_names' - exports.EXPORTS_obj2name[array_funcs._as_obj()] = 'rpy_revdb_command_funcs' - db.get(array_names) - db.get(array_funcs) + allocation_cmd = getattr(db.translator, 'revdb_allocation_cmd', None) + if allocation_cmd is not None: + s.alloc = lltype.getfunctionptr( + bk.getdesc(allocation_cmd).getuniquegraph()) + + exports.EXPORTS_obj2name[s._as_obj()] = 'rpy_revdb_commands' + db.get(s) diff --git a/rpython/translator/revdb/message.py b/rpython/translator/revdb/message.py --- a/rpython/translator/revdb/message.py +++ b/rpython/translator/revdb/message.py @@ -4,9 +4,11 @@ # See the corresponding answers for details about messages. -CMD_FORK = -1 # Message(CMD_FORK) -CMD_QUIT = -2 # Message(CMD_QUIT) -CMD_FORWARD = -3 # Message(CMD_FORWARD, steps, breakpoint_mode) +CMD_FORK = -1 # Message(CMD_FORK) +CMD_QUIT = -2 # Message(CMD_QUIT) +CMD_FORWARD = -3 # Message(CMD_FORWARD, steps, breakpoint_mode) +CMD_FUTUREIDS = -4 # Message(CMD_FUTUREIDS, extra=list-of-8bytes-uids) +CMD_ALLOCATING= -5 # Message(CMD_CREATING, uid, addr) # extra commands which are not handled by revdb.c, but # by revdb.register_debug_command() CMD_PRINT = 1 # Message(CMD_PRINT, extra=expression) @@ -50,6 +52,10 @@ # Message(ANSWER_MOREINFO, stack_depth) ANSWER_MOREINFO = 21 +# sent from CMD_PRINT to record the existence of a recallable object +# Message(ANSWER_NEXTNID, unique-id) +ANSWER_NEXTNID = 22 + # ____________________________________________________________ diff --git a/rpython/translator/revdb/process.py b/rpython/translator/revdb/process.py --- a/rpython/translator/revdb/process.py +++ b/rpython/translator/revdb/process.py @@ -172,6 +172,7 @@ self.active = child self.paused = {1: child.clone()} # {time: subprocess} self.all_breakpoints = AllBreakpoints() + self.all_printed_objects = [] def get_current_time(self): return self.active.current_time @@ -313,7 +314,8 @@ """Print an expression. """ self.active.tainted = True - self.active.send(Message(CMD_PRINT, extra=expression)) + next_nid = len(self.all_printed_objects) + self.active.send(Message(CMD_PRINT, next_nid, extra=expression)) self.active.print_text_answer() def show_backtrace(self): diff --git a/rpython/translator/revdb/src-revdb/revdb.c b/rpython/translator/revdb/src-revdb/revdb.c --- a/rpython/translator/revdb/src-revdb/revdb.c +++ b/rpython/translator/revdb/src-revdb/revdb.c @@ -192,9 +192,10 @@ #define INIT_VERSION_NUMBER 0xd80100 -#define CMD_FORK (-1) -#define CMD_QUIT (-2) -#define CMD_FORWARD (-3) +#define CMD_FORK (-1) +#define CMD_QUIT (-2) +#define CMD_FORWARD (-3) +#define CMD_FUTUREIDS (-4) #define ANSWER_INIT (-20) #define ANSWER_READY (-21) @@ -215,6 +216,7 @@ static uint64_t last_recorded_breakpoint_loc; static int last_recorded_breakpoint_num; static char breakpoint_mode; +static uint64_t *future_ids, *future_next_id; static void attach_gdb(void) { @@ -540,12 +542,33 @@ } } +static void command_future_ids(rpy_revdb_command_t *cmd, char *extra) +{ + free(future_ids); + if (cmd->extra_size == 0) { + future_ids = NULL; + rpy_revdb.unique_id_break = 0; + } + else { + assert(cmd->extra_size % sizeof(uint64_t) == 0); + future_ids = malloc(cmd->extra_size + sizeof(uint64_t)); + if (future_ids == NULL) { + fprintf(stderr, "out of memory for a buffer of %llu chars\n", + (unsigned long long)cmd->extra_size); + exit(1); + } + memcpy(future_ids, extra, cmd->extra_size); + future_ids[cmd->extra_size / sizeof(uint64_t)] = 0; + } + future_next_id = future_ids; +} + static void command_default(rpy_revdb_command_t *cmd, char *extra) { RPyString *s; int i; - for (i = 0; rpy_revdb_command_names[i] != cmd->cmd; i++) { - if (rpy_revdb_command_names[i] == 0) { + for (i = 0; rpy_revdb_commands.rp_names[i] != cmd->cmd; i++) { + if (rpy_revdb_commands.rp_names[i] == 0) { fprintf(stderr, "unknown command %d\n", cmd->cmd); exit(1); } @@ -558,16 +581,29 @@ s = make_rpy_string(cmd->extra_size); memcpy(_RPyString_AsString(s), extra, cmd->extra_size); } - execute_rpy_function(rpy_revdb_command_funcs[i], cmd, s); + execute_rpy_function(rpy_revdb_commands.rp_funcs[i], cmd, s); +} + +static void save_state(void) +{ + stopped_time = rpy_revdb.stop_point_seen; + stopped_uid = rpy_revdb.unique_id_seen; + rpy_revdb.unique_id_seen = (-1ULL) << 63; +} + +static void restore_state(void) +{ + rpy_revdb.stop_point_seen = stopped_time; + rpy_revdb.unique_id_seen = stopped_uid; + stopped_time = 0; + stopped_uid = 0; } RPY_EXTERN void rpy_reverse_db_stop_point(void) { while (rpy_revdb.stop_point_break == rpy_revdb.stop_point_seen) { - stopped_time = rpy_revdb.stop_point_seen; - stopped_uid = rpy_revdb.unique_id_seen; - rpy_revdb.unique_id_seen = (-1ULL) << 63; + save_state(); breakpoint_mode = 0; if (pending_after_forward) { @@ -599,15 +635,16 @@ command_forward(&cmd); break; + case CMD_FUTUREIDS: + command_future_ids(&cmd, extra); + break; + default: command_default(&cmd, extra); break; } } - rpy_revdb.stop_point_seen = stopped_time; - rpy_revdb.unique_id_seen = stopped_uid; - stopped_time = 0; - stopped_uid = 0; + restore_state(); } } @@ -696,39 +733,21 @@ } } -static void (*unique_id_callback)(void *); - RPY_EXTERN uint64_t rpy_reverse_db_unique_id_break(void *new_object) { - rpy_revdb_t dinfo; - rpy_revdb.unique_id_break = 0; - disable_io(&dinfo); - if (setjmp(jmp_buf_cancel_execution) == 0) - unique_id_callback(new_object); - enable_io(&dinfo); + if (!new_object) { + fprintf(stderr, "out of memory: allocation failed, cannot continue\n"); + exit(1); + } + if (rpy_revdb_commands.rp_alloc) { + save_state(); + rpy_revdb_commands.rp_alloc(rpy_revdb.unique_id_seen, new_object); + restore_state(); + } + rpy_revdb.unique_id_break = *future_next_id++; return rpy_revdb.unique_id_seen; } -RPY_EXTERN -void rpy_reverse_db_track_object(long long unique_id, void callback(void *)) -{ - if (stopped_uid <= 0) { - fprintf(stderr, "stopped_uid should not be <= 0\n"); - return; - } - if (unique_id <= 0) { - fprintf(stderr, "cannot track a prebuilt or debugger-created object\n"); - return; - } - if (unique_id < stopped_uid) { - fprintf(stderr, "cannot track the creation of an object already created\n"); - return; - } - assert(callback != NULL); - unique_id_callback = callback; - rpy_revdb.unique_id_break = unique_id; -} - /* ------------------------------------------------------------ */ diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h b/rpython/translator/revdb/src-revdb/revdb_include.h --- a/rpython/translator/revdb/src-revdb/revdb_include.h +++ b/rpython/translator/revdb/src-revdb/revdb_include.h @@ -114,8 +114,5 @@ RPY_EXTERN void rpy_reverse_db_breakpoint(int64_t num); RPY_EXTERN long long rpy_reverse_db_get_value(char value_id); RPY_EXTERN uint64_t rpy_reverse_db_unique_id_break(void *new_object); -RPY_EXTERN void rpy_reverse_db_track_object(long long unique_id, - void callback(void *)); - /* ------------------------------------------------------------ */ _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit