X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ftarget.c;h=5f7a2e729afd6751677878d62b40ba7d2f88eea0;hb=d62d0f5fc2156db337ac3cbbc3c05ca76565dbd3;hp=ceb71b36cde459d360e811b88e00dd34cb9f1d7f;hpb=8edfe2693228f91b78661dc04e8c91095ab19487;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/target.c b/gdb/target.c index ceb71b36cd..5f7a2e729a 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1,7 +1,7 @@ /* Select target systems and architectures at runtime for GDB. Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -39,15 +39,18 @@ #include "gdbcore.h" #include "exceptions.h" #include "target-descriptions.h" +#include "gdbthread.h" +#include "solib.h" +#include "exec.h" +#include "inline-frame.h" static void target_info (char *, int); -static void maybe_kill_then_attach (char *, int); - -static void kill_or_be_killed (int); - static void default_terminal_info (char *, int); +static int default_watchpoint_addr_within_range (struct target_ops *, + CORE_ADDR, CORE_ADDR, int); + static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int); static int nosymbol (char *, CORE_ADDR *); @@ -68,8 +71,6 @@ static void target_command (char *, int); static struct target_ops *find_default_run_target (char *); -static void nosupport_runtime (void); - static LONGEST default_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, @@ -88,39 +89,32 @@ static LONGEST target_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf, ULONGEST offset, LONGEST len); +static struct gdbarch *default_thread_architecture (struct target_ops *ops, + ptid_t ptid); + static void init_dummy_target (void); static struct target_ops debug_target; static void debug_to_open (char *, int); -static void debug_to_close (int); - -static void debug_to_attach (char *, int); - -static void debug_to_detach (char *, int); - -static void debug_to_resume (ptid_t, int, enum target_signal); - -static ptid_t debug_to_wait (ptid_t, struct target_waitstatus *); - -static void debug_to_fetch_registers (struct regcache *, int); - -static void debug_to_store_registers (struct regcache *, int); - static void debug_to_prepare_to_store (struct regcache *); static void debug_to_files_info (struct target_ops *); -static int debug_to_insert_breakpoint (struct bp_target_info *); +static int debug_to_insert_breakpoint (struct gdbarch *, + struct bp_target_info *); -static int debug_to_remove_breakpoint (struct bp_target_info *); +static int debug_to_remove_breakpoint (struct gdbarch *, + struct bp_target_info *); static int debug_to_can_use_hw_breakpoint (int, int, int); -static int debug_to_insert_hw_breakpoint (struct bp_target_info *); +static int debug_to_insert_hw_breakpoint (struct gdbarch *, + struct bp_target_info *); -static int debug_to_remove_hw_breakpoint (struct bp_target_info *); +static int debug_to_remove_hw_breakpoint (struct gdbarch *, + struct bp_target_info *); static int debug_to_insert_watchpoint (CORE_ADDR, int, int); @@ -130,6 +124,9 @@ static int debug_to_stopped_by_watchpoint (void); static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *); +static int debug_to_watchpoint_addr_within_range (struct target_ops *, + CORE_ADDR, CORE_ADDR, int); + static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int); static void debug_to_terminal_init (void); @@ -144,21 +141,15 @@ static void debug_to_terminal_ours (void); static void debug_to_terminal_info (char *, int); -static void debug_to_kill (void); - static void debug_to_load (char *, int); static int debug_to_lookup_symbol (char *, CORE_ADDR *); -static void debug_to_mourn_inferior (void); - static int debug_to_can_run (void); static void debug_to_notice_signals (ptid_t); -static int debug_to_thread_alive (ptid_t); - -static void debug_to_stop (void); +static void debug_to_stop (ptid_t); /* NOTE: cagney/2004-09-29: Many targets reference this variable in wierd and mysterious ways. Putting the variable here lets those @@ -193,16 +184,16 @@ struct target_ops current_target; static struct cmd_list_element *targetlist = NULL; -/* Nonzero if we are debugging an attached outside process - rather than an inferior. */ - -int attach_flag; - /* Nonzero if we should trust readonly sections from the executable when reading memory. */ static int trust_readonly = 0; +/* Nonzero if we should show true memory content including + memory breakpoint inserted by gdb. */ + +static int show_memory_breakpoints = 0; + /* Non-zero if we want to see trace of target level stuff. */ static int targetdebug = 0; @@ -215,7 +206,45 @@ show_targetdebug (struct ui_file *file, int from_tty, static void setup_target_debug (void); -DCACHE *target_dcache; +/* The option sets this. */ +static int stack_cache_enabled_p_1 = 1; +/* And set_stack_cache_enabled_p updates this. + The reason for the separation is so that we don't flush the cache for + on->on transitions. */ +static int stack_cache_enabled_p = 1; + +/* This is called *after* the stack-cache has been set. + Flush the cache for off->on and on->off transitions. + There's no real need to flush the cache for on->off transitions, + except cleanliness. */ + +static void +set_stack_cache_enabled_p (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (stack_cache_enabled_p != stack_cache_enabled_p_1) + target_dcache_invalidate (); + + stack_cache_enabled_p = stack_cache_enabled_p_1; +} + +static void +show_stack_cache_enabled_p (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Cache use for stack accesses is %s.\n"), value); +} + +/* Cache of memory operations, to speed up remote access. */ +static DCACHE *target_dcache; + +/* Invalidate the target dcache. */ + +void +target_dcache_invalidate (void) +{ + dcache_invalidate (target_dcache); +} /* The user just typed 'target' without the name of a target. */ @@ -226,6 +255,120 @@ target_command (char *arg, int from_tty) gdb_stdout); } +/* Default target_has_* methods for process_stratum targets. */ + +int +default_child_has_all_memory (struct target_ops *ops) +{ + /* If no inferior selected, then we can't read memory here. */ + if (ptid_equal (inferior_ptid, null_ptid)) + return 0; + + return 1; +} + +int +default_child_has_memory (struct target_ops *ops) +{ + /* If no inferior selected, then we can't read memory here. */ + if (ptid_equal (inferior_ptid, null_ptid)) + return 0; + + return 1; +} + +int +default_child_has_stack (struct target_ops *ops) +{ + /* If no inferior selected, there's no stack. */ + if (ptid_equal (inferior_ptid, null_ptid)) + return 0; + + return 1; +} + +int +default_child_has_registers (struct target_ops *ops) +{ + /* Can't read registers from no inferior. */ + if (ptid_equal (inferior_ptid, null_ptid)) + return 0; + + return 1; +} + +int +default_child_has_execution (struct target_ops *ops) +{ + /* If there's no thread selected, then we can't make it run through + hoops. */ + if (ptid_equal (inferior_ptid, null_ptid)) + return 0; + + return 1; +} + + +int +target_has_all_memory_1 (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_has_all_memory (t)) + return 1; + + return 0; +} + +int +target_has_memory_1 (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_has_memory (t)) + return 1; + + return 0; +} + +int +target_has_stack_1 (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_has_stack (t)) + return 1; + + return 0; +} + +int +target_has_registers_1 (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_has_registers (t)) + return 1; + + return 0; +} + +int +target_has_execution_1 (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_has_execution (t)) + return 1; + + return 0; +} + /* Add a possible target architecture to the list. */ void @@ -235,6 +378,21 @@ add_target (struct target_ops *t) if (t->to_xfer_partial == NULL) t->to_xfer_partial = default_xfer_partial; + if (t->to_has_all_memory == NULL) + t->to_has_all_memory = (int (*) (struct target_ops *)) return_zero; + + if (t->to_has_memory == NULL) + t->to_has_memory = (int (*) (struct target_ops *)) return_zero; + + if (t->to_has_stack == NULL) + t->to_has_stack = (int (*) (struct target_ops *)) return_zero; + + if (t->to_has_registers == NULL) + t->to_has_registers = (int (*) (struct target_ops *)) return_zero; + + if (t->to_has_execution == NULL) + t->to_has_execution = (int (*) (struct target_ops *)) return_zero; + if (!target_structs) { target_struct_allocsize = DEFAULT_ALLOCSIZE; @@ -268,13 +426,68 @@ target_ignore (void) { } +void +target_kill (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_kill != NULL) + { + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_kill ()\n"); + + t->to_kill (t); + return; + } + + noprocess (); +} + void target_load (char *arg, int from_tty) { - dcache_invalidate (target_dcache); + target_dcache_invalidate (); (*current_target.to_load) (arg, from_tty); } +void +target_create_inferior (char *exec_file, char *args, + char **env, int from_tty) +{ + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_create_inferior != NULL) + { + t->to_create_inferior (t, exec_file, args, env, from_tty); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, + "target_create_inferior (%s, %s, xxx, %d)\n", + exec_file, args, from_tty); + return; + } + } + + internal_error (__FILE__, __LINE__, + "could not find a target to create inferior"); +} + +void +target_terminal_inferior (void) +{ + /* A background resume (``run&'') should leave GDB in control of the + terminal. Use target_can_async_p, not target_is_async_p, since at + this point the target is not async yet. However, if sync_execution + is not set, we know it will become async prior to resume. */ + if (target_can_async_p () && !sync_execution) + return; + + /* If GDB is resuming the inferior in the foreground, install + inferior's terminal modes. */ + (*current_target.to_terminal_inferior) (); +} + static int nomemory (CORE_ADDR memaddr, char *myaddr, int len, int write, struct target_ops *t) @@ -302,62 +515,22 @@ nosymbol (char *name, CORE_ADDR *addrp) return 1; /* Symbol does not exist in target env */ } -static void -nosupport_runtime (void) -{ - if (ptid_equal (inferior_ptid, null_ptid)) - noprocess (); - else - error (_("No run-time support for this")); -} - - static void default_terminal_info (char *args, int from_tty) { printf_unfiltered (_("No saved terminal information.\n")); } -/* This is the default target_create_inferior and target_attach function. - If the current target is executing, it asks whether to kill it off. - If this function returns without calling error(), it has killed off - the target, and the operation should be attempted. */ +/* A default implementation for the to_get_ada_task_ptid target method. -static void -kill_or_be_killed (int from_tty) -{ - if (target_has_execution) - { - printf_unfiltered (_("You are already running a program:\n")); - target_files_info (); - if (query ("Kill it? ")) - { - target_kill (); - if (target_has_execution) - error (_("Killing the program did not help.")); - return; - } - else - { - error (_("Program not killed.")); - } - } - tcomplain (); -} + This function builds the PTID by using both LWP and TID as part of + the PTID lwp and tid elements. The pid used is the pid of the + inferior_ptid. */ -static void -maybe_kill_then_attach (char *args, int from_tty) -{ - kill_or_be_killed (from_tty); - target_attach (args, from_tty); -} - -static void -maybe_kill_then_create_inferior (char *exec, char *args, char **env, - int from_tty) +static ptid_t +default_get_ada_task_ptid (long lwp, long tid) { - kill_or_be_killed (0); - target_create_inferior (exec, args, env, from_tty); + return ptid_build (ptid_get_pid (inferior_ptid), lwp, tid); } /* Go through the target stack from top to bottom, copying over zero @@ -389,16 +562,17 @@ update_current_target (void) INHERIT (to_shortname, t); INHERIT (to_longname, t); INHERIT (to_doc, t); - INHERIT (to_open, t); - INHERIT (to_close, t); - INHERIT (to_attach, t); + /* Do not inherit to_open. */ + /* Do not inherit to_close. */ + /* Do not inherit to_attach. */ INHERIT (to_post_attach, t); - INHERIT (to_detach, t); + INHERIT (to_attach_no_wait, t); + /* Do not inherit to_detach. */ /* Do not inherit to_disconnect. */ - INHERIT (to_resume, t); - INHERIT (to_wait, t); - INHERIT (to_fetch_registers, t); - INHERIT (to_store_registers, t); + /* Do not inherit to_resume. */ + /* Do not inherit to_wait. */ + /* Do not inherit to_fetch_registers. */ + /* Do not inherit to_store_registers. */ INHERIT (to_prepare_to_store, t); INHERIT (deprecated_xfer_memory, t); INHERIT (to_files_info, t); @@ -410,9 +584,10 @@ update_current_target (void) INHERIT (to_insert_watchpoint, t); INHERIT (to_remove_watchpoint, t); INHERIT (to_stopped_data_address, t); - INHERIT (to_stopped_by_watchpoint, t); INHERIT (to_have_steppable_watchpoint, t); INHERIT (to_have_continuable_watchpoint, t); + INHERIT (to_stopped_by_watchpoint, t); + INHERIT (to_watchpoint_addr_within_range, t); INHERIT (to_region_ok_for_hw_watchpoint, t); INHERIT (to_terminal_init, t); INHERIT (to_terminal_inferior, t); @@ -420,10 +595,10 @@ update_current_target (void) INHERIT (to_terminal_ours, t); INHERIT (to_terminal_save_ours, t); INHERIT (to_terminal_info, t); - INHERIT (to_kill, t); + /* Do not inherit to_kill. */ INHERIT (to_load, t); INHERIT (to_lookup_symbol, t); - INHERIT (to_create_inferior, t); + /* Do no inherit to_create_inferior. */ INHERIT (to_post_startup_inferior, t); INHERIT (to_acknowledge_created_inferior, t); INHERIT (to_insert_fork_catchpoint, t); @@ -433,14 +608,14 @@ update_current_target (void) /* Do not inherit to_follow_fork. */ INHERIT (to_insert_exec_catchpoint, t); INHERIT (to_remove_exec_catchpoint, t); - INHERIT (to_reported_exec_events_per_exec_call, t); + INHERIT (to_set_syscall_catchpoint, t); INHERIT (to_has_exited, t); - INHERIT (to_mourn_inferior, t); + /* Do not inherit to_mourn_inferiour. */ INHERIT (to_can_run, t); INHERIT (to_notice_signals, t); - INHERIT (to_thread_alive, t); - INHERIT (to_find_new_threads, t); - INHERIT (to_pid_to_str, t); + /* Do not inherit to_thread_alive. */ + /* Do not inherit to_find_new_threads. */ + /* Do not inherit to_pid_to_str. */ INHERIT (to_extra_thread_info, t); INHERIT (to_stop, t); /* Do not inherit to_xfer_partial. */ @@ -448,22 +623,41 @@ update_current_target (void) INHERIT (to_pid_to_exec_file, t); INHERIT (to_log_command, t); INHERIT (to_stratum, t); - INHERIT (to_has_all_memory, t); - INHERIT (to_has_memory, t); - INHERIT (to_has_stack, t); - INHERIT (to_has_registers, t); - INHERIT (to_has_execution, t); + /* Do not inherit to_has_all_memory */ + /* Do not inherit to_has_memory */ + /* Do not inherit to_has_stack */ + /* Do not inherit to_has_registers */ + /* Do not inherit to_has_execution */ INHERIT (to_has_thread_control, t); - INHERIT (to_sections, t); - INHERIT (to_sections_end, t); INHERIT (to_can_async_p, t); INHERIT (to_is_async_p, t); INHERIT (to_async, t); - INHERIT (to_async_mask_value, t); + INHERIT (to_async_mask, t); INHERIT (to_find_memory_regions, t); INHERIT (to_make_corefile_notes, t); - INHERIT (to_get_thread_local_address, t); + INHERIT (to_get_bookmark, t); + INHERIT (to_goto_bookmark, t); + /* Do not inherit to_get_thread_local_address. */ + INHERIT (to_can_execute_reverse, t); + INHERIT (to_thread_architecture, t); /* Do not inherit to_read_description. */ + INHERIT (to_get_ada_task_ptid, t); + /* Do not inherit to_search_memory. */ + INHERIT (to_supports_multi_process, t); + INHERIT (to_trace_init, t); + INHERIT (to_download_tracepoint, t); + INHERIT (to_download_trace_state_variable, t); + INHERIT (to_trace_set_readonly_regions, t); + INHERIT (to_trace_start, t); + INHERIT (to_get_trace_status, t); + INHERIT (to_trace_stop, t); + INHERIT (to_trace_find, t); + INHERIT (to_get_trace_state_variable_value, t); + INHERIT (to_save_trace_data, t); + INHERIT (to_upload_tracepoints, t); + INHERIT (to_upload_trace_state_variables, t); + INHERIT (to_get_raw_trace_data, t); + INHERIT (to_set_disconnected_tracing, t); INHERIT (to_magic, t); /* Do not inherit to_memory_map. */ /* Do not inherit to_flash_erase. */ @@ -485,26 +679,9 @@ update_current_target (void) de_fault (to_close, (void (*) (int)) target_ignore); - de_fault (to_attach, - maybe_kill_then_attach); de_fault (to_post_attach, (void (*) (int)) target_ignore); - de_fault (to_detach, - (void (*) (char *, int)) - target_ignore); - de_fault (to_resume, - (void (*) (ptid_t, int, enum target_signal)) - noprocess); - de_fault (to_wait, - (ptid_t (*) (ptid_t, struct target_waitstatus *)) - noprocess); - de_fault (to_fetch_registers, - (void (*) (struct regcache *, int)) - target_ignore); - de_fault (to_store_registers, - (void (*) (struct regcache *, int)) - noprocess); de_fault (to_prepare_to_store, (void (*) (struct regcache *)) noprocess); @@ -522,10 +699,10 @@ update_current_target (void) (int (*) (int, int, int)) return_zero); de_fault (to_insert_hw_breakpoint, - (int (*) (struct bp_target_info *)) + (int (*) (struct gdbarch *, struct bp_target_info *)) return_minus_one); de_fault (to_remove_hw_breakpoint, - (int (*) (struct bp_target_info *)) + (int (*) (struct gdbarch *, struct bp_target_info *)) return_minus_one); de_fault (to_insert_watchpoint, (int (*) (CORE_ADDR, int, int)) @@ -539,6 +716,8 @@ update_current_target (void) de_fault (to_stopped_data_address, (int (*) (struct target_ops *, CORE_ADDR *)) return_zero); + de_fault (to_watchpoint_addr_within_range, + default_watchpoint_addr_within_range); de_fault (to_region_ok_for_hw_watchpoint, default_region_ok_for_hw_watchpoint); de_fault (to_terminal_init, @@ -558,17 +737,12 @@ update_current_target (void) target_ignore); de_fault (to_terminal_info, default_terminal_info); - de_fault (to_kill, - (void (*) (void)) - noprocess); de_fault (to_load, (void (*) (char *, int)) tcomplain); de_fault (to_lookup_symbol, (int (*) (char *, CORE_ADDR *)) nosymbol); - de_fault (to_create_inferior, - maybe_kill_then_create_inferior); de_fault (to_post_startup_inferior, (void (*) (ptid_t)) target_ignore); @@ -593,31 +767,22 @@ update_current_target (void) de_fault (to_remove_exec_catchpoint, (int (*) (int)) tcomplain); - de_fault (to_reported_exec_events_per_exec_call, - (int (*) (void)) - return_one); + de_fault (to_set_syscall_catchpoint, + (int (*) (int, int, int, int, int *)) + tcomplain); de_fault (to_has_exited, (int (*) (int, int, int *)) return_zero); - de_fault (to_mourn_inferior, - (void (*) (void)) - noprocess); de_fault (to_can_run, return_zero); de_fault (to_notice_signals, (void (*) (ptid_t)) target_ignore); - de_fault (to_thread_alive, - (int (*) (ptid_t)) - return_zero); - de_fault (to_find_new_threads, - (void (*) (void)) - target_ignore); de_fault (to_extra_thread_info, (char *(*) (struct thread_info *)) return_zero); de_fault (to_stop, - (void (*) (void)) + (void (*) (ptid_t)) target_ignore); current_target.to_xfer_partial = current_xfer_partial; de_fault (to_rcmd, @@ -626,16 +791,63 @@ update_current_target (void) de_fault (to_pid_to_exec_file, (char *(*) (int)) return_zero); - de_fault (to_can_async_p, - (int (*) (void)) - return_zero); - de_fault (to_is_async_p, - (int (*) (void)) - return_zero); de_fault (to_async, (void (*) (void (*) (enum inferior_event_type, void*), void*)) tcomplain); + de_fault (to_async_mask, + (int (*) (int)) + return_one); + de_fault (to_thread_architecture, + default_thread_architecture); current_target.to_read_description = NULL; + de_fault (to_get_ada_task_ptid, + (ptid_t (*) (long, long)) + default_get_ada_task_ptid); + de_fault (to_supports_multi_process, + (int (*) (void)) + return_zero); + de_fault (to_trace_init, + (void (*) (void)) + tcomplain); + de_fault (to_download_tracepoint, + (void (*) (struct breakpoint *)) + tcomplain); + de_fault (to_download_trace_state_variable, + (void (*) (struct trace_state_variable *)) + tcomplain); + de_fault (to_trace_set_readonly_regions, + (void (*) (void)) + tcomplain); + de_fault (to_trace_start, + (void (*) (void)) + tcomplain); + de_fault (to_get_trace_status, + (int (*) (struct trace_status *)) + return_minus_one); + de_fault (to_trace_stop, + (void (*) (void)) + tcomplain); + de_fault (to_trace_find, + (int (*) (enum trace_find_type, int, ULONGEST, ULONGEST, int *)) + return_zero); + de_fault (to_get_trace_state_variable_value, + (int (*) (int, LONGEST *)) + return_zero); + de_fault (to_save_trace_data, + (int (*) (char *)) + tcomplain); + de_fault (to_upload_tracepoints, + (int (*) (struct uploaded_tp **)) + return_zero); + de_fault (to_upload_trace_state_variables, + (int (*) (struct uploaded_tsv **)) + return_zero); + de_fault (to_get_raw_trace_data, + (LONGEST (*) (gdb_byte *, ULONGEST, LONGEST)) + tcomplain); + de_fault (to_set_disconnected_tracing, + (void (*) (int)) + tcomplain); #undef de_fault /* Finally, position the target-stack beneath the squashed @@ -647,56 +859,6 @@ update_current_target (void) setup_target_debug (); } -/* Mark OPS as a running target. This reverses the effect - of target_mark_exited. */ - -void -target_mark_running (struct target_ops *ops) -{ - struct target_ops *t; - - for (t = target_stack; t != NULL; t = t->beneath) - if (t == ops) - break; - if (t == NULL) - internal_error (__FILE__, __LINE__, - "Attempted to mark unpushed target \"%s\" as running", - ops->to_shortname); - - ops->to_has_execution = 1; - ops->to_has_all_memory = 1; - ops->to_has_memory = 1; - ops->to_has_stack = 1; - ops->to_has_registers = 1; - - update_current_target (); -} - -/* Mark OPS as a non-running target. This reverses the effect - of target_mark_running. */ - -void -target_mark_exited (struct target_ops *ops) -{ - struct target_ops *t; - - for (t = target_stack; t != NULL; t = t->beneath) - if (t == ops) - break; - if (t == NULL) - internal_error (__FILE__, __LINE__, - "Attempted to mark unpushed target \"%s\" as running", - ops->to_shortname); - - ops->to_has_execution = 0; - ops->to_has_all_memory = 0; - ops->to_has_memory = 0; - ops->to_has_stack = 0; - ops->to_has_registers = 0; - - update_current_target (); -} - /* Push a new target type into the stack of the existing target accessors, possibly superseding some of the existing accessors. @@ -761,6 +923,10 @@ unpush_target (struct target_ops *t) struct target_ops **cur; struct target_ops *tmp; + if (t->to_stratum == dummy_stratum) + internal_error (__FILE__, __LINE__, + "Attempt to unpush the dummy target"); + /* Look for the specified target. Note that we assume that a target can only occur once in the target stack. */ @@ -794,7 +960,7 @@ unpush_target (struct target_ops *t) void pop_target (void) { - target_close (¤t_target, 0); /* Let it clean up */ + target_close (target_stack, 0); /* Let it clean up */ if (unpush_target (target_stack) == 1) return; @@ -804,15 +970,48 @@ pop_target (void) internal_error (__FILE__, __LINE__, _("failed internal consistency check")); } +void +pop_all_targets_above (enum strata above_stratum, int quitting) +{ + while ((int) (current_target.to_stratum) > (int) above_stratum) + { + target_close (target_stack, quitting); + if (!unpush_target (target_stack)) + { + fprintf_unfiltered (gdb_stderr, + "pop_all_targets couldn't find target %s\n", + target_stack->to_shortname); + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + break; + } + } +} + +void +pop_all_targets (int quitting) +{ + pop_all_targets_above (dummy_stratum, quitting); +} + /* Using the objfile specified in OBJFILE, find the address for the current thread's thread-local storage with offset OFFSET. */ CORE_ADDR target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset) { volatile CORE_ADDR addr = 0; + struct target_ops *target; + + for (target = current_target.beneath; + target != NULL; + target = target->beneath) + { + if (target->to_get_thread_local_address != NULL) + break; + } - if (target_get_thread_local_address_p () - && gdbarch_fetch_tls_load_module_address_p (current_gdbarch)) + if (target != NULL + && gdbarch_fetch_tls_load_module_address_p (target_gdbarch)) { ptid_t ptid = inferior_ptid; volatile struct gdb_exception ex; @@ -822,14 +1021,14 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset) CORE_ADDR lm_addr; /* Fetch the load module address for this objfile. */ - lm_addr = gdbarch_fetch_tls_load_module_address (current_gdbarch, + lm_addr = gdbarch_fetch_tls_load_module_address (target_gdbarch, objfile); /* If it's 0, throw the appropriate exception. */ if (lm_addr == 0) throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR, _("TLS load module not found")); - addr = target_get_thread_local_address (ptid, lm_addr, offset); + addr = target->to_get_thread_local_address (target, ptid, lm_addr, offset); } /* If an error occurred, print TLS related messages here. Otherwise, throw the error to some higher catcher. */ @@ -967,14 +1166,33 @@ done: return nbytes_read; } +struct target_section_table * +target_get_section_table (struct target_ops *target) +{ + struct target_ops *t; + + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_get_section_table ()\n"); + + for (t = target; t != NULL; t = t->beneath) + if (t->to_get_section_table != NULL) + return (*t->to_get_section_table) (t); + + return NULL; +} + /* Find a section containing ADDR. */ -struct section_table * + +struct target_section * target_section_by_addr (struct target_ops *target, CORE_ADDR addr) { - struct section_table *secp; - for (secp = target->to_sections; - secp < target->to_sections_end; - secp++) + struct target_section_table *table = target_get_section_table (target); + struct target_section *secp; + + if (table == NULL) + return NULL; + + for (secp = table->sections; secp < table->sections_end; secp++) { if (addr >= secp->addr && addr < secp->endaddr) return secp; @@ -982,39 +1200,60 @@ target_section_by_addr (struct target_ops *target, CORE_ADDR addr) return NULL; } -/* Perform a partial memory transfer. The arguments and return - value are just as for target_xfer_partial. */ +/* Perform a partial memory transfer. + For docs see target.h, to_xfer_partial. */ static LONGEST -memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf, - ULONGEST memaddr, LONGEST len) +memory_xfer_partial (struct target_ops *ops, enum target_object object, + void *readbuf, const void *writebuf, ULONGEST memaddr, + LONGEST len) { LONGEST res; int reg_len; struct mem_region *region; + struct inferior *inf; /* Zero length requests are ok and require no work. */ if (len == 0) return 0; - /* Try the executable file, if "trust-readonly-sections" is set. */ + /* For accesses to unmapped overlay sections, read directly from + files. Must do this first, as MEMADDR may need adjustment. */ + if (readbuf != NULL && overlay_debugging) + { + struct obj_section *section = find_pc_overlay (memaddr); + if (pc_in_unmapped_range (memaddr, section)) + { + struct target_section_table *table + = target_get_section_table (ops); + const char *section_name = section->the_bfd_section->name; + memaddr = overlay_mapped_address (memaddr, section); + return section_table_xfer_memory_partial (readbuf, writebuf, + memaddr, len, + table->sections, + table->sections_end, + section_name); + } + } + + /* Try the executable files, if "trust-readonly-sections" is set. */ if (readbuf != NULL && trust_readonly) { - struct section_table *secp; + struct target_section *secp; + struct target_section_table *table; secp = target_section_by_addr (ops, memaddr); if (secp != NULL && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section) & SEC_READONLY)) - return xfer_memory (memaddr, readbuf, len, 0, NULL, ops); - } - - /* Likewise for accesses to unmapped overlay sections. */ - if (readbuf != NULL && overlay_debugging) - { - asection *section = find_pc_overlay (memaddr); - if (pc_in_unmapped_range (memaddr, section)) - return xfer_memory (memaddr, readbuf, len, 0, NULL, ops); + { + table = target_get_section_table (ops); + return section_table_xfer_memory_partial (readbuf, writebuf, + memaddr, len, + table->sections, + table->sections_end, + NULL); + } } /* Try GDB's internal data cache. */ @@ -1047,24 +1286,33 @@ memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf return -1; } - if (region->attrib.cache) + if (!ptid_equal (inferior_ptid, null_ptid)) + inf = find_inferior_pid (ptid_get_pid (inferior_ptid)); + else + inf = NULL; + + if (inf != NULL + && (region->attrib.cache + || (stack_cache_enabled_p && object == TARGET_OBJECT_STACK_MEMORY))) { - /* FIXME drow/2006-08-09: This call discards OPS, so the raw - memory request will start back at current_target. */ if (readbuf != NULL) - res = dcache_xfer_memory (target_dcache, memaddr, readbuf, + res = dcache_xfer_memory (ops, target_dcache, memaddr, readbuf, reg_len, 0); else /* FIXME drow/2006-08-09: If we're going to preserve const correctness dcache_xfer_memory should take readbuf and writebuf. */ - res = dcache_xfer_memory (target_dcache, memaddr, + res = dcache_xfer_memory (ops, target_dcache, memaddr, (void *) writebuf, reg_len, 1); if (res <= 0) return -1; else - return res; + { + if (readbuf && !show_memory_breakpoints) + breakpoint_restore_shadows (readbuf, memaddr, reg_len); + return res; + } } /* If none of those methods found the memory we wanted, fall back @@ -1082,22 +1330,57 @@ memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf res = ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL, readbuf, writebuf, memaddr, reg_len); if (res > 0) - return res; + break; /* We want to continue past core files to executables, but not past a running target's memory. */ - if (ops->to_has_all_memory) - return res; + if (ops->to_has_all_memory (ops)) + break; ops = ops->beneath; } while (ops != NULL); + if (readbuf && !show_memory_breakpoints) + breakpoint_restore_shadows (readbuf, memaddr, reg_len); + + /* Make sure the cache gets updated no matter what - if we are writing + to the stack. Even if this write is not tagged as such, we still need + to update the cache. */ + + if (res > 0 + && inf != NULL + && writebuf != NULL + && !region->attrib.cache + && stack_cache_enabled_p + && object != TARGET_OBJECT_STACK_MEMORY) + { + dcache_update (target_dcache, memaddr, (void *) writebuf, res); + } + /* If we still haven't got anything, return the last error. We give up. */ return res; } +static void +restore_show_memory_breakpoints (void *arg) +{ + show_memory_breakpoints = (uintptr_t) arg; +} + +struct cleanup * +make_show_memory_breakpoints_cleanup (int show) +{ + int current = show_memory_breakpoints; + show_memory_breakpoints = show; + + return make_cleanup (restore_show_memory_breakpoints, + (void *) (uintptr_t) current); +} + +/* For docs see target.h, to_xfer_partial. */ + static LONGEST target_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, @@ -1111,8 +1394,9 @@ target_xfer_partial (struct target_ops *ops, /* If this is a memory transfer, let the memory-specific code have a look at it instead. Memory transfers are more complicated. */ - if (object == TARGET_OBJECT_MEMORY) - retval = memory_xfer_partial (ops, readbuf, writebuf, offset, len); + if (object == TARGET_OBJECT_MEMORY || object == TARGET_OBJECT_STACK_MEMORY) + retval = memory_xfer_partial (ops, object, readbuf, + writebuf, offset, len); else { enum target_object raw_object = object; @@ -1131,12 +1415,14 @@ target_xfer_partial (struct target_ops *ops, const unsigned char *myaddr = NULL; fprintf_unfiltered (gdb_stdlog, - "%s:target_xfer_partial (%d, %s, 0x%lx, 0x%lx, 0x%s, %s) = %s", + "%s:target_xfer_partial (%d, %s, %s, %s, %s, %s) = %s", ops->to_shortname, (int) object, (annex ? annex : "(null)"), - (long) readbuf, (long) writebuf, - paddr_nz (offset), paddr_d (len), paddr_d (retval)); + host_address_to_string (readbuf), + host_address_to_string (writebuf), + core_addr_to_string_nz (offset), + plongest (len), plongest (retval)); if (readbuf) myaddr = readbuf; @@ -1149,7 +1435,7 @@ target_xfer_partial (struct target_ops *ops, fputs_unfiltered (", bytes =", gdb_stdlog); for (i = 0; i < retval; i++) { - if ((((long) &(myaddr[i])) & 0xf) == 0) + if ((((intptr_t) &(myaddr[i])) & 0xf) == 0) { if (targetdebug < 2 && i > 0) { @@ -1182,17 +1468,45 @@ target_xfer_partial (struct target_ops *ops, int target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) { - if (target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL, + /* Dispatch to the topmost target, not the flattened current_target. + Memory accesses check target->to_has_(all_)memory, and the + flattened target doesn't inherit those. */ + if (target_read (current_target.beneath, TARGET_OBJECT_MEMORY, NULL, myaddr, memaddr, len) == len) return 0; else return EIO; } +/* Like target_read_memory, but specify explicitly that this is a read from + the target's stack. This may trigger different cache behavior. */ + +int +target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) +{ + /* Dispatch to the topmost target, not the flattened current_target. + Memory accesses check target->to_has_(all_)memory, and the + flattened target doesn't inherit those. */ + + if (target_read (current_target.beneath, TARGET_OBJECT_STACK_MEMORY, NULL, + myaddr, memaddr, len) == len) + return 0; + else + return EIO; +} + +/* Write LEN bytes from MYADDR to target memory at address MEMADDR. + Returns either 0 for success or an errno value if any error occurs. + If an error occurs, no guarantee is made about how much data got written. + Callers that can deal with partial writes should call target_write. */ + int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) { - if (target_write (¤t_target, TARGET_OBJECT_MEMORY, NULL, + /* Dispatch to the topmost target, not the flattened current_target. + Memory accesses check target->to_has_(all_)memory, and the + flattened target doesn't inherit those. */ + if (target_write (current_target.beneath, TARGET_OBJECT_MEMORY, NULL, myaddr, memaddr, len) == len) return 0; else @@ -1257,7 +1571,7 @@ target_flash_erase (ULONGEST address, LONGEST length) { if (targetdebug) fprintf_unfiltered (gdb_stdlog, "target_flash_erase (%s, %s)\n", - paddr (address), phex (length, 0)); + hex_string (address), phex (length, 0)); t->to_flash_erase (t, address, length); return; } @@ -1282,21 +1596,6 @@ target_flash_done (void) tcomplain (); } -#ifndef target_stopped_data_address_p -int -target_stopped_data_address_p (struct target_ops *target) -{ - if (target->to_stopped_data_address - == (int (*) (struct target_ops *, CORE_ADDR *)) return_zero) - return 0; - if (target->to_stopped_data_address == debug_to_stopped_data_address - && (debug_target.to_stopped_data_address - == (int (*) (struct target_ops *, CORE_ADDR *)) return_zero)) - return 0; - return 1; -} -#endif - static void show_trust_readonly (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -1364,11 +1663,7 @@ current_xfer_partial (struct target_ops *ops, enum target_object object, return -1; } -/* Target vector read/write partial wrapper functions. - - NOTE: cagney/2003-10-21: I wonder if having "to_xfer_partial - (inbuf, outbuf)", instead of separate read/write methods, make life - easier. */ +/* Target vector read/write partial wrapper functions. */ static LONGEST target_read_partial (struct target_ops *ops, @@ -1389,6 +1684,9 @@ target_write_partial (struct target_ops *ops, } /* Wrappers to perform the full transfer. */ + +/* For docs on target_read see target.h. */ + LONGEST target_read (struct target_ops *ops, enum target_object object, @@ -1412,6 +1710,71 @@ target_read (struct target_ops *ops, return len; } +LONGEST +target_read_until_error (struct target_ops *ops, + enum target_object object, + const char *annex, gdb_byte *buf, + ULONGEST offset, LONGEST len) +{ + LONGEST xfered = 0; + while (xfered < len) + { + LONGEST xfer = target_read_partial (ops, object, annex, + (gdb_byte *) buf + xfered, + offset + xfered, len - xfered); + /* Call an observer, notifying them of the xfer progress? */ + if (xfer == 0) + return xfered; + if (xfer < 0) + { + /* We've got an error. Try to read in smaller blocks. */ + ULONGEST start = offset + xfered; + ULONGEST remaining = len - xfered; + ULONGEST half; + + /* If an attempt was made to read a random memory address, + it's likely that the very first byte is not accessible. + Try reading the first byte, to avoid doing log N tries + below. */ + xfer = target_read_partial (ops, object, annex, + (gdb_byte *) buf + xfered, start, 1); + if (xfer <= 0) + return xfered; + start += 1; + remaining -= 1; + half = remaining/2; + + while (half > 0) + { + xfer = target_read_partial (ops, object, annex, + (gdb_byte *) buf + xfered, + start, half); + if (xfer == 0) + return xfered; + if (xfer < 0) + { + remaining = half; + } + else + { + /* We have successfully read the first half. So, the + error must be in the second half. Adjust start and + remaining to point at the second half. */ + xfered += xfer; + start += xfer; + remaining -= xfer; + } + half = remaining/2; + } + + return xfered; + } + xfered += xfer; + QUIT; + } + return len; +} + /* An alternative to target_write with progress callbacks. */ LONGEST @@ -1447,6 +1810,8 @@ target_write_with_progress (struct target_ops *ops, return len; } +/* For docs on target_write see target.h. */ + LONGEST target_write (struct target_ops *ops, enum target_object object, @@ -1563,20 +1928,24 @@ void get_target_memory (struct target_ops *ops, CORE_ADDR addr, gdb_byte *buf, LONGEST len) { - if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, buf, addr, len) + /* This method is used to read from an alternate, non-current + target. This read must bypass the overlay support (as symbols + don't match this target), and GDB's internal cache (wrong cache + for this target). */ + if (target_read (ops, TARGET_OBJECT_RAW_MEMORY, NULL, buf, addr, len) != len) memory_error (EIO, addr); } ULONGEST get_target_memory_unsigned (struct target_ops *ops, - CORE_ADDR addr, int len) + CORE_ADDR addr, int len, enum bfd_endian byte_order) { gdb_byte buf[sizeof (ULONGEST)]; gdb_assert (len <= sizeof (buf)); get_target_memory (ops, addr, buf, len); - return extract_unsigned_integer (buf, len); + return extract_unsigned_integer (buf, len, byte_order); } static void @@ -1590,7 +1959,7 @@ target_info (char *args, int from_tty) for (t = target_stack; t != NULL; t = t->beneath) { - if (!t->to_has_memory) + if (!(*t->to_has_memory) (t)) continue; if ((int) (t->to_stratum) <= (int) dummy_stratum) @@ -1599,7 +1968,7 @@ target_info (char *args, int from_tty) printf_unfiltered (_("\tWhile running this, GDB does not access memory from...\n")); printf_unfiltered ("%s:\n", t->to_longname); (t->to_files_info) (t); - has_all_mem = t->to_has_all_memory; + has_all_mem = (*t->to_has_all_memory) (t); } } @@ -1612,9 +1981,57 @@ target_info (char *args, int from_tty) void target_pre_inferior (int from_tty) { - invalidate_target_mem_regions (); + /* Clear out solib state. Otherwise the solib state of the previous + inferior might have survived and is entirely wrong for the new + target. This has been observed on GNU/Linux using glibc 2.3. How + to reproduce: + + bash$ ./foo& + [1] 4711 + bash$ ./foo& + [1] 4712 + bash$ gdb ./foo + [...] + (gdb) attach 4711 + (gdb) detach + (gdb) attach 4712 + Cannot access memory at address 0xdeadbeef + */ + + /* In some OSs, the shared library list is the same/global/shared + across inferiors. If code is shared between processes, so are + memory regions and features. */ + if (!gdbarch_has_global_solist (target_gdbarch)) + { + no_shared_libraries (NULL, from_tty); + + invalidate_target_mem_regions (); + + target_clear_description (); + } +} + +/* Callback for iterate_over_inferiors. Gets rid of the given + inferior. */ + +static int +dispose_inferior (struct inferior *inf, void *args) +{ + struct thread_info *thread; + + thread = any_thread_of_process (inf->pid); + if (thread) + { + switch_to_thread (thread->ptid); + + /* Core inferiors actually should be detached, not killed. */ + if (target_has_execution) + target_kill (); + else + target_detach (NULL, 0); + } - target_clear_description (); + return 0; } /* This is to be called by the open routine before it does @@ -1625,20 +2042,21 @@ target_preopen (int from_tty) { dont_repeat (); - if (target_has_execution) + if (have_inferiors ()) { if (!from_tty - || query (_("A program is being debugged already. Kill it? "))) - target_kill (); + || !have_live_inferiors () + || query (_("A program is being debugged already. Kill it? "))) + iterate_over_inferiors (dispose_inferior, NULL); else error (_("Program not killed.")); } /* Calling target_kill may remove the target from the stack. But if it doesn't (which seems like a win for UDI), remove it now. */ - - if (target_has_execution) - pop_target (); + /* Leave the exec target, though. The user may be switching from a + live process to a core of the same program. */ + pop_all_targets_above (file_stratum, 0); target_pre_inferior (from_tty); } @@ -1648,7 +2066,32 @@ target_preopen (int from_tty) void target_detach (char *args, int from_tty) { - (current_target.to_detach) (args, from_tty); + struct target_ops* t; + + if (gdbarch_has_global_breakpoints (target_gdbarch)) + /* Don't remove global breakpoints here. They're removed on + disconnection from the target. */ + ; + else + /* If we're in breakpoints-always-inserted mode, have to remove + them before detaching. */ + remove_breakpoints_pid (PIDGET (inferior_ptid)); + + prepare_for_detach (); + + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_detach != NULL) + { + t->to_detach (t, args, from_tty); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_detach (%s, %d)\n", + args, from_tty); + return; + } + } + + internal_error (__FILE__, __LINE__, "could not find a target to detach"); } void @@ -1656,6 +2099,11 @@ target_disconnect (char *args, int from_tty) { struct target_ops *t; + /* If we're in breakpoints-always-inserted mode or if breakpoints + are global across processes, we have to remove them before + disconnecting. */ + remove_breakpoints (); + for (t = current_target.beneath; t != NULL; t = t->beneath) if (t->to_disconnect != NULL) { @@ -1669,14 +2117,77 @@ target_disconnect (char *args, int from_tty) tcomplain (); } -int -target_async_mask (int mask) +ptid_t +target_wait (ptid_t ptid, struct target_waitstatus *status, int options) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_wait != NULL) + { + ptid_t retval = (*t->to_wait) (t, ptid, status, options); + + if (targetdebug) + { + char *status_string; + + status_string = target_waitstatus_to_string (status); + fprintf_unfiltered (gdb_stdlog, + "target_wait (%d, status) = %d, %s\n", + PIDGET (ptid), PIDGET (retval), + status_string); + xfree (status_string); + } + + return retval; + } + } + + noprocess (); +} + +char * +target_pid_to_str (ptid_t ptid) { - int saved_async_masked_status = target_async_mask_value; - target_async_mask_value = mask; - return saved_async_masked_status; + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_pid_to_str != NULL) + return (*t->to_pid_to_str) (t, ptid); + } + + return normal_pid_to_str (ptid); } +void +target_resume (ptid_t ptid, int step, enum target_signal signal) +{ + struct target_ops *t; + + target_dcache_invalidate (); + + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_resume != NULL) + { + t->to_resume (t, ptid, step, signal); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_resume (%d, %s, %s)\n", + PIDGET (ptid), + step ? "step" : "continue", + target_signal_to_name (signal)); + + set_executing (ptid, 1); + set_running (ptid, 1); + clear_inline_frame_state (ptid); + return; + } + } + + noprocess (); +} /* Look through the list of possible targets for a target that can follow forks. */ @@ -1702,6 +2213,31 @@ target_follow_fork (int follow_child) "could not find a target to follow fork"); } +void +target_mourn_inferior (void) +{ + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_mourn_inferior != NULL) + { + t->to_mourn_inferior (t); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_mourn_inferior ()\n"); + + /* We no longer need to keep handles on any of the object files. + Make sure to release them to avoid unnecessarily locking any + of them while we're not actually debugging. */ + bfd_cache_close_all (); + + return; + } + } + + internal_error (__FILE__, __LINE__, + "could not find a target to follow mourn inferiour"); +} + /* Look for a target which can describe architectural features, starting from TARGET. If we find one, return its description. */ @@ -1720,7 +2256,158 @@ target_read_description (struct target_ops *target) return tdesc; } - return NULL; + return NULL; +} + +/* The default implementation of to_search_memory. + This implements a basic search of memory, reading target memory and + performing the search here (as opposed to performing the search in on the + target side with, for example, gdbserver). */ + +int +simple_search_memory (struct target_ops *ops, + CORE_ADDR start_addr, ULONGEST search_space_len, + const gdb_byte *pattern, ULONGEST pattern_len, + CORE_ADDR *found_addrp) +{ + /* NOTE: also defined in find.c testcase. */ +#define SEARCH_CHUNK_SIZE 16000 + const unsigned chunk_size = SEARCH_CHUNK_SIZE; + /* Buffer to hold memory contents for searching. */ + gdb_byte *search_buf; + unsigned search_buf_size; + struct cleanup *old_cleanups; + + search_buf_size = chunk_size + pattern_len - 1; + + /* No point in trying to allocate a buffer larger than the search space. */ + if (search_space_len < search_buf_size) + search_buf_size = search_space_len; + + search_buf = malloc (search_buf_size); + if (search_buf == NULL) + error (_("Unable to allocate memory to perform the search.")); + old_cleanups = make_cleanup (free_current_contents, &search_buf); + + /* Prime the search buffer. */ + + if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, + search_buf, start_addr, search_buf_size) != search_buf_size) + { + warning (_("Unable to access target memory at %s, halting search."), + hex_string (start_addr)); + do_cleanups (old_cleanups); + return -1; + } + + /* Perform the search. + + The loop is kept simple by allocating [N + pattern-length - 1] bytes. + When we've scanned N bytes we copy the trailing bytes to the start and + read in another N bytes. */ + + while (search_space_len >= pattern_len) + { + gdb_byte *found_ptr; + unsigned nr_search_bytes = min (search_space_len, search_buf_size); + + found_ptr = memmem (search_buf, nr_search_bytes, + pattern, pattern_len); + + if (found_ptr != NULL) + { + CORE_ADDR found_addr = start_addr + (found_ptr - search_buf); + *found_addrp = found_addr; + do_cleanups (old_cleanups); + return 1; + } + + /* Not found in this chunk, skip to next chunk. */ + + /* Don't let search_space_len wrap here, it's unsigned. */ + if (search_space_len >= chunk_size) + search_space_len -= chunk_size; + else + search_space_len = 0; + + if (search_space_len >= pattern_len) + { + unsigned keep_len = search_buf_size - chunk_size; + CORE_ADDR read_addr = start_addr + chunk_size + keep_len; + int nr_to_read; + + /* Copy the trailing part of the previous iteration to the front + of the buffer for the next iteration. */ + gdb_assert (keep_len == pattern_len - 1); + memcpy (search_buf, search_buf + chunk_size, keep_len); + + nr_to_read = min (search_space_len - keep_len, chunk_size); + + if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, + search_buf + keep_len, read_addr, + nr_to_read) != nr_to_read) + { + warning (_("Unable to access target memory at %s, halting search."), + hex_string (read_addr)); + do_cleanups (old_cleanups); + return -1; + } + + start_addr += chunk_size; + } + } + + /* Not found. */ + + do_cleanups (old_cleanups); + return 0; +} + +/* Search SEARCH_SPACE_LEN bytes beginning at START_ADDR for the + sequence of bytes in PATTERN with length PATTERN_LEN. + + The result is 1 if found, 0 if not found, and -1 if there was an error + requiring halting of the search (e.g. memory read error). + If the pattern is found the address is recorded in FOUND_ADDRP. */ + +int +target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len, + const gdb_byte *pattern, ULONGEST pattern_len, + CORE_ADDR *found_addrp) +{ + struct target_ops *t; + int found; + + /* We don't use INHERIT to set current_target.to_search_memory, + so we have to scan the target stack and handle targetdebug + ourselves. */ + + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_search_memory (%s, ...)\n", + hex_string (start_addr)); + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_search_memory != NULL) + break; + + if (t != NULL) + { + found = t->to_search_memory (t, start_addr, search_space_len, + pattern, pattern_len, found_addrp); + } + else + { + /* If a special version of to_search_memory isn't available, use the + simple version. */ + found = simple_search_memory (current_target.beneath, + start_addr, search_space_len, + pattern, pattern_len, found_addrp); + } + + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, " = %d\n", found); + + return found; } /* Look through the currently pushed targets. If none of them will @@ -1744,7 +2431,8 @@ target_require_runnable (void) /* Do not worry about thread_stratum targets that can not create inferiors. Assume they will be pushed again if necessary, and continue to the process_stratum. */ - if (t->to_stratum == thread_stratum) + if (t->to_stratum == thread_stratum + || t->to_stratum == arch_stratum) continue; error (_("\ @@ -1762,7 +2450,8 @@ The \"%s\" target does not support \"run\". Try \"help target\" or \"continue\" execute a run or attach command without any other data. This is used to locate the default process stratum. - Result is always valid (error() is called for errors). */ + If DO_MESG is not NULL, the result is always valid (error() is + called for errors); else, return NULL on error. */ static struct target_ops * find_default_run_target (char *do_mesg) @@ -1784,145 +2473,184 @@ find_default_run_target (char *do_mesg) } if (count != 1) - error (_("Don't know how to %s. Try \"help target\"."), do_mesg); + { + if (do_mesg) + error (_("Don't know how to %s. Try \"help target\"."), do_mesg); + else + return NULL; + } return runable; } void -find_default_attach (char *args, int from_tty) +find_default_attach (struct target_ops *ops, char *args, int from_tty) { struct target_ops *t; t = find_default_run_target ("attach"); - (t->to_attach) (args, from_tty); + (t->to_attach) (t, args, from_tty); return; } void -find_default_create_inferior (char *exec_file, char *allargs, char **env, +find_default_create_inferior (struct target_ops *ops, + char *exec_file, char *allargs, char **env, int from_tty) { struct target_ops *t; t = find_default_run_target ("run"); - (t->to_create_inferior) (exec_file, allargs, env, from_tty); + (t->to_create_inferior) (t, exec_file, allargs, env, from_tty); return; } static int -default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +find_default_can_async_p (void) { - return (len <= TYPE_LENGTH (builtin_type_void_data_ptr)); + struct target_ops *t; + + /* This may be called before the target is pushed on the stack; + look for the default process stratum. If there's none, gdb isn't + configured with a native debugger, and target remote isn't + connected yet. */ + t = find_default_run_target (NULL); + if (t && t->to_can_async_p) + return (t->to_can_async_p) (); + return 0; } static int -return_zero (void) +find_default_is_async_p (void) { + struct target_ops *t; + + /* This may be called before the target is pushed on the stack; + look for the default process stratum. If there's none, gdb isn't + configured with a native debugger, and target remote isn't + connected yet. */ + t = find_default_run_target (NULL); + if (t && t->to_is_async_p) + return (t->to_is_async_p) (); return 0; } static int -return_one (void) +find_default_supports_non_stop (void) { - return 1; + struct target_ops *t; + + t = find_default_run_target (NULL); + if (t && t->to_supports_non_stop) + return (t->to_supports_non_stop) (); + return 0; } -static int -return_minus_one (void) +int +target_supports_non_stop (void) { - return -1; + struct target_ops *t; + for (t = ¤t_target; t != NULL; t = t->beneath) + if (t->to_supports_non_stop) + return t->to_supports_non_stop (); + + return 0; } -/* - * Resize the to_sections pointer. Also make sure that anyone that - * was holding on to an old value of it gets updated. - * Returns the old size. - */ -int -target_resize_to_sections (struct target_ops *target, int num_added) +char * +target_get_osdata (const char *type) { - struct target_ops **t; - struct section_table *old_value; - int old_count; - - old_value = target->to_sections; + char *document; + struct target_ops *t; - if (target->to_sections) - { - old_count = target->to_sections_end - target->to_sections; - target->to_sections = (struct section_table *) - xrealloc ((char *) target->to_sections, - (sizeof (struct section_table)) * (num_added + old_count)); - } + /* If we're already connected to something that can get us OS + related data, use it. Otherwise, try using the native + target. */ + if (current_target.to_stratum >= process_stratum) + t = current_target.beneath; else - { - old_count = 0; - target->to_sections = (struct section_table *) - xmalloc ((sizeof (struct section_table)) * num_added); - } - target->to_sections_end = target->to_sections + (num_added + old_count); + t = find_default_run_target ("get OS data"); + + if (!t) + return NULL; - /* Check to see if anyone else was pointing to this structure. - If old_value was null, then no one was. */ + return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type); +} + +/* Determine the current address space of thread PTID. */ + +struct address_space * +target_thread_address_space (ptid_t ptid) +{ + struct address_space *aspace; + struct inferior *inf; + struct target_ops *t; - if (old_value) + for (t = current_target.beneath; t != NULL; t = t->beneath) { - for (t = target_structs; t < target_structs + target_struct_size; - ++t) - { - if ((*t)->to_sections == old_value) - { - (*t)->to_sections = target->to_sections; - (*t)->to_sections_end = target->to_sections_end; - } - } - /* There is a flattened view of the target stack in current_target, - so its to_sections pointer might also need updating. */ - if (current_target.to_sections == old_value) + if (t->to_thread_address_space != NULL) { - current_target.to_sections = target->to_sections; - current_target.to_sections_end = target->to_sections_end; + aspace = t->to_thread_address_space (t, ptid); + gdb_assert (aspace); + + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, + "target_thread_address_space (%s) = %d\n", + target_pid_to_str (ptid), + address_space_num (aspace)); + return aspace; } } - return old_count; + /* Fall-back to the "main" address space of the inferior. */ + inf = find_inferior_pid (ptid_get_pid (ptid)); + if (inf == NULL || inf->aspace == NULL) + internal_error (__FILE__, __LINE__, "\ +Can't determine the current address space of thread %s\n", + target_pid_to_str (ptid)); + + return inf->aspace; } -/* Remove all target sections taken from ABFD. +static int +default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +{ + return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT); +} - Scan the current target stack for targets whose section tables - refer to sections from BFD, and remove those sections. We use this - when we notice that the inferior has unloaded a shared object, for - example. */ -void -remove_target_sections (bfd *abfd) +static int +default_watchpoint_addr_within_range (struct target_ops *target, + CORE_ADDR addr, + CORE_ADDR start, int length) { - struct target_ops **t; + return addr >= start && addr < start + length; +} - for (t = target_structs; t < target_structs + target_struct_size; t++) - { - struct section_table *src, *dest; - - dest = (*t)->to_sections; - for (src = (*t)->to_sections; src < (*t)->to_sections_end; src++) - if (src->bfd != abfd) - { - /* Keep this section. */ - if (dest < src) *dest = *src; - dest++; - } - - /* If we've dropped any sections, resize the section table. */ - if (dest < src) - target_resize_to_sections (*t, dest - src); - } +static struct gdbarch * +default_thread_architecture (struct target_ops *ops, ptid_t ptid) +{ + return target_gdbarch; } +static int +return_zero (void) +{ + return 0; +} +static int +return_one (void) +{ + return 1; +} +static int +return_minus_one (void) +{ + return -1; +} /* Find a single runnable target in the stack and return it. If for some reason there is more than one, return NULL. */ @@ -1989,23 +2717,23 @@ find_target_beneath (struct target_ops *t) void generic_mourn_inferior (void) { - extern int show_breakpoint_hit_counts; + ptid_t ptid; + ptid = inferior_ptid; inferior_ptid = null_ptid; - attach_flag = 0; + + if (!ptid_equal (ptid, null_ptid)) + { + int pid = ptid_get_pid (ptid); + exit_inferior (pid); + } + breakpoint_init_inferior (inf_exited); registers_changed (); reopen_exec_file (); reinit_frame_cache (); - /* It is confusing to the user for ignore counts to stick around - from previous runs of the inferior. So clear them. */ - /* However, it is more confusing for the ignore counts to disappear when - using hit counts. So don't clear them if we're counting hits. */ - if (!show_breakpoint_hit_counts) - breakpoint_clear_ignore_counts (); - if (deprecated_detach_hook) deprecated_detach_hook (); } @@ -2033,10 +2761,6 @@ store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) } } -/* Returns zero to leave the inferior alone, one to interrupt it. */ -int (*target_activity_function) (void); -int target_activity_fd; - /* Convert a normal process ID to a string. Returns the string in a static buffer. */ @@ -2049,20 +2773,43 @@ normal_pid_to_str (ptid_t ptid) return buf; } -/* Error-catcher for target_find_memory_regions */ -static int dummy_find_memory_regions (int (*ignore1) (), void *ignore2) +static char * +dummy_pid_to_str (struct target_ops *ops, ptid_t ptid) +{ + return normal_pid_to_str (ptid); +} + +/* Error-catcher for target_find_memory_regions. */ +static int +dummy_find_memory_regions (int (*ignore1) (), void *ignore2) { - error (_("No target.")); + error (_("Command not implemented for this target.")); return 0; } -/* Error-catcher for target_make_corefile_notes */ -static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2) +/* Error-catcher for target_make_corefile_notes. */ +static char * +dummy_make_corefile_notes (bfd *ignore1, int *ignore2) +{ + error (_("Command not implemented for this target.")); + return NULL; +} + +/* Error-catcher for target_get_bookmark. */ +static gdb_byte * +dummy_get_bookmark (char *ignore1, int ignore2) { - error (_("No target.")); + tcomplain (); return NULL; } +/* Error-catcher for target_goto_bookmark. */ +static void +dummy_goto_bookmark (gdb_byte *ignore, int from_tty) +{ + tcomplain (); +} + /* Set up the handful of non-empty slots needed by the dummy target vector. */ @@ -2073,12 +2820,27 @@ init_dummy_target (void) dummy_target.to_longname = "None"; dummy_target.to_doc = ""; dummy_target.to_attach = find_default_attach; + dummy_target.to_detach = + (void (*)(struct target_ops *, char *, int))target_ignore; dummy_target.to_create_inferior = find_default_create_inferior; - dummy_target.to_pid_to_str = normal_pid_to_str; + dummy_target.to_can_async_p = find_default_can_async_p; + dummy_target.to_is_async_p = find_default_is_async_p; + dummy_target.to_supports_non_stop = find_default_supports_non_stop; + dummy_target.to_pid_to_str = dummy_pid_to_str; dummy_target.to_stratum = dummy_stratum; dummy_target.to_find_memory_regions = dummy_find_memory_regions; dummy_target.to_make_corefile_notes = dummy_make_corefile_notes; + dummy_target.to_get_bookmark = dummy_get_bookmark; + dummy_target.to_goto_bookmark = dummy_goto_bookmark; dummy_target.to_xfer_partial = default_xfer_partial; + dummy_target.to_has_all_memory = (int (*) (struct target_ops *)) return_zero; + dummy_target.to_has_memory = (int (*) (struct target_ops *)) return_zero; + dummy_target.to_has_stack = (int (*) (struct target_ops *)) return_zero; + dummy_target.to_has_registers = (int (*) (struct target_ops *)) return_zero; + dummy_target.to_has_execution = (int (*) (struct target_ops *)) return_zero; + dummy_target.to_stopped_by_watchpoint = return_zero; + dummy_target.to_stopped_data_address = + (int (*) (struct target_ops *, CORE_ADDR *)) return_zero; dummy_target.to_magic = OPS_MAGIC; } @@ -2090,13 +2852,6 @@ debug_to_open (char *args, int from_tty) fprintf_unfiltered (gdb_stdlog, "target_open (%s, %d)\n", args, from_tty); } -static void -debug_to_close (int quitting) -{ - target_close (&debug_target, quitting); - fprintf_unfiltered (gdb_stdlog, "target_close (%d)\n", quitting); -} - void target_close (struct target_ops *targ, int quitting) { @@ -2104,89 +2859,118 @@ target_close (struct target_ops *targ, int quitting) targ->to_xclose (targ, quitting); else if (targ->to_close != NULL) targ->to_close (quitting); + + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_close (%d)\n", quitting); } -static void -debug_to_attach (char *args, int from_tty) +void +target_attach (char *args, int from_tty) { - debug_target.to_attach (args, from_tty); + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_attach != NULL) + { + t->to_attach (t, args, from_tty); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_attach (%s, %d)\n", + args, from_tty); + return; + } + } - fprintf_unfiltered (gdb_stdlog, "target_attach (%s, %d)\n", args, from_tty); + internal_error (__FILE__, __LINE__, + "could not find a target to attach"); } - -static void -debug_to_post_attach (int pid) +int +target_thread_alive (ptid_t ptid) { - debug_target.to_post_attach (pid); + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_thread_alive != NULL) + { + int retval; - fprintf_unfiltered (gdb_stdlog, "target_post_attach (%d)\n", pid); + retval = t->to_thread_alive (t, ptid); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_thread_alive (%d) = %d\n", + PIDGET (ptid), retval); + + return retval; + } + } + + return 0; } -static void -debug_to_detach (char *args, int from_tty) +void +target_find_new_threads (void) { - debug_target.to_detach (args, from_tty); + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_find_new_threads != NULL) + { + t->to_find_new_threads (t); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_find_new_threads ()\n"); - fprintf_unfiltered (gdb_stdlog, "target_detach (%s, %d)\n", args, from_tty); + return; + } + } } static void -debug_to_resume (ptid_t ptid, int step, enum target_signal siggnal) +debug_to_post_attach (int pid) { - debug_target.to_resume (ptid, step, siggnal); + debug_target.to_post_attach (pid); - fprintf_unfiltered (gdb_stdlog, "target_resume (%d, %s, %s)\n", PIDGET (ptid), - step ? "step" : "continue", - target_signal_to_name (siggnal)); + fprintf_unfiltered (gdb_stdlog, "target_post_attach (%d)\n", pid); } -static ptid_t -debug_to_wait (ptid_t ptid, struct target_waitstatus *status) -{ - ptid_t retval; +/* Return a pretty printed form of target_waitstatus. + Space for the result is malloc'd, caller must free. */ - retval = debug_target.to_wait (ptid, status); +char * +target_waitstatus_to_string (const struct target_waitstatus *ws) +{ + const char *kind_str = "status->kind = "; - fprintf_unfiltered (gdb_stdlog, - "target_wait (%d, status) = %d, ", PIDGET (ptid), - PIDGET (retval)); - fprintf_unfiltered (gdb_stdlog, "status->kind = "); - switch (status->kind) + switch (ws->kind) { case TARGET_WAITKIND_EXITED: - fprintf_unfiltered (gdb_stdlog, "exited, status = %d\n", - status->value.integer); - break; + return xstrprintf ("%sexited, status = %d", + kind_str, ws->value.integer); case TARGET_WAITKIND_STOPPED: - fprintf_unfiltered (gdb_stdlog, "stopped, signal = %s\n", - target_signal_to_name (status->value.sig)); - break; + return xstrprintf ("%sstopped, signal = %s", + kind_str, target_signal_to_name (ws->value.sig)); case TARGET_WAITKIND_SIGNALLED: - fprintf_unfiltered (gdb_stdlog, "signalled, signal = %s\n", - target_signal_to_name (status->value.sig)); - break; + return xstrprintf ("%ssignalled, signal = %s", + kind_str, target_signal_to_name (ws->value.sig)); case TARGET_WAITKIND_LOADED: - fprintf_unfiltered (gdb_stdlog, "loaded\n"); - break; + return xstrprintf ("%sloaded", kind_str); case TARGET_WAITKIND_FORKED: - fprintf_unfiltered (gdb_stdlog, "forked\n"); - break; + return xstrprintf ("%sforked", kind_str); case TARGET_WAITKIND_VFORKED: - fprintf_unfiltered (gdb_stdlog, "vforked\n"); - break; + return xstrprintf ("%svforked", kind_str); case TARGET_WAITKIND_EXECD: - fprintf_unfiltered (gdb_stdlog, "execd\n"); - break; + return xstrprintf ("%sexecd", kind_str); + case TARGET_WAITKIND_SYSCALL_ENTRY: + return xstrprintf ("%sentered syscall", kind_str); + case TARGET_WAITKIND_SYSCALL_RETURN: + return xstrprintf ("%sexited syscall", kind_str); case TARGET_WAITKIND_SPURIOUS: - fprintf_unfiltered (gdb_stdlog, "spurious\n"); - break; + return xstrprintf ("%sspurious", kind_str); + case TARGET_WAITKIND_IGNORE: + return xstrprintf ("%signore", kind_str); + case TARGET_WAITKIND_NO_HISTORY: + return xstrprintf ("%sno-history", kind_str); default: - fprintf_unfiltered (gdb_stdlog, "unknown???\n"); - break; + return xstrprintf ("%sunknown???", kind_str); } - - return retval; } static void @@ -2196,18 +2980,18 @@ debug_print_register (const char * func, struct gdbarch *gdbarch = get_regcache_arch (regcache); fprintf_unfiltered (gdb_stdlog, "%s ", func); if (regno >= 0 && regno < gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch) && gdbarch_register_name (gdbarch, regno) != NULL && gdbarch_register_name (gdbarch, regno)[0] != '\0') fprintf_unfiltered (gdb_stdlog, "(%s)", gdbarch_register_name (gdbarch, regno)); else fprintf_unfiltered (gdb_stdlog, "(%d)", regno); - if (regno >= 0) + if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)) { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int i, size = register_size (gdbarch, regno); unsigned char buf[MAX_REGISTER_SIZE]; - regcache_cooked_read (regcache, regno, buf); + regcache_raw_collect (regcache, regno, buf); fprintf_unfiltered (gdb_stdlog, " = "); for (i = 0; i < size; i++) { @@ -2215,27 +2999,69 @@ debug_print_register (const char * func, } if (size <= sizeof (LONGEST)) { - ULONGEST val = extract_unsigned_integer (buf, size); - fprintf_unfiltered (gdb_stdlog, " 0x%s %s", - paddr_nz (val), paddr_d (val)); + ULONGEST val = extract_unsigned_integer (buf, size, byte_order); + fprintf_unfiltered (gdb_stdlog, " %s %s", + core_addr_to_string_nz (val), plongest (val)); } } fprintf_unfiltered (gdb_stdlog, "\n"); } -static void -debug_to_fetch_registers (struct regcache *regcache, int regno) +void +target_fetch_registers (struct regcache *regcache, int regno) { - debug_target.to_fetch_registers (regcache, regno); - debug_print_register ("target_fetch_registers", regcache, regno); + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_fetch_registers != NULL) + { + t->to_fetch_registers (t, regcache, regno); + if (targetdebug) + debug_print_register ("target_fetch_registers", regcache, regno); + return; + } + } } -static void -debug_to_store_registers (struct regcache *regcache, int regno) +void +target_store_registers (struct regcache *regcache, int regno) { - debug_target.to_store_registers (regcache, regno); - debug_print_register ("target_store_registers", regcache, regno); - fprintf_unfiltered (gdb_stdlog, "\n"); + + struct target_ops *t; + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_store_registers != NULL) + { + t->to_store_registers (t, regcache, regno); + if (targetdebug) + { + debug_print_register ("target_store_registers", regcache, regno); + } + return; + } + } + + noprocess (); +} + +int +target_core_of_thread (ptid_t ptid) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_core_of_thread != NULL) + { + int retval = t->to_core_of_thread (t, ptid); + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, "target_core_of_thread (%d) = %d\n", + PIDGET (ptid), retval); + return retval; + } + } + + return -1; } static void @@ -2257,9 +3083,9 @@ deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, int len, attrib, target); fprintf_unfiltered (gdb_stdlog, - "target_xfer_memory (0x%x, xxx, %d, %s, xxx) = %d", - (unsigned int) memaddr, /* possable truncate long long */ - len, write ? "write" : "read", retval); + "target_xfer_memory (%s, xxx, %d, %s, xxx) = %d", + paddress (target_gdbarch, memaddr), len, + write ? "write" : "read", retval); if (retval > 0) { @@ -2268,7 +3094,7 @@ deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, int len, fputs_unfiltered (", bytes =", gdb_stdlog); for (i = 0; i < retval; i++) { - if ((((long) &(myaddr[i])) & 0xf) == 0) + if ((((intptr_t) &(myaddr[i])) & 0xf) == 0) { if (targetdebug < 2 && i > 0) { @@ -2296,11 +3122,12 @@ debug_to_files_info (struct target_ops *target) } static int -debug_to_insert_breakpoint (struct bp_target_info *bp_tgt) +debug_to_insert_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { int retval; - retval = debug_target.to_insert_breakpoint (bp_tgt); + retval = debug_target.to_insert_breakpoint (gdbarch, bp_tgt); fprintf_unfiltered (gdb_stdlog, "target_insert_breakpoint (0x%lx, xxx) = %ld\n", @@ -2310,11 +3137,12 @@ debug_to_insert_breakpoint (struct bp_target_info *bp_tgt) } static int -debug_to_remove_breakpoint (struct bp_target_info *bp_tgt) +debug_to_remove_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { int retval; - retval = debug_target.to_remove_breakpoint (bp_tgt); + retval = debug_target.to_remove_breakpoint (gdbarch, bp_tgt); fprintf_unfiltered (gdb_stdlog, "target_remove_breakpoint (0x%lx, xxx) = %ld\n", @@ -2347,7 +3175,7 @@ debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len); fprintf_unfiltered (gdb_stdlog, - "TARGET_REGION_OK_FOR_HW_WATCHPOINT (%ld, %ld) = 0x%lx\n", + "target_region_ok_for_hw_watchpoint (%ld, %ld) = 0x%lx\n", (unsigned long) addr, (unsigned long) len, (unsigned long) retval); @@ -2362,7 +3190,7 @@ debug_to_stopped_by_watchpoint (void) retval = debug_target.to_stopped_by_watchpoint (); fprintf_unfiltered (gdb_stdlog, - "STOPPED_BY_WATCHPOINT () = %ld\n", + "target_stopped_by_watchpoint () = %ld\n", (unsigned long) retval); return retval; } @@ -2382,11 +3210,29 @@ debug_to_stopped_data_address (struct target_ops *target, CORE_ADDR *addr) } static int -debug_to_insert_hw_breakpoint (struct bp_target_info *bp_tgt) +debug_to_watchpoint_addr_within_range (struct target_ops *target, + CORE_ADDR addr, + CORE_ADDR start, int length) +{ + int retval; + + retval = debug_target.to_watchpoint_addr_within_range (target, addr, + start, length); + + fprintf_filtered (gdb_stdlog, + "target_watchpoint_addr_within_range (0x%lx, 0x%lx, %d) = %d\n", + (unsigned long) addr, (unsigned long) start, length, + retval); + return retval; +} + +static int +debug_to_insert_hw_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { int retval; - retval = debug_target.to_insert_hw_breakpoint (bp_tgt); + retval = debug_target.to_insert_hw_breakpoint (gdbarch, bp_tgt); fprintf_unfiltered (gdb_stdlog, "target_insert_hw_breakpoint (0x%lx, xxx) = %ld\n", @@ -2396,11 +3242,12 @@ debug_to_insert_hw_breakpoint (struct bp_target_info *bp_tgt) } static int -debug_to_remove_hw_breakpoint (struct bp_target_info *bp_tgt) +debug_to_remove_hw_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { int retval; - retval = debug_target.to_remove_hw_breakpoint (bp_tgt); + retval = debug_target.to_remove_hw_breakpoint (gdbarch, bp_tgt); fprintf_unfiltered (gdb_stdlog, "target_remove_hw_breakpoint (0x%lx, xxx) = %ld\n", @@ -2484,14 +3331,6 @@ debug_to_terminal_info (char *arg, int from_tty) from_tty); } -static void -debug_to_kill (void) -{ - debug_target.to_kill (); - - fprintf_unfiltered (gdb_stdlog, "target_kill ()\n"); -} - static void debug_to_load (char *args, int from_tty) { @@ -2512,16 +3351,6 @@ debug_to_lookup_symbol (char *name, CORE_ADDR *addrp) return retval; } -static void -debug_to_create_inferior (char *exec_file, char *args, char **env, - int from_tty) -{ - debug_target.to_create_inferior (exec_file, args, env, from_tty); - - fprintf_unfiltered (gdb_stdlog, "target_create_inferior (%s, %s, xxx, %d)\n", - exec_file, args, from_tty); -} - static void debug_to_post_startup_inferior (ptid_t ptid) { @@ -2606,20 +3435,6 @@ debug_to_remove_exec_catchpoint (int pid) return retval; } -static int -debug_to_reported_exec_events_per_exec_call (void) -{ - int reported_exec_events; - - reported_exec_events = debug_target.to_reported_exec_events_per_exec_call (); - - fprintf_unfiltered (gdb_stdlog, - "target_reported_exec_events_per_exec_call () = %d\n", - reported_exec_events); - - return reported_exec_events; -} - static int debug_to_has_exited (int pid, int wait_status, int *exit_status) { @@ -2633,14 +3448,6 @@ debug_to_has_exited (int pid, int wait_status, int *exit_status) return has_exited; } -static void -debug_to_mourn_inferior (void) -{ - debug_target.to_mourn_inferior (); - - fprintf_unfiltered (gdb_stdlog, "target_mourn_inferior ()\n"); -} - static int debug_to_can_run (void) { @@ -2662,33 +3469,26 @@ debug_to_notice_signals (ptid_t ptid) PIDGET (ptid)); } -static int -debug_to_thread_alive (ptid_t ptid) +static struct gdbarch * +debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid) { - int retval; + struct gdbarch *retval; - retval = debug_target.to_thread_alive (ptid); - - fprintf_unfiltered (gdb_stdlog, "target_thread_alive (%d) = %d\n", - PIDGET (ptid), retval); + retval = debug_target.to_thread_architecture (ops, ptid); + fprintf_unfiltered (gdb_stdlog, "target_thread_architecture (%s) = %s [%s]\n", + target_pid_to_str (ptid), host_address_to_string (retval), + gdbarch_bfd_arch_info (retval)->printable_name); return retval; } static void -debug_to_find_new_threads (void) -{ - debug_target.to_find_new_threads (); - - fputs_unfiltered ("target_find_new_threads ()\n", gdb_stdlog); -} - -static void -debug_to_stop (void) +debug_to_stop (ptid_t ptid) { - debug_target.to_stop (); + debug_target.to_stop (ptid); - fprintf_unfiltered (gdb_stdlog, "target_stop ()\n"); + fprintf_unfiltered (gdb_stdlog, "target_stop (%s)\n", + target_pid_to_str (ptid)); } static void @@ -2718,14 +3518,7 @@ setup_target_debug (void) memcpy (&debug_target, ¤t_target, sizeof debug_target); current_target.to_open = debug_to_open; - current_target.to_close = debug_to_close; - current_target.to_attach = debug_to_attach; current_target.to_post_attach = debug_to_post_attach; - current_target.to_detach = debug_to_detach; - current_target.to_resume = debug_to_resume; - current_target.to_wait = debug_to_wait; - current_target.to_fetch_registers = debug_to_fetch_registers; - current_target.to_store_registers = debug_to_store_registers; current_target.to_prepare_to_store = debug_to_prepare_to_store; current_target.deprecated_xfer_memory = deprecated_debug_xfer_memory; current_target.to_files_info = debug_to_files_info; @@ -2738,6 +3531,7 @@ setup_target_debug (void) current_target.to_remove_watchpoint = debug_to_remove_watchpoint; current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint; current_target.to_stopped_data_address = debug_to_stopped_data_address; + current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range; current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint; current_target.to_terminal_init = debug_to_terminal_init; current_target.to_terminal_inferior = debug_to_terminal_inferior; @@ -2745,10 +3539,8 @@ setup_target_debug (void) current_target.to_terminal_ours = debug_to_terminal_ours; current_target.to_terminal_save_ours = debug_to_terminal_save_ours; current_target.to_terminal_info = debug_to_terminal_info; - current_target.to_kill = debug_to_kill; current_target.to_load = debug_to_load; current_target.to_lookup_symbol = debug_to_lookup_symbol; - current_target.to_create_inferior = debug_to_create_inferior; current_target.to_post_startup_inferior = debug_to_post_startup_inferior; current_target.to_acknowledge_created_inferior = debug_to_acknowledge_created_inferior; current_target.to_insert_fork_catchpoint = debug_to_insert_fork_catchpoint; @@ -2757,16 +3549,13 @@ setup_target_debug (void) current_target.to_remove_vfork_catchpoint = debug_to_remove_vfork_catchpoint; current_target.to_insert_exec_catchpoint = debug_to_insert_exec_catchpoint; current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint; - current_target.to_reported_exec_events_per_exec_call = debug_to_reported_exec_events_per_exec_call; current_target.to_has_exited = debug_to_has_exited; - current_target.to_mourn_inferior = debug_to_mourn_inferior; current_target.to_can_run = debug_to_can_run; current_target.to_notice_signals = debug_to_notice_signals; - current_target.to_thread_alive = debug_to_thread_alive; - current_target.to_find_new_threads = debug_to_find_new_threads; current_target.to_stop = debug_to_stop; current_target.to_rcmd = debug_to_rcmd; current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file; + current_target.to_thread_architecture = debug_to_thread_architecture; } @@ -2803,6 +3592,35 @@ maintenance_print_target_stack (char *cmd, int from_tty) } } +/* Controls if async mode is permitted. */ +int target_async_permitted = 0; + +/* The set command writes to this variable. If the inferior is + executing, linux_nat_async_permitted is *not* updated. */ +static int target_async_permitted_1 = 0; + +static void +set_maintenance_target_async_permitted (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (have_live_inferiors ()) + { + target_async_permitted_1 = target_async_permitted; + error (_("Cannot change this setting while the inferior is running.")); + } + + target_async_permitted = target_async_permitted_1; +} + +static void +show_maintenance_target_async_permitted (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered (file, _("\ +Controlling the inferior in asynchronous mode is %s.\n"), value); +} + void initialize_targets (void) { @@ -2840,5 +3658,26 @@ result in significant performance improvement for remote targets."), _("Print the name of each layer of the internal target stack."), &maintenanceprintlist); + add_setshow_boolean_cmd ("target-async", no_class, + &target_async_permitted_1, _("\ +Set whether gdb controls the inferior in asynchronous mode."), _("\ +Show whether gdb controls the inferior in asynchronous mode."), _("\ +Tells gdb whether to control the inferior in asynchronous mode."), + set_maintenance_target_async_permitted, + show_maintenance_target_async_permitted, + &setlist, + &showlist); + + add_setshow_boolean_cmd ("stack-cache", class_support, + &stack_cache_enabled_p_1, _("\ +Set cache use for stack access."), _("\ +Show cache use for stack access."), _("\ +When on, use the data cache for all stack access, regardless of any\n\ +configured memory regions. This improves remote performance significantly.\n\ +By default, caching for stack access is on."), + set_stack_cache_enabled_p, + show_stack_cache_enabled_p, + &setlist, &showlist); + target_dcache = dcache_init (); }