From 357d8270b141ee35d60fc6e01d0a17b9cd9b45fa Mon Sep 17 00:00:00 2001 From: Paul Koning Date: Mon, 26 Oct 2015 15:26:16 -0400 Subject: introduce the target stack there's a huge hack in multi_target_compatible 2014-07-29 Tom Tromey * target-delegates.c: Rebuild. * make-target-delegates (write_debugmethod): Update for change to debug_target. * progspace.c (add_program_space): Acquire a reference to the target stack. (release_program_space): Release reference to the program space. (set_current_program_space): Set the target stack. * progspace.h (struct program_space) : New field. * target.c (target_ops_ptr): New typedef. (struct target_stack): New. (target_stack): Change type. (current_target): Update comment. (update_current_target): Update. (multi_target_compatible, ensure_multi_target_ok): New functions. (push_target): Update. Add multi-target check. (unpush_target, pop_all_targets_above, target_is_pushed) (target_info, target_require_runnable): Update. (target_stack_set): New global. (currently_multi_target, target_stack_incref, target_stack_decref) (target_stack_set_current, new_target_stack): New functions. (maintenance_print_target_stack): Update. (initialize_targets): Initialize target_stack_set, target_stack. Update. (target_stack_id): New function. (next_available_target_id): New global. (print_one_target_stack): New function. (maintenance_print_target_stack): Move earlier. Rewrite. (debug_target): Remove. (debug_to_open, setup_target_debug): Update. * target.h (target_stack_incref, target_stack_decref) (target_stack_set_current, new_target_stack, target_stack_id): Declare. * testsuite/gdb.base/auto-connect-native-target.exp: Update. --- gdb/target.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 228 insertions(+), 35 deletions(-) (limited to 'gdb/target.c') diff --git a/gdb/target.c b/gdb/target.c index 345a668..1d7a4cf 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -107,12 +107,12 @@ static enum exec_direction_kind default_execution_direction static struct target_ops debug_target; -#include "target-delegates.c" - static void init_dummy_target (void); static void update_current_target (void); +static int currently_multi_target (void); + /* Vector of existing target structures. */ typedef struct target_ops *target_ops_p; DEF_VEC_P (target_ops_p); @@ -123,15 +123,48 @@ static VEC (target_ops_p) *target_structs; static struct target_ops dummy_target; -/* Top of target stack. */ +/* The next available target id. */ + +static int next_available_target_id; + +/* The type of the target stack. */ + +struct target_stack +{ + /* The targets making up the current stack. */ + + struct target_ops *top; -static struct target_ops *target_stack; + /* Reference count. */ + + int refc; + + /* Target id. */ + + int id; + + /* The "smashed" target_ops. */ + + struct target_ops smashed; + + /* When the debug target is pushed, this holds a copy of the + previous smashed target. */ + + struct target_ops debug_target; +}; + +/* The current target stack. */ + +static struct target_stack *target_stack; /* The target structure we are currently using to talk to a process - or file or whatever "inferior" we have. */ + or file or whatever "inferior" we have. This is always equal to + TARGET_STACK->smashed. */ struct target_ops *current_target; +#include "target-delegates.c" + /* Command list for target. */ static struct cmd_list_element *targetlist = NULL; @@ -627,7 +660,7 @@ update_current_target (void) /* Install the delegators. */ install_delegators (current_target); - current_target->to_stratum = target_stack->to_stratum; + current_target->to_stratum = target_stack->top->to_stratum; #define INHERIT(FIELD, TARGET) \ if (!current_target->FIELD) \ @@ -635,7 +668,7 @@ update_current_target (void) /* Do not add any new INHERITs here. Instead, use the delegation mechanism provided by make-target-delegates. */ - for (t = target_stack; t; t = t->beneath) + for (t = target_stack->top; t; t = t->beneath) { INHERIT (to_shortname, t); INHERIT (to_longname, t); @@ -649,12 +682,40 @@ update_current_target (void) /* Finally, position the target-stack beneath the squashed "current_target". That way code looking for a non-inherited target method can quickly and simply find it. */ - current_target->beneath = target_stack; + current_target->beneath = target_stack->top; if (targetdebug) setup_target_debug (); } +/* Return true if target T is multi-target-compatible. */ + +static int +multi_target_compatible (struct target_ops *t) +{ + /* The main sentinel is the existence of to_xclose. Ideally all + targets would be converted to this approach. */ + if (t->to_xclose != NULL) + return 1; + + /* Dummy target is always ok. */ + if (t == &dummy_target) + return 1; + + /* "child" targets are native and thus always ok. Super hack. */ + return strcmp (t->to_shortname, "child") == 0; +} + +/* Require T to be multi-target-compatible. */ + +static void +ensure_multi_target_ok (struct target_ops *t) +{ + if (!multi_target_compatible (t)) + error (_("Target %s cannot be used in multi-target mode"), + t->to_shortname); +} + /* Push a new target type into the stack of the existing target accessors, possibly superseding some of the existing accessors. @@ -679,13 +740,16 @@ push_target (struct target_ops *t) } /* Find the proper stratum to install this target in. */ - for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath) + for (cur = &target_stack->top; (*cur) != NULL; cur = &(*cur)->beneath) { if ((int) (t->to_stratum) >= (int) (*cur)->to_stratum) break; } - /* If there's already targets at this stratum, remove them. */ + if (currently_multi_target ()) + ensure_multi_target_ok (t); + + /* If there's already a target at this stratum, remove them. */ /* FIXME: cagney/2003-10-15: I think this should be popping all targets to CUR, and not just those at this stratum level. */ while ((*cur) != NULL && t->to_stratum == (*cur)->to_stratum) @@ -742,7 +806,7 @@ unpush_target (struct target_ops *t) /* Look for the specified target. Note that we assume that a target can only occur once in the target stack. */ - for (cur = &target_stack; (*cur) != NULL; cur = &(*cur)->beneath) + for (cur = &target_stack->top; (*cur) != NULL; cur = &(*cur)->beneath) { if ((*cur) == t || (*cur)->to_identity == t) break; @@ -773,11 +837,11 @@ pop_all_targets_above (enum strata above_stratum) { while ((int) (current_target->to_stratum) > (int) above_stratum) { - if (!unpush_target (target_stack)) + if (!unpush_target (target_stack->top)) { fprintf_unfiltered (gdb_stderr, "pop_all_targets couldn't find target %s\n", - target_stack->to_shortname); + target_stack->top->to_shortname); internal_error (__FILE__, __LINE__, _("failed internal consistency check")); break; @@ -809,7 +873,7 @@ target_is_pushed (struct target_ops *t) _("failed internal consistency check")); } - for (cur = target_stack; cur != NULL; cur = cur->beneath) + for (cur = target_stack->top; cur != NULL; cur = cur->beneath) if (cur == t || cur->to_identity == t) return 1; @@ -2106,7 +2170,7 @@ target_info (char *args, int from_tty) printf_unfiltered (_("Symbols from \"%s\".\n"), objfile_name (symfile_objfile)); - for (t = target_stack; t != NULL; t = t->beneath) + for (t = target_stack->top; t != NULL; t = t->beneath) { if (!(*t->to_has_memory) (t)) continue; @@ -2508,7 +2572,7 @@ target_require_runnable (void) { struct target_ops *t; - for (t = target_stack; t != NULL; t = t->beneath) + for (t = target_stack->top; t != NULL; t = t->beneath) { /* If this target knows how to create a new program, then assume we will still be able to after killing the current @@ -3806,12 +3870,152 @@ target_done_generating_core (void) static void setup_target_debug (void) { - memcpy (&debug_target, current_target, sizeof debug_target); + memcpy (&target_stack->debug_target, current_target, + sizeof (struct target_ops)); init_debug_target (current_target); } +/* A set of all current target stacks. */ + +static htab_t target_stack_set; + +/* Return true if there are already multiple target stacks. */ + +static int +currently_multi_target (void) +{ + return htab_elements (target_stack_set) > 1; +} + +/* See target.h. */ + +struct target_stack * +target_stack_incref (void) +{ + ++target_stack->refc; + return target_stack; +} + +/* See target.h. */ + +void +target_stack_decref (struct target_stack *tstack) +{ + --tstack->refc; + if (tstack->refc == 0) + { + /* It is ok to delete any random target stack as long as it only + has the dummy target. If any other target has been pushed, + then the target stack being deleted must be the current + target stack. */ + if (tstack->smashed.to_stratum != dummy_stratum) + { + gdb_assert (tstack == target_stack); + + pop_all_targets (); + target_stack = NULL; + current_target = NULL; + } + + htab_remove_elt (target_stack_set, tstack); + xfree (tstack); + } +} + +/* See target.h. */ + +void +target_stack_set_current (struct target_stack *tstack) +{ + target_stack = tstack; + current_target = &tstack->smashed; +} + +/* See target.h. */ + +struct target_stack * +new_target_stack (void) +{ + struct target_stack *save = target_stack; + struct target_stack *result; + void **slot; + + if (!currently_multi_target () && target_stack != NULL) + { + struct target_ops *t; + + for (t = target_stack->top; t != NULL; t = t->beneath) + ensure_multi_target_ok (t); + } + + /* Overwrite the globals so that push_target can work. */ + target_stack = XCNEW (struct target_stack); + target_stack->refc = 1; + /* A subtlety here is that post-increment ensures that the first + target stack we create has an id of 0. This will be handy once + we introduce a way to create a per-target ptid -- unconverted, + non-multi-capable targets will continue to do the right + thing. */ + target_stack->id = next_available_target_id++; + current_target = &target_stack->smashed; + + slot = htab_find_slot (target_stack_set, target_stack, INSERT); + gdb_assert (*slot == NULL); + *slot = target_stack; + + push_target (&dummy_target); + + result = target_stack; + target_stack = save; + if (target_stack == NULL) + current_target = NULL; + else + current_target = &save->smashed; + + return result; +} + +/* See target.h. */ + +int target_stack_id (void) +{ + return target_stack->id; +} + +/* Print a single target stack. */ + +static int +print_one_target_stack (void **slot, void *arg) +{ + struct target_stack *stack = *slot; + struct target_ops *t; + int i; + + printf_filtered (_("Target stack %s"), host_address_to_string (stack)); + if (stack == target_stack) + printf_filtered (_(" (current)")); + printf_filtered (_("\n")); + + for (t = stack->top; t != NULL; t = t->beneath) + { + printf_filtered (" - %s (%s)\n", t->to_shortname, t->to_longname); + } + + return 1; +} + +/* Print the name of each layers of our target stack. */ + +static void +maintenance_print_target_stack (char *cmd, int from_tty) +{ + htab_traverse (target_stack_set, print_one_target_stack, NULL); +} + + + static char targ_desc[] = "Names of targets and files being debugged.\nShows the entire \ stack of targets currently in use (including the exec-file,\n\ @@ -3831,21 +4035,6 @@ do_monitor_command (char *cmd, target_rcmd (cmd, gdb_stdtarg); } -/* Print the name of each layers of our target stack. */ - -static void -maintenance_print_target_stack (char *cmd, int from_tty) -{ - struct target_ops *t; - - printf_filtered (_("The current target stack is:\n")); - - for (t = target_stack; t != NULL; t = t->beneath) - { - printf_filtered (" - %s (%s)\n", t->to_shortname, t->to_longname); - } -} - /* See target.h. */ void @@ -4006,10 +4195,14 @@ set_write_memory_permission (char *args, int from_tty, void initialize_targets (void) { - current_target = XCNEW (struct target_ops); - init_dummy_target (); - push_target (&dummy_target); + + target_stack_set = htab_create_alloc (1, htab_hash_pointer, + htab_eq_pointer, NULL, + xcalloc, xfree); + + target_stack = new_target_stack (); + current_target = &target_stack->smashed; add_info ("target", target_info, targ_desc); add_info ("files", target_info, targ_desc); -- cgit v1.1