X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Futils.c;h=82e3adbafb7e2c01fb5d6c9178e0a5f5042a975a;hb=91033e3716b2eccc227992cde676198949941edf;hp=f5325f692fbc3a9a0a1a88c26688859f7ac2051e;hpb=e1024ff1ddc5fdc00175c3fa2bdfdea412d6687f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/utils.c b/gdb/utils.c index f5325f692f..82e3adbafb 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1,14 +1,14 @@ /* General utility routines for GDB, the GNU debugger. Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, - 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, + 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,9 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "gdb_assert.h" @@ -27,6 +25,10 @@ #include "gdb_string.h" #include "event-top.h" #include "exceptions.h" +#include "gdbthread.h" +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif /* HAVE_SYS_RESOURCE_H */ #ifdef TUI #include "tui/tui.h" /* For tui_get_command_dimension. */ @@ -36,7 +38,7 @@ #include #endif -/* SunOS's curses.h has a '#define reg register' in it. Thank you Sun. */ +/* SunOS's curses.h has a '#define reg register' in it. Thank you Sun. */ #ifdef reg #undef reg #endif @@ -54,7 +56,9 @@ #include "filenames.h" #include "symfile.h" #include "gdb_obstack.h" +#include "gdbcore.h" #include "top.h" +#include "main.h" #include "inferior.h" /* for signed_pointer_to_address */ @@ -64,11 +68,18 @@ #include "readline/readline.h" +#include +#include + +#include "gdb_usleep.h" +#include "interps.h" +#include "gdb_regex.h" + #if !HAVE_DECL_MALLOC -extern PTR malloc (); /* OK: PTR */ +extern PTR malloc (); /* ARI: PTR */ #endif #if !HAVE_DECL_REALLOC -extern PTR realloc (); /* OK: PTR */ +extern PTR realloc (); /* ARI: PTR */ #endif #if !HAVE_DECL_FREE extern void free (); @@ -82,7 +93,7 @@ void (*deprecated_error_begin_hook) (void); /* Prototypes for local functions */ static void vfprintf_maybe_filtered (struct ui_file *, const char *, - va_list, int) ATTR_FORMAT (printf, 2, 0); + va_list, int) ATTRIBUTE_PRINTF (2, 0); static void fputs_maybe_filtered (const char *, struct ui_file *, int); @@ -93,24 +104,17 @@ static void prompt_for_continue (void); static void set_screen_size (void); static void set_width (void); +/* A flag indicating whether to timestamp debugging messages. */ + +static int debug_timestamp = 0; + /* Chain of cleanup actions established with make_cleanup, to be executed if an error happens. */ static struct cleanup *cleanup_chain; /* cleaned up after a failed command */ static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */ -static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */ -static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */ -/* cleaned up on each error from within an execution command */ -static struct cleanup *exec_error_cleanup_chain; - -/* Pointer to what is left to do for an execution command after the - target stops. Used only in asynchronous mode, by targets that - support async execution. The finish and until commands use it. So - does the target extended-remote command. */ -struct continuation *cmd_continuation; -struct continuation *intermediate_continuation; -/* Nonzero if we have job control. */ +/* Nonzero if we have job control. */ int job_control; @@ -139,8 +143,9 @@ static void show_demangle (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Demangling of encoded C++/ObjC names when displaying symbols is %s.\n"), + fprintf_filtered (file, + _("Demangling of encoded C++/ObjC names " + "when displaying symbols is %s.\n"), value); } @@ -153,8 +158,9 @@ static void show_asm_demangle (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Demangling of C++/ObjC names in disassembly listings is %s.\n"), + fprintf_filtered (file, + _("Demangling of C++/ObjC names in " + "disassembly listings is %s.\n"), value); } @@ -167,8 +173,8 @@ static void show_sevenbit_strings (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Printing of 8-bit characters in strings as \\nnn is %s.\n"), + fprintf_filtered (file, _("Printing of 8-bit characters " + "in strings as \\nnn is %s.\n"), value); } @@ -206,27 +212,17 @@ make_cleanup (make_cleanup_ftype *function, void *arg) } struct cleanup * -make_final_cleanup (make_cleanup_ftype *function, void *arg) +make_cleanup_dtor (make_cleanup_ftype *function, void *arg, + void (*dtor) (void *)) { - return make_my_cleanup (&final_cleanup_chain, function, arg); + return make_my_cleanup2 (&cleanup_chain, + function, arg, dtor); } struct cleanup * -make_run_cleanup (make_cleanup_ftype *function, void *arg) -{ - return make_my_cleanup (&run_cleanup_chain, function, arg); -} - -struct cleanup * -make_exec_cleanup (make_cleanup_ftype *function, void *arg) -{ - return make_my_cleanup (&exec_cleanup_chain, function, arg); -} - -struct cleanup * -make_exec_error_cleanup (make_cleanup_ftype *function, void *arg) +make_final_cleanup (make_cleanup_ftype *function, void *arg) { - return make_my_cleanup (&exec_error_cleanup_chain, function, arg); + return make_my_cleanup (&final_cleanup_chain, function, arg); } static void @@ -257,16 +253,53 @@ static void do_close_cleanup (void *arg) { int *fd = arg; + close (*fd); - xfree (fd); } struct cleanup * make_cleanup_close (int fd) { int *saved_fd = xmalloc (sizeof (fd)); + *saved_fd = fd; - return make_cleanup (do_close_cleanup, saved_fd); + return make_cleanup_dtor (do_close_cleanup, saved_fd, xfree); +} + +/* Helper function which does the work for make_cleanup_fclose. */ + +static void +do_fclose_cleanup (void *arg) +{ + FILE *file = arg; + + fclose (file); +} + +/* Return a new cleanup that closes FILE. */ + +struct cleanup * +make_cleanup_fclose (FILE *file) +{ + return make_cleanup (do_fclose_cleanup, file); +} + +/* Helper function which does the work for make_cleanup_obstack_free. */ + +static void +do_obstack_free (void *arg) +{ + struct obstack *ob = arg; + + obstack_free (ob, NULL); +} + +/* Return a new cleanup that frees OBSTACK. */ + +struct cleanup * +make_cleanup_obstack_free (struct obstack *obstack) +{ + return make_cleanup (do_obstack_free, obstack); } static void @@ -281,6 +314,26 @@ make_cleanup_ui_file_delete (struct ui_file *arg) return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg); } +/* Helper function for make_cleanup_ui_out_redirect_pop. */ + +static void +do_ui_out_redirect_pop (void *arg) +{ + struct ui_out *uiout = arg; + + if (ui_out_redirect (uiout, NULL) < 0) + warning (_("Cannot restore redirection of the current output protocol")); +} + +/* Return a new cleanup that pops the last redirection by ui_out_redirect + with NULL parameter. */ + +struct cleanup * +make_cleanup_ui_out_redirect_pop (struct ui_out *uiout) +{ + return make_my_cleanup (&cleanup_chain, do_ui_out_redirect_pop, uiout); +} + static void do_free_section_addr_info (void *arg) { @@ -293,10 +346,94 @@ make_cleanup_free_section_addr_info (struct section_addr_info *addrs) return make_my_cleanup (&cleanup_chain, do_free_section_addr_info, addrs); } +struct restore_integer_closure +{ + int *variable; + int value; +}; + +static void +restore_integer (void *p) +{ + struct restore_integer_closure *closure = p; + + *(closure->variable) = closure->value; +} + +/* Remember the current value of *VARIABLE and make it restored when + the cleanup is run. */ struct cleanup * -make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, - void *arg) +make_cleanup_restore_integer (int *variable) +{ + struct restore_integer_closure *c = + xmalloc (sizeof (struct restore_integer_closure)); + + c->variable = variable; + c->value = *variable; + + return make_my_cleanup2 (&cleanup_chain, restore_integer, (void *)c, + xfree); +} + +/* Remember the current value of *VARIABLE and make it restored when + the cleanup is run. */ + +struct cleanup * +make_cleanup_restore_uinteger (unsigned int *variable) +{ + return make_cleanup_restore_integer ((int *) variable); +} + +/* Helper for make_cleanup_unpush_target. */ + +static void +do_unpush_target (void *arg) +{ + struct target_ops *ops = arg; + + unpush_target (ops); +} + +/* Return a new cleanup that unpushes OPS. */ + +struct cleanup * +make_cleanup_unpush_target (struct target_ops *ops) +{ + return make_my_cleanup (&cleanup_chain, do_unpush_target, ops); +} + +struct restore_ui_file_closure +{ + struct ui_file **variable; + struct ui_file *value; +}; + +static void +do_restore_ui_file (void *p) +{ + struct restore_ui_file_closure *closure = p; + + *(closure->variable) = closure->value; +} + +/* Remember the current value of *VARIABLE and make it restored when + the cleanup is run. */ + +struct cleanup * +make_cleanup_restore_ui_file (struct ui_file **variable) +{ + struct restore_ui_file_closure *c = XNEW (struct restore_ui_file_closure); + + c->variable = variable; + c->value = *variable; + + return make_cleanup_dtor (do_restore_ui_file, (void *) c, xfree); +} + +struct cleanup * +make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg, void (*free_arg) (void *)) { struct cleanup *new = (struct cleanup *) xmalloc (sizeof (struct cleanup)); @@ -304,12 +441,20 @@ make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, new->next = *pmy_chain; new->function = function; + new->free_arg = free_arg; new->arg = arg; *pmy_chain = new; return old_chain; } +struct cleanup * +make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg) +{ + return make_my_cleanup2 (pmy_chain, function, arg, NULL); +} + /* Discard cleanups and do the actions they describe until we get back to the point OLD_CHAIN in the cleanup_chain. */ @@ -325,33 +470,18 @@ do_final_cleanups (struct cleanup *old_chain) do_my_cleanups (&final_cleanup_chain, old_chain); } -void -do_run_cleanups (struct cleanup *old_chain) -{ - do_my_cleanups (&run_cleanup_chain, old_chain); -} - -void -do_exec_cleanups (struct cleanup *old_chain) -{ - do_my_cleanups (&exec_cleanup_chain, old_chain); -} - -void -do_exec_error_cleanups (struct cleanup *old_chain) -{ - do_my_cleanups (&exec_error_cleanup_chain, old_chain); -} - static void do_my_cleanups (struct cleanup **pmy_chain, struct cleanup *old_chain) { struct cleanup *ptr; + while ((ptr = *pmy_chain) != old_chain) { - *pmy_chain = ptr->next; /* Do this first incase recursion */ + *pmy_chain = ptr->next; /* Do this first in case of recursion. */ (*ptr->function) (ptr->arg); + if (ptr->free_arg) + (*ptr->free_arg) (ptr->arg); xfree (ptr); } } @@ -371,20 +501,17 @@ discard_final_cleanups (struct cleanup *old_chain) discard_my_cleanups (&final_cleanup_chain, old_chain); } -void -discard_exec_error_cleanups (struct cleanup *old_chain) -{ - discard_my_cleanups (&exec_error_cleanup_chain, old_chain); -} - void discard_my_cleanups (struct cleanup **pmy_chain, struct cleanup *old_chain) { struct cleanup *ptr; + while ((ptr = *pmy_chain) != old_chain) { *pmy_chain = ptr->next; + if (ptr->free_arg) + (*ptr->free_arg) (ptr->arg); xfree (ptr); } } @@ -442,6 +569,7 @@ void free_current_contents (void *ptr) { void **location = ptr; + if (location == NULL) internal_error (__FILE__, __LINE__, _("free_current_contents: NULL pointer")); @@ -457,137 +585,367 @@ free_current_contents (void *ptr) use the cleanup chain for handling normal cleanups as well as dealing with cleanups that need to be done as a result of a call to error(). In such cases, we may not be certain where the first cleanup is, unless - we have a do-nothing one to always use as the base. */ + we have a do-nothing one to always use as the base. */ void null_cleanup (void *arg) { } -/* Add a continuation to the continuation list, the global list - cmd_continuation. The new continuation will be added at the front.*/ +/* If nonzero, display time usage both at startup and for each command. */ + +static int display_time; + +/* If nonzero, display space usage both at startup and for each command. */ + +static int display_space; + +/* Records a run time and space usage to be used as a base for + reporting elapsed time or change in space. In addition, + the msg_type field indicates whether the saved time is from the + beginning of GDB execution (0) or the beginning of an individual + command execution (1). */ +struct cmd_stats +{ + int msg_type; + long start_time; + long start_space; +}; + +/* Set whether to display time statistics to NEW_VALUE (non-zero + means true). */ void -add_continuation (void (*continuation_hook) (struct continuation_arg *), - struct continuation_arg *arg_list) +set_display_time (int new_value) { - struct continuation *continuation_ptr; + display_time = new_value; +} - continuation_ptr = - (struct continuation *) xmalloc (sizeof (struct continuation)); - continuation_ptr->continuation_hook = continuation_hook; - continuation_ptr->arg_list = arg_list; - continuation_ptr->next = cmd_continuation; - cmd_continuation = continuation_ptr; +/* Set whether to display space statistics to NEW_VALUE (non-zero + means true). */ +void +set_display_space (int new_value) +{ + display_space = new_value; } -/* Walk down the cmd_continuation list, and execute all the - continuations. There is a problem though. In some cases new - continuations may be added while we are in the middle of this - loop. If this happens they will be added in the front, and done - before we have a chance of exhausting those that were already - there. We need to then save the beginning of the list in a pointer - and do the continuations from there on, instead of using the - global beginning of list as our iteration pointer. */ +/* As indicated by display_time and display_space, report GDB's elapsed time + and space usage from the base time and space provided in ARG, which + must be a pointer to a struct cmd_stat. This function is intended + to be called as a cleanup. */ +static void +report_command_stats (void *arg) +{ + struct cmd_stats *start_stats = (struct cmd_stats *) arg; + int msg_type = start_stats->msg_type; + + if (display_time) + { + long cmd_time = get_run_time () - start_stats->start_time; + + printf_unfiltered (msg_type == 0 + ? _("Startup time: %ld.%06ld\n") + : _("Command execution time: %ld.%06ld\n"), + cmd_time / 1000000, cmd_time % 1000000); + } + + if (display_space) + { +#ifdef HAVE_SBRK + char *lim = (char *) sbrk (0); + + long space_now = lim - lim_at_start; + long space_diff = space_now - start_stats->start_space; + + printf_unfiltered (msg_type == 0 + ? _("Space used: %ld (%c%ld during startup)\n") + : _("Space used: %ld (%c%ld for this command)\n"), + space_now, + (space_diff >= 0 ? '+' : '-'), + space_diff); +#endif + } +} + +/* Create a cleanup that reports time and space used since its + creation. Precise messages depend on MSG_TYPE: + 0: Initial time/space + 1: Individual command time/space. */ +struct cleanup * +make_command_stats_cleanup (int msg_type) +{ + struct cmd_stats *new_stat = XMALLOC (struct cmd_stats); + +#ifdef HAVE_SBRK + char *lim = (char *) sbrk (0); + new_stat->start_space = lim - lim_at_start; +#endif + + new_stat->msg_type = msg_type; + new_stat->start_time = get_run_time (); + + return make_cleanup_dtor (report_command_stats, new_stat, xfree); +} + +/* Continuations are implemented as cleanups internally. Inherit from + cleanups. */ +struct continuation +{ + struct cleanup base; +}; + +/* Add a continuation to the continuation list of THREAD. The new + continuation will be added at the front. */ void -do_all_continuations (void) +add_continuation (struct thread_info *thread, + void (*continuation_hook) (void *), void *args, + void (*continuation_free_args) (void *)) +{ + struct cleanup *as_cleanup = &thread->continuations->base; + make_cleanup_ftype *continuation_hook_fn = continuation_hook; + + make_my_cleanup2 (&as_cleanup, + continuation_hook_fn, + args, + continuation_free_args); + + thread->continuations = (struct continuation *) as_cleanup; +} + +/* Add a continuation to the continuation list of INFERIOR. The new + continuation will be added at the front. */ + +void +add_inferior_continuation (void (*continuation_hook) (void *), void *args, + void (*continuation_free_args) (void *)) { - struct continuation *continuation_ptr; - struct continuation *saved_continuation; + struct inferior *inf = current_inferior (); + struct cleanup *as_cleanup = &inf->continuations->base; + make_cleanup_ftype *continuation_hook_fn = continuation_hook; + + make_my_cleanup2 (&as_cleanup, + continuation_hook_fn, + args, + continuation_free_args); + + inf->continuations = (struct continuation *) as_cleanup; +} + +/* Do all continuations of the current inferior. */ + +void +do_all_inferior_continuations (void) +{ + struct cleanup *as_cleanup; + struct inferior *inf = current_inferior (); + + if (inf->continuations == NULL) + return; /* Copy the list header into another pointer, and set the global list header to null, so that the global list can change as a side - effect of invoking the continuations and the processing of - the preexisting continuations will not be affected. */ - continuation_ptr = cmd_continuation; - cmd_continuation = NULL; + effect of invoking the continuations and the processing of the + preexisting continuations will not be affected. */ + + as_cleanup = &inf->continuations->base; + inf->continuations = NULL; /* Work now on the list we have set aside. */ - while (continuation_ptr) - { - (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); - saved_continuation = continuation_ptr; - continuation_ptr = continuation_ptr->next; - xfree (saved_continuation); - } + do_my_cleanups (&as_cleanup, NULL); } -/* Walk down the cmd_continuation list, and get rid of all the - continuations. */ +/* Get rid of all the inferior-wide continuations of INF. */ + void -discard_all_continuations (void) +discard_all_inferior_continuations (struct inferior *inf) { - struct continuation *continuation_ptr; + struct cleanup *continuation_ptr = &inf->continuations->base; - while (cmd_continuation) - { - continuation_ptr = cmd_continuation; - cmd_continuation = continuation_ptr->next; - xfree (continuation_ptr); - } + discard_my_cleanups (&continuation_ptr, NULL); + inf->continuations = NULL; +} + +static void +restore_thread_cleanup (void *arg) +{ + ptid_t *ptid_p = arg; + + switch_to_thread (*ptid_p); +} + +/* Walk down the continuation list of PTID, and execute all the + continuations. There is a problem though. In some cases new + continuations may be added while we are in the middle of this loop. + If this happens they will be added in the front, and done before we + have a chance of exhausting those that were already there. We need + to then save the beginning of the list in a pointer and do the + continuations from there on, instead of using the global beginning + of list as our iteration pointer. */ +static void +do_all_continuations_ptid (ptid_t ptid, + struct continuation **continuations_p) +{ + struct cleanup *old_chain; + ptid_t current_thread; + struct cleanup *as_cleanup; + + if (*continuations_p == NULL) + return; + + current_thread = inferior_ptid; + + /* Restore selected thread on exit. Don't try to restore the frame + as well, because: + + - When running continuations, the selected frame is always #0. + + - The continuations may trigger symbol file loads, which may + change the frame layout (frame ids change), which would trigger + a warning if we used make_cleanup_restore_current_thread. */ + + old_chain = make_cleanup (restore_thread_cleanup, ¤t_thread); + + /* Let the continuation see this thread as selected. */ + switch_to_thread (ptid); + + /* Copy the list header into another pointer, and set the global + list header to null, so that the global list can change as a side + effect of invoking the continuations and the processing of the + preexisting continuations will not be affected. */ + + as_cleanup = &(*continuations_p)->base; + *continuations_p = NULL; + + /* Work now on the list we have set aside. */ + do_my_cleanups (&as_cleanup, NULL); + + do_cleanups (old_chain); +} + +/* Callback for iterate over threads. */ +static int +do_all_continuations_thread_callback (struct thread_info *thread, void *data) +{ + do_all_continuations_ptid (thread->ptid, &thread->continuations); + return 0; +} + +/* Do all continuations of thread THREAD. */ +void +do_all_continuations_thread (struct thread_info *thread) +{ + do_all_continuations_thread_callback (thread, NULL); +} + +/* Do all continuations of all threads. */ +void +do_all_continuations (void) +{ + iterate_over_threads (do_all_continuations_thread_callback, NULL); } -/* Add a continuation to the continuation list, the global list - intermediate_continuation. The new continuation will be added at - the front. */ +/* Callback for iterate over threads. */ +static int +discard_all_continuations_thread_callback (struct thread_info *thread, + void *data) +{ + struct cleanup *continuation_ptr = &thread->continuations->base; + + discard_my_cleanups (&continuation_ptr, NULL); + thread->continuations = NULL; + return 0; +} + +/* Get rid of all the continuations of THREAD. */ void -add_intermediate_continuation (void (*continuation_hook) - (struct continuation_arg *), - struct continuation_arg *arg_list) +discard_all_continuations_thread (struct thread_info *thread) { - struct continuation *continuation_ptr; + discard_all_continuations_thread_callback (thread, NULL); +} - continuation_ptr = - (struct continuation *) xmalloc (sizeof (struct continuation)); - continuation_ptr->continuation_hook = continuation_hook; - continuation_ptr->arg_list = arg_list; - continuation_ptr->next = intermediate_continuation; - intermediate_continuation = continuation_ptr; +/* Get rid of all the continuations of all threads. */ +void +discard_all_continuations (void) +{ + iterate_over_threads (discard_all_continuations_thread_callback, NULL); +} + + +/* Add a continuation to the intermediate continuation list of THREAD. + The new continuation will be added at the front. */ +void +add_intermediate_continuation (struct thread_info *thread, + void (*continuation_hook) + (void *), void *args, + void (*continuation_free_args) (void *)) +{ + struct cleanup *as_cleanup = &thread->intermediate_continuations->base; + make_cleanup_ftype *continuation_hook_fn = continuation_hook; + + make_my_cleanup2 (&as_cleanup, + continuation_hook_fn, + args, + continuation_free_args); + + thread->intermediate_continuations = (struct continuation *) as_cleanup; } /* Walk down the cmd_continuation list, and execute all the - continuations. There is a problem though. In some cases new + continuations. There is a problem though. In some cases new continuations may be added while we are in the middle of this - loop. If this happens they will be added in the front, and done + loop. If this happens they will be added in the front, and done before we have a chance of exhausting those that were already - there. We need to then save the beginning of the list in a pointer + there. We need to then save the beginning of the list in a pointer and do the continuations from there on, instead of using the - global beginning of list as our iteration pointer.*/ + global beginning of list as our iteration pointer. */ +static int +do_all_intermediate_continuations_thread_callback (struct thread_info *thread, + void *data) +{ + do_all_continuations_ptid (thread->ptid, + &thread->intermediate_continuations); + return 0; +} + +/* Do all intermediate continuations of thread THREAD. */ +void +do_all_intermediate_continuations_thread (struct thread_info *thread) +{ + do_all_intermediate_continuations_thread_callback (thread, NULL); +} + +/* Do all intermediate continuations of all threads. */ void do_all_intermediate_continuations (void) { - struct continuation *continuation_ptr; - struct continuation *saved_continuation; + iterate_over_threads (do_all_intermediate_continuations_thread_callback, + NULL); +} - /* Copy the list header into another pointer, and set the global - list header to null, so that the global list can change as a side - effect of invoking the continuations and the processing of - the preexisting continuations will not be affected. */ - continuation_ptr = intermediate_continuation; - intermediate_continuation = NULL; +/* Callback for iterate over threads. */ +static int +discard_all_intermediate_continuations_thread_callback (struct thread_info *thread, + void *data) +{ + struct cleanup *continuation_ptr = &thread->intermediate_continuations->base; - /* Work now on the list we have set aside. */ - while (continuation_ptr) - { - (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); - saved_continuation = continuation_ptr; - continuation_ptr = continuation_ptr->next; - xfree (saved_continuation); - } + discard_my_cleanups (&continuation_ptr, NULL); + thread->intermediate_continuations = NULL; + return 0; } -/* Walk down the cmd_continuation list, and get rid of all the - continuations. */ +/* Get rid of all the intermediate continuations of THREAD. */ void -discard_all_intermediate_continuations (void) +discard_all_intermediate_continuations_thread (struct thread_info *thread) { - struct continuation *continuation_ptr; + discard_all_intermediate_continuations_thread_callback (thread, NULL); +} - while (intermediate_continuation) - { - continuation_ptr = intermediate_continuation; - intermediate_continuation = continuation_ptr->next; - xfree (continuation_ptr); - } +/* Get rid of all the intermediate continuations of all threads. */ +void +discard_all_intermediate_continuations (void) +{ + iterate_over_threads (discard_all_intermediate_continuations_thread_callback, + NULL); } @@ -606,7 +964,7 @@ vwarning (const char *string, va_list args) else { target_terminal_ours (); - wrap_here (""); /* Force out any buffered output */ + wrap_here (""); /* Force out any buffered output. */ gdb_flush (gdb_stdout); if (warning_pre_print) fputs_unfiltered (warning_pre_print, gdb_stderr); @@ -626,6 +984,7 @@ void warning (const char *string, ...) { va_list args; + va_start (args, string); vwarning (string, args); va_end (args); @@ -635,16 +994,17 @@ warning (const char *string, ...) The first argument STRING is the error message, used as a fprintf string, and the remaining args are passed as arguments to it. */ -NORETURN void +void verror (const char *string, va_list args) { throw_verror (GENERIC_ERROR, string, args); } -NORETURN void +void error (const char *string, ...) { va_list args; + va_start (args, string); throw_verror (GENERIC_ERROR, string, args); va_end (args); @@ -654,48 +1014,101 @@ error (const char *string, ...) The first argument STRING is the error message, used as a fprintf string, and the remaining args are passed as arguments to it. */ -NORETURN void +void vfatal (const char *string, va_list args) { throw_vfatal (string, args); } -NORETURN void +void fatal (const char *string, ...) { va_list args; + va_start (args, string); throw_vfatal (string, args); va_end (args); } -NORETURN void +void error_stream (struct ui_file *stream) { - long len; - char *message = ui_file_xstrdup (stream, &len); + char *message = ui_file_xstrdup (stream, NULL); + make_cleanup (xfree, message); error (("%s"), message); } -/* Print a message reporting an internal error/warning. Ask the user +/* Dump core trying to increase the core soft limit to hard limit first. */ + +static void +dump_core (void) +{ +#ifdef HAVE_SETRLIMIT + struct rlimit rlim = { RLIM_INFINITY, RLIM_INFINITY }; + + setrlimit (RLIMIT_CORE, &rlim); +#endif /* HAVE_SETRLIMIT */ + + abort (); /* NOTE: GDB has only three calls to abort(). */ +} + +/* Check whether GDB will be able to dump core using the dump_core + function. */ + +static int +can_dump_core (const char *reason) +{ +#ifdef HAVE_GETRLIMIT + struct rlimit rlim; + + /* Be quiet and assume we can dump if an error is returned. */ + if (getrlimit (RLIMIT_CORE, &rlim) != 0) + return 1; + + if (rlim.rlim_max == 0) + { + fprintf_unfiltered (gdb_stderr, + _("%s\nUnable to dump core, use `ulimit -c" + " unlimited' before executing GDB next time.\n"), + reason); + return 0; + } +#endif /* HAVE_GETRLIMIT */ + + return 1; +} + +/* Allow the user to configure the debugger behavior with respect to + what to do when an internal problem is detected. */ + +const char internal_problem_ask[] = "ask"; +const char internal_problem_yes[] = "yes"; +const char internal_problem_no[] = "no"; +static const char *internal_problem_modes[] = +{ + internal_problem_ask, + internal_problem_yes, + internal_problem_no, + NULL +}; + +/* Print a message reporting an internal error/warning. Ask the user if they want to continue, dump core, or just exit. Return something to indicate a quit. */ struct internal_problem { const char *name; - /* FIXME: cagney/2002-08-15: There should be ``maint set/show'' - commands available for controlling these variables. */ - enum auto_boolean should_quit; - enum auto_boolean should_dump_core; + const char *should_quit; + const char *should_dump_core; }; /* Report a problem, internal to GDB, to the user. Once the problem has been reported, and assuming GDB didn't quit, the caller can either allow execution to resume or throw an error. */ -static void ATTR_FORMAT (printf, 4, 0) +static void ATTRIBUTE_PRINTF (4, 0) internal_vproblem (struct internal_problem *problem, const char *file, int line, const char *fmt, va_list ap) { @@ -707,6 +1120,7 @@ internal_vproblem (struct internal_problem *problem, /* Don't allow infinite error/warning recursion. */ { static char msg[] = "Recursive internal problem.\n"; + switch (dejavu) { case 0: @@ -718,7 +1132,13 @@ internal_vproblem (struct internal_problem *problem, abort (); /* NOTE: GDB has only three calls to abort(). */ default: dejavu = 3; - write (STDERR_FILENO, msg, sizeof (msg)); + /* Newer GLIBC versions put the warn_unused_result attribute + on write, but this is one of those rare cases where + ignoring the return value is correct. Casting to (void) + does not fix this problem. This is the solution suggested + at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509. */ + if (write (STDERR_FILENO, msg, sizeof (msg)) != sizeof (msg)) + abort (); /* NOTE: GDB has only three calls to abort(). */ exit (1); } } @@ -734,56 +1154,61 @@ internal_vproblem (struct internal_problem *problem, so that the user knows that they are living on the edge. */ { char *msg; + msg = xstrvprintf (fmt, ap); - reason = xstrprintf ("\ -%s:%d: %s: %s\n\ -A problem internal to GDB has been detected,\n\ -further debugging may prove unreliable.", file, line, problem->name, msg); + reason = xstrprintf ("%s:%d: %s: %s\n" + "A problem internal to GDB has been detected,\n" + "further debugging may prove unreliable.", + file, line, problem->name, msg); xfree (msg); make_cleanup (xfree, reason); } - switch (problem->should_quit) + if (problem->should_quit == internal_problem_ask) { - case AUTO_BOOLEAN_AUTO: /* Default (yes/batch case) is to quit GDB. When in batch mode - this lessens the likelhood of GDB going into an infinate - loop. */ - quit_p = query (_("%s\nQuit this debugging session? "), reason); - break; - case AUTO_BOOLEAN_TRUE: - quit_p = 1; - break; - case AUTO_BOOLEAN_FALSE: - quit_p = 0; - break; - default: - internal_error (__FILE__, __LINE__, _("bad switch")); + this lessens the likelihood of GDB going into an infinite + loop. */ + if (caution == 0) + { + /* Emit the message and quit. */ + fputs_unfiltered (reason, gdb_stderr); + fputs_unfiltered ("\n", gdb_stderr); + quit_p = 1; + } + else + quit_p = query (_("%s\nQuit this debugging session? "), reason); } + else if (problem->should_quit == internal_problem_yes) + quit_p = 1; + else if (problem->should_quit == internal_problem_no) + quit_p = 0; + else + internal_error (__FILE__, __LINE__, _("bad switch")); - switch (problem->should_dump_core) + if (problem->should_dump_core == internal_problem_ask) { - case AUTO_BOOLEAN_AUTO: - /* Default (yes/batch case) is to dump core. This leaves a GDB - `dropping' so that it is easier to see that something went - wrong in GDB. */ - dump_core_p = query (_("%s\nCreate a core file of GDB? "), reason); - break; - break; - case AUTO_BOOLEAN_TRUE: - dump_core_p = 1; - break; - case AUTO_BOOLEAN_FALSE: - dump_core_p = 0; - break; - default: - internal_error (__FILE__, __LINE__, _("bad switch")); + if (!can_dump_core (reason)) + dump_core_p = 0; + else + { + /* Default (yes/batch case) is to dump core. This leaves a GDB + `dropping' so that it is easier to see that something went + wrong in GDB. */ + dump_core_p = query (_("%s\nCreate a core file of GDB? "), reason); + } } + else if (problem->should_dump_core == internal_problem_yes) + dump_core_p = can_dump_core (reason); + else if (problem->should_dump_core == internal_problem_no) + dump_core_p = 0; + else + internal_error (__FILE__, __LINE__, _("bad switch")); if (quit_p) { if (dump_core_p) - abort (); /* NOTE: GDB has only three calls to abort(). */ + dump_core (); else exit (1); } @@ -793,7 +1218,7 @@ further debugging may prove unreliable.", file, line, problem->name, msg); { #ifdef HAVE_WORKING_FORK if (fork () == 0) - abort (); /* NOTE: GDB has only three calls to abort(). */ + dump_core (); #endif } } @@ -802,27 +1227,28 @@ further debugging may prove unreliable.", file, line, problem->name, msg); } static struct internal_problem internal_error_problem = { - "internal-error", AUTO_BOOLEAN_AUTO, AUTO_BOOLEAN_AUTO + "internal-error", internal_problem_ask, internal_problem_ask }; -NORETURN void +void internal_verror (const char *file, int line, const char *fmt, va_list ap) { internal_vproblem (&internal_error_problem, file, line, fmt, ap); deprecated_throw_reason (RETURN_ERROR); } -NORETURN void +void internal_error (const char *file, int line, const char *string, ...) { va_list ap; + va_start (ap, string); internal_verror (file, line, string, ap); va_end (ap); } static struct internal_problem internal_warning_problem = { - "internal-warning", AUTO_BOOLEAN_AUTO, AUTO_BOOLEAN_AUTO + "internal-warning", internal_problem_ask, internal_problem_ask }; void @@ -835,16 +1261,118 @@ void internal_warning (const char *file, int line, const char *string, ...) { va_list ap; + va_start (ap, string); internal_vwarning (file, line, string, ap); va_end (ap); } +/* Dummy functions to keep add_prefix_cmd happy. */ + +static void +set_internal_problem_cmd (char *args, int from_tty) +{ +} + +static void +show_internal_problem_cmd (char *args, int from_tty) +{ +} + +/* When GDB reports an internal problem (error or warning) it gives + the user the opportunity to quit GDB and/or create a core file of + the current debug session. This function registers a few commands + that make it possible to specify that GDB should always or never + quit or create a core file, without asking. The commands look + like: + + maint set PROBLEM-NAME quit ask|yes|no + maint show PROBLEM-NAME quit + maint set PROBLEM-NAME corefile ask|yes|no + maint show PROBLEM-NAME corefile + + Where PROBLEM-NAME is currently "internal-error" or + "internal-warning". */ + +static void +add_internal_problem_command (struct internal_problem *problem) +{ + struct cmd_list_element **set_cmd_list; + struct cmd_list_element **show_cmd_list; + char *set_doc; + char *show_doc; + + set_cmd_list = xmalloc (sizeof (*set_cmd_list)); + show_cmd_list = xmalloc (sizeof (*set_cmd_list)); + *set_cmd_list = NULL; + *show_cmd_list = NULL; + + set_doc = xstrprintf (_("Configure what GDB does when %s is detected."), + problem->name); + + show_doc = xstrprintf (_("Show what GDB does when %s is detected."), + problem->name); + + add_prefix_cmd ((char*) problem->name, + class_maintenance, set_internal_problem_cmd, set_doc, + set_cmd_list, + concat ("maintenance set ", problem->name, " ", + (char *) NULL), + 0/*allow-unknown*/, &maintenance_set_cmdlist); + + add_prefix_cmd ((char*) problem->name, + class_maintenance, show_internal_problem_cmd, show_doc, + show_cmd_list, + concat ("maintenance show ", problem->name, " ", + (char *) NULL), + 0/*allow-unknown*/, &maintenance_show_cmdlist); + + set_doc = xstrprintf (_("Set whether GDB should quit " + "when an %s is detected"), + problem->name); + show_doc = xstrprintf (_("Show whether GDB will quit " + "when an %s is detected"), + problem->name); + add_setshow_enum_cmd ("quit", class_maintenance, + internal_problem_modes, + &problem->should_quit, + set_doc, + show_doc, + NULL, /* help_doc */ + NULL, /* setfunc */ + NULL, /* showfunc */ + set_cmd_list, + show_cmd_list); + + xfree (set_doc); + xfree (show_doc); + + set_doc = xstrprintf (_("Set whether GDB should create a core " + "file of GDB when %s is detected"), + problem->name); + show_doc = xstrprintf (_("Show whether GDB will create a core " + "file of GDB when %s is detected"), + problem->name); + add_setshow_enum_cmd ("corefile", class_maintenance, + internal_problem_modes, + &problem->should_dump_core, + set_doc, + show_doc, + NULL, /* help_doc */ + NULL, /* setfunc */ + NULL, /* showfunc */ + set_cmd_list, + show_cmd_list); + + xfree (set_doc); + xfree (show_doc); +} + /* Print the system error message for errno, and also mention STRING as the file name for which the error was encountered. Then return to command level. */ -NORETURN void +void perror_with_name (const char *string) { char *err; @@ -858,7 +1386,7 @@ perror_with_name (const char *string) /* I understand setting these is a matter of taste. Still, some people may clear errno but not know about bfd_error. Doing this here is not - unreasonable. */ + unreasonable. */ bfd_set_error (bfd_error_no_error); errno = 0; @@ -908,9 +1436,9 @@ quit (void) /* Called when a memory allocation fails, with the number of bytes of - memory requested in SIZE. */ + memory requested in SIZE. */ -NORETURN void +void nomem (long size) { if (size > 0) @@ -934,7 +1462,7 @@ nomem (long size) /* NOTE: These are declared using PTR to ensure consistency with "libiberty.h". xfree() is GDB local. */ -PTR /* OK: PTR */ +PTR /* ARI: PTR */ xmalloc (size_t size) { void *val; @@ -944,7 +1472,7 @@ xmalloc (size_t size) if (size == 0) size = 1; - val = malloc (size); /* OK: malloc */ + val = malloc (size); /* ARI: malloc */ if (val == NULL) nomem (size); @@ -957,8 +1485,8 @@ xzalloc (size_t size) return xcalloc (1, size); } -PTR /* OK: PTR */ -xrealloc (PTR ptr, size_t size) /* OK: PTR */ +PTR /* ARI: PTR */ +xrealloc (PTR ptr, size_t size) /* ARI: PTR */ { void *val; @@ -968,16 +1496,16 @@ xrealloc (PTR ptr, size_t size) /* OK: PTR */ size = 1; if (ptr != NULL) - val = realloc (ptr, size); /* OK: realloc */ + val = realloc (ptr, size); /* ARI: realloc */ else - val = malloc (size); /* OK: malloc */ + val = malloc (size); /* ARI: malloc */ if (val == NULL) nomem (size); return (val); } -PTR /* OK: PTR */ +PTR /* ARI: PTR */ xcalloc (size_t number, size_t size) { void *mem; @@ -990,7 +1518,7 @@ xcalloc (size_t number, size_t size) size = 1; } - mem = calloc (number, size); /* OK: xcalloc */ + mem = calloc (number, size); /* ARI: xcalloc */ if (mem == NULL) nomem (number * size); @@ -1001,18 +1529,19 @@ void xfree (void *ptr) { if (ptr != NULL) - free (ptr); /* OK: free */ + free (ptr); /* ARI: free */ } /* Like asprintf/vasprintf but get an internal_error if the call - fails. */ + fails. */ char * xstrprintf (const char *format, ...) { char *ret; va_list args; + va_start (args, format); ret = xstrvprintf (format, args); va_end (args); @@ -1023,6 +1552,7 @@ void xasprintf (char **ret, const char *format, ...) { va_list args; + va_start (args, format); (*ret) = xstrvprintf (format, args); va_end (args); @@ -1039,6 +1569,7 @@ xstrvprintf (const char *format, va_list ap) { char *ret = NULL; int status = vasprintf (&ret, format, ap); + /* NULL is returned when there was a memory allocation problem, or any other error (for instance, a bad format string). A negative status (the printed length) with a non-NULL buffer should never @@ -1092,6 +1623,7 @@ char * savestring (const char *ptr, size_t size) { char *p = (char *) xmalloc (size + 1); + memcpy (p, ptr, size); p[size] = 0; return p; @@ -1108,13 +1640,39 @@ print_spaces (int n, struct ui_file *file) void gdb_print_host_address (const void *addr, struct ui_file *stream) { + fprintf_filtered (stream, "%s", host_address_to_string (addr)); +} + + +/* A cleanup function that calls regfree. */ + +static void +do_regfree_cleanup (void *r) +{ + regfree (r); +} + +/* Create a new cleanup that frees the compiled regular expression R. */ + +struct cleanup * +make_regfree_cleanup (regex_t *r) +{ + return make_cleanup (do_regfree_cleanup, r); +} - /* We could use the %p conversion specifier to fprintf if we had any - way of knowing whether this host supports it. But the following - should work on the Alpha and on 32 bit machines. */ +/* Return an xmalloc'd error message resulting from a regular + expression compilation failure. */ + +char * +get_regcomp_error (int code, regex_t *rx) +{ + size_t length = regerror (code, rx, NULL, 0); + char *result = xmalloc (length); - fprintf_filtered (stream, "0x%lx", (unsigned long) addr); + regerror (code, rx, result, length); + return result; } + /* This function supports the query, nquery, and yquery functions. @@ -1127,7 +1685,7 @@ gdb_print_host_address (const void *addr, struct ui_file *stream) ARGS are the arguments passed along with the CTLSTR argument to printf. */ -static int ATTR_FORMAT (printf, 1, 0) +static int ATTRIBUTE_PRINTF (1, 0) defaulted_query (const char *ctlstr, const char defchar, va_list args) { int answer; @@ -1164,12 +1722,12 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) } /* Automatically answer the default value if the user did not want - prompts. */ - if (! caution) + prompts or the command was issued with the server prefix. */ + if (! caution || server_command) return def_value; /* If input isn't coming from the user directly, just say what - question we're asking, and then answer "yes" automatically. This + question we're asking, and then answer the default automatically. This way, important error messages don't get lost when talking to GDB over a pipe. */ if (! input_from_terminal_p ()) @@ -1177,18 +1735,14 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) wrap_here (""); vfprintf_filtered (gdb_stdout, ctlstr, args); - printf_filtered (_("(%s or %s) [answered %c; input not from terminal]\n"), + printf_filtered (_("(%s or %s) [answered %c; " + "input not from terminal]\n"), y_string, n_string, def_answer); gdb_flush (gdb_stdout); return def_value; } - /* Automatically answer the default value if input is not from the user - directly, or if the user did not want prompts. */ - if (!input_from_terminal_p () || !caution) - return def_value; - if (deprecated_query_hook) { return deprecated_query_hook (ctlstr, args); @@ -1199,7 +1753,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) while (1) { - wrap_here (""); /* Flush any buffered output */ + wrap_here (""); /* Flush any buffered output. */ gdb_flush (gdb_stdout); if (annotation_level > 1) @@ -1215,6 +1769,25 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) gdb_flush (gdb_stdout); answer = fgetc (stdin); + + /* We expect fgetc to block until a character is read. But + this may not be the case if the terminal was opened with + the NONBLOCK flag. In that case, if there is nothing to + read on stdin, fgetc returns EOF, but also sets the error + condition flag on stdin and errno to EAGAIN. With a true + EOF, stdin's error condition flag is not set. + + A situation where this behavior was observed is a pseudo + terminal on AIX. */ + while (answer == EOF && ferror (stdin) && errno == EAGAIN) + { + /* Not a real EOF. Wait a little while and try again until + we read something. */ + clearerr (stdin); + gdb_usleep (10000); + answer = fgetc (stdin); + } + clearerr (stdin); /* in case of C-d */ if (answer == EOF) /* C-d */ { @@ -1222,7 +1795,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) retval = def_value; break; } - /* Eat rest of input line, to EOF or newline */ + /* Eat rest of input line, to EOF or newline. */ if (answer != '\n') do { @@ -1309,21 +1882,33 @@ query (const char *ctlstr, ...) va_end (args); } -/* Print an error message saying that we couldn't make sense of a - \^mumble sequence in a string or character constant. START and END - indicate a substring of some larger string that contains the - erroneous backslash sequence, missing the initial backslash. */ -static NORETURN int -no_control_char_error (const char *start, const char *end) +/* A helper for parse_escape that converts a host character to a + target character. C is the host character. If conversion is + possible, then the target character is stored in *TARGET_C and the + function returns 1. Otherwise, the function returns 0. */ + +static int +host_char_to_target (struct gdbarch *gdbarch, int c, int *target_c) { - int len = end - start; - char *copy = alloca (end - start + 1); + struct obstack host_data; + char the_char = c; + struct cleanup *cleanups; + int result = 0; + + obstack_init (&host_data); + cleanups = make_cleanup_obstack_free (&host_data); - memcpy (copy, start, len); - copy[len] = '\0'; + convert_between_encodings (target_charset (gdbarch), host_charset (), + &the_char, 1, 1, &host_data, translit_none); + + if (obstack_object_size (&host_data) == 1) + { + result = 1; + *target_c = *(char *) obstack_base (&host_data); + } - error (_("There is no control character `\\%s' in the `%s' character set."), - copy, target_charset ()); + do_cleanups (cleanups); + return result; } /* Parse a C escape sequence. STRING_PTR points to a variable @@ -1342,57 +1927,18 @@ no_control_char_error (const char *start, const char *end) after the zeros. A value of 0 does not mean end of string. */ int -parse_escape (char **string_ptr) +parse_escape (struct gdbarch *gdbarch, char **string_ptr) { - int target_char; + int target_char = -2; /* Initialize to avoid GCC warnings. */ int c = *(*string_ptr)++; - if (c_parse_backslash (c, &target_char)) - return target_char; - else - switch (c) - { + + switch (c) + { case '\n': return -2; case 0: (*string_ptr)--; return 0; - case '^': - { - /* Remember where this escape sequence started, for reporting - errors. */ - char *sequence_start_pos = *string_ptr - 1; - - c = *(*string_ptr)++; - - if (c == '?') - { - /* XXXCHARSET: What is `delete' in the host character set? */ - c = 0177; - - if (!host_char_to_target (c, &target_char)) - error (_("There is no character corresponding to `Delete' " - "in the target character set `%s'."), host_charset ()); - - return target_char; - } - else if (c == '\\') - target_char = parse_escape (string_ptr); - else - { - if (!host_char_to_target (c, &target_char)) - no_control_char_error (sequence_start_pos, *string_ptr); - } - - /* Now target_char is something like `c', and we want to find - its control-character equivalent. */ - if (!target_char_to_control_char (target_char, &target_char)) - no_control_char_error (sequence_start_pos, *string_ptr); - - return target_char; - } - - /* XXXCHARSET: we need to use isdigit and value-of-digit - methods of the host character set here. */ case '0': case '1': @@ -1403,16 +1949,16 @@ parse_escape (char **string_ptr) case '6': case '7': { - int i = c - '0'; + int i = host_hex_value (c); int count = 0; while (++count < 3) { c = (**string_ptr); - if (c >= '0' && c <= '7') + if (isdigit (c) && c != '8' && c != '9') { (*string_ptr)++; i *= 8; - i += c - '0'; + i += host_hex_value (c); } else { @@ -1421,27 +1967,51 @@ parse_escape (char **string_ptr) } return i; } - default: - if (!host_char_to_target (c, &target_char)) - error - ("The escape sequence `\%c' is equivalent to plain `%c', which" - " has no equivalent\n" "in the `%s' character set.", c, c, - target_charset ()); - return target_char; - } + + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + + default: + break; + } + + if (!host_char_to_target (gdbarch, c, &target_char)) + error + ("The escape sequence `\%c' is equivalent to plain `%c', which" + " has no equivalent\n" "in the `%s' character set.", c, c, + target_charset (gdbarch)); + return target_char; } /* Print the character C on STREAM as part of the contents of a literal string whose delimiter is QUOTER. Note that this routine should only be call for printing things which are independent of the language - of the program being debugged. */ + of the program being debugged. */ static void printchar (int c, void (*do_fputs) (const char *, struct ui_file *), void (*do_fprintf) (struct ui_file *, const char *, ...) ATTRIBUTE_FPTR_PRINTF_2, struct ui_file *stream, int quoter) { - c &= 0xFF; /* Avoid sign bit follies */ if (c < 0x20 || /* Low control chars */ @@ -1487,7 +2057,7 @@ printchar (int c, void (*do_fputs) (const char *, struct ui_file *), /* Print the character C on STREAM as part of the contents of a literal string whose delimiter is QUOTER. Note that these routines should only be call for printing things which are independent of - the language of the program being debugged. */ + the language of the program being debugged. */ void fputstr_filtered (const char *str, int quoter, struct ui_file *stream) @@ -1508,6 +2078,7 @@ fputstrn_filtered (const char *str, int n, int quoter, struct ui_file *stream) { int i; + for (i = 0; i < n; i++) printchar (str[i], fputs_filtered, fprintf_filtered, stream, quoter); } @@ -1517,6 +2088,7 @@ fputstrn_unfiltered (const char *str, int n, int quoter, struct ui_file *stream) { int i; + for (i = 0; i < n; i++) printchar (str[i], fputs_unfiltered, fprintf_unfiltered, stream, quoter); } @@ -1528,8 +2100,8 @@ static void show_lines_per_page (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Number of lines gdb thinks are in a page is %s.\n"), + fprintf_filtered (file, + _("Number of lines gdb thinks are in a page is %s.\n"), value); } @@ -1539,8 +2111,9 @@ static void show_chars_per_line (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Number of characters gdb thinks are in a line is %s.\n"), + fprintf_filtered (file, + _("Number of characters gdb thinks " + "are in a line is %s.\n"), value); } @@ -1577,6 +2150,12 @@ static int wrap_column; void init_page_info (void) { + if (batch_flag) + { + lines_per_page = UINT_MAX; + chars_per_line = UINT_MAX; + } + else #if defined(TUI) if (!tui_get_command_dimension (&chars_per_line, &lines_per_page)) #endif @@ -1621,6 +2200,44 @@ init_page_info (void) set_width (); } +/* Helper for make_cleanup_restore_page_info. */ + +static void +do_restore_page_info_cleanup (void *arg) +{ + set_screen_size (); + set_width (); +} + +/* Provide cleanup for restoring the terminal size. */ + +struct cleanup * +make_cleanup_restore_page_info (void) +{ + struct cleanup *back_to; + + back_to = make_cleanup (do_restore_page_info_cleanup, NULL); + make_cleanup_restore_uinteger (&lines_per_page); + make_cleanup_restore_uinteger (&chars_per_line); + + return back_to; +} + +/* Temporarily set BATCH_FLAG and the associated unlimited terminal size. + Provide cleanup for restoring the original state. */ + +struct cleanup * +set_batch_flag_and_make_cleanup_restore_page_info (void) +{ + struct cleanup *back_to = make_cleanup_restore_page_info (); + + make_cleanup_restore_integer (&batch_flag); + batch_flag = 1; + init_page_info (); + + return back_to; +} + /* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */ static void @@ -1633,7 +2250,7 @@ set_screen_size (void) rows = INT_MAX; if (cols <= 0) - rl_get_screen_size (NULL, &cols); + cols = INT_MAX; /* Update Readline's idea of the terminal size. */ rl_set_screen_size (rows, cols); @@ -1712,6 +2329,7 @@ prompt_for_continue (void) if (ignore) { char *p = ignore; + while (*p == ' ' || *p == '\t') ++p; if (p[0] == 'q') @@ -1724,7 +2342,7 @@ prompt_for_continue (void) need to save the ---Type --- line at the top of the screen. */ reinitialize_more_filter (); - dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */ + dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */ } /* Reinitialize filter; ie. tell it to reset to original values. */ @@ -1737,7 +2355,7 @@ reinitialize_more_filter (void) } /* Indicate that if the next sequence of characters overflows the line, - a newline should be inserted here rather than when it hits the end. + a newline should be inserted here rather than when it hits the end. If INDENT is non-null, it is a string to be printed to indent the wrapped part on the next line. INDENT must remain accessible until the next call to wrap_here() or until a newline is printed through @@ -1760,9 +2378,10 @@ reinitialize_more_filter (void) void wrap_here (char *indent) { - /* This should have been allocated, but be paranoid anyway. */ + /* This should have been allocated, but be paranoid anyway. */ if (!wrap_buffer) - internal_error (__FILE__, __LINE__, _("failed internal consistency check")); + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); if (wrap_buffer[0]) { @@ -1771,7 +2390,7 @@ wrap_here (char *indent) } wrap_pointer = wrap_buffer; wrap_buffer[0] = '\0'; - if (chars_per_line == UINT_MAX) /* No line overflow checking */ + if (chars_per_line == UINT_MAX) /* No line overflow checking. */ { wrap_column = 0; } @@ -1793,11 +2412,11 @@ wrap_here (char *indent) } /* Print input string to gdb_stdout, filtered, with wrap, - arranging strings in columns of n chars. String can be + arranging strings in columns of n chars. String can be right or left justified in the column. Never prints trailing spaces. String should never be longer than width. FIXME: this could be useful for the EXAMINE - command, which currently doesn't tabulate very well */ + command, which currently doesn't tabulate very well. */ void puts_filtered_tabular (char *string, int width, int right) @@ -1838,9 +2457,9 @@ puts_filtered_tabular (char *string, int width, int right) /* Ensure that whatever gets printed next, using the filtered output - commands, starts at the beginning of the line. I.E. if there is + commands, starts at the beginning of the line. I.e. if there is any pending output for the current line, flush it and start a new - line. Otherwise do nothing. */ + line. Otherwise do nothing. */ void begin_line (void) @@ -1875,8 +2494,12 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream, return; /* Don't do any filtering if it is disabled. */ - if ((stream != gdb_stdout) || !pagination_enabled - || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)) + if (stream != gdb_stdout + || ! pagination_enabled + || ! input_from_terminal_p () + || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX) + || top_level_interpreter () == NULL + || ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ()))) { fputs_unfiltered (linebuffer, stream); return; @@ -1934,16 +2557,16 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream, if (lines_printed >= lines_per_page - 1) prompt_for_continue (); - /* Now output indentation and wrapped string */ + /* Now output indentation and wrapped string. */ if (wrap_column) { fputs_unfiltered (wrap_indent, stream); - *wrap_pointer = '\0'; /* Null-terminate saved stuff */ - fputs_unfiltered (wrap_buffer, stream); /* and eject it */ + *wrap_pointer = '\0'; /* Null-terminate saved stuff, */ + fputs_unfiltered (wrap_buffer, stream); /* and eject it. */ /* FIXME, this strlen is what prevents wrap_indent from containing tabs. However, if we recurse to print it and count its chars, we risk trouble if wrap_indent is - longer than (the user settable) chars_per_line. + longer than (the user settable) chars_per_line. Note also that this can set chars_printed > chars_per_line if we are printing a long string. */ chars_printed = strlen (wrap_indent) @@ -1958,7 +2581,8 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream, if (*lineptr == '\n') { chars_printed = 0; - wrap_here ((char *) 0); /* Spit out chars, cancel further wraps */ + wrap_here ((char *) 0); /* Spit out chars, cancel + further wraps. */ lines_printed++; fputc_unfiltered ('\n', stream); lineptr++; @@ -1976,6 +2600,7 @@ int putchar_unfiltered (int c) { char buf = c; + ui_file_write (gdb_stdout, &buf, 1); return c; } @@ -1993,6 +2618,7 @@ int fputc_unfiltered (int c, struct ui_file *stream) { char buf = c; + ui_file_write (stream, &buf, 1); return c; } @@ -2135,7 +2761,26 @@ vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args) linebuffer = xstrvprintf (format, args); old_cleanups = make_cleanup (xfree, linebuffer); - fputs_unfiltered (linebuffer, stream); + if (debug_timestamp && stream == gdb_stdlog) + { + struct timeval tm; + char *timestamp; + int len, need_nl; + + gettimeofday (&tm, NULL); + + len = strlen (linebuffer); + need_nl = (len > 0 && linebuffer[len - 1] != '\n'); + + timestamp = xstrprintf ("%ld:%ld %s%s", + (long) tm.tv_sec, (long) tm.tv_usec, + linebuffer, + need_nl ? "\n": ""); + make_cleanup (xfree, timestamp); + fputs_unfiltered (timestamp, stream); + } + else + fputs_unfiltered (linebuffer, stream); do_cleanups (old_cleanups); } @@ -2155,6 +2800,7 @@ void fprintf_filtered (struct ui_file *stream, const char *format, ...) { va_list args; + va_start (args, format); vfprintf_filtered (stream, format, args); va_end (args); @@ -2164,6 +2810,7 @@ void fprintf_unfiltered (struct ui_file *stream, const char *format, ...) { va_list args; + va_start (args, format); vfprintf_unfiltered (stream, format, args); va_end (args); @@ -2177,6 +2824,7 @@ fprintfi_filtered (int spaces, struct ui_file *stream, const char *format, ...) { va_list args; + va_start (args, format); print_spaces_filtered (spaces, stream); @@ -2189,6 +2837,7 @@ void printf_filtered (const char *format, ...) { va_list args; + va_start (args, format); vfprintf_filtered (gdb_stdout, format, args); va_end (args); @@ -2199,6 +2848,7 @@ void printf_unfiltered (const char *format, ...) { va_list args; + va_start (args, format); vfprintf_unfiltered (gdb_stdout, format, args); va_end (args); @@ -2211,6 +2861,7 @@ void printfi_filtered (int spaces, const char *format, ...) { va_list args; + va_start (args, format); print_spaces_filtered (spaces, gdb_stdout); vfprintf_filtered (gdb_stdout, format, args); @@ -2269,7 +2920,7 @@ print_spaces_filtered (int n, struct ui_file *stream) /* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language LANG, using demangling args ARG_MODE, and print it filtered to STREAM. If the name is not mangled, or the language for the name is unknown, or - demangling is off, the name is printed in its "raw" form. */ + demangling is off, the name is printed in its "raw" form. */ void fprintf_symbol_filtered (struct ui_file *stream, char *name, @@ -2303,7 +2954,7 @@ fprintf_symbol_filtered (struct ui_file *stream, char *name, As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO". This "feature" is useful when searching for matching C++ function names (such as if the user types 'break FOO', where FOO is a mangled C++ - function). */ + function). */ int strcmp_iw (const char *string1, const char *string2) @@ -2430,6 +3081,7 @@ int subset_compare (char *string_to_compare, char *template_string) { int match; + if (template_string != (char *) NULL && string_to_compare != (char *) NULL && strlen (string_to_compare) <= strlen (template_string)) match = @@ -2451,13 +3103,19 @@ pagination_off_command (char *arg, int from_tty) { pagination_enabled = 0; } + +static void +show_debug_timestamp (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Timestamping debugging messages is %s.\n"), + value); +} void initialize_utils (void) { - struct cmd_list_element *c; - add_setshow_uinteger_cmd ("width", class_support, &chars_per_line, _("\ Set number of characters gdb thinks are in a line."), _("\ Show number of characters gdb thinks are in a line."), NULL, @@ -2511,15 +3169,24 @@ Show demangling of C++/ObjC names in disassembly listings."), NULL, NULL, show_asm_demangle, &setprintlist, &showprintlist); + + add_setshow_boolean_cmd ("timestamp", class_maintenance, + &debug_timestamp, _("\ +Set timestamping of debugging messages."), _("\ +Show timestamping of debugging messages."), _("\ +When set, debugging messages will be marked with seconds and microseconds."), + NULL, + show_debug_timestamp, + &setdebuglist, &showdebuglist); } -/* Machine specific function to handle SIGWINCH signal. */ +/* Machine specific function to handle SIGWINCH signal. */ #ifdef SIGWINCH_HANDLER_BODY SIGWINCH_HANDLER_BODY #endif -/* print routines to handle variable size regs, etc. */ -/* temporary storage using circular buffer */ +/* Print routines to handle variable size regs, etc. */ +/* Temporary storage using circular buffer. */ #define NUMCELLS 16 #define CELLSIZE 50 static char * @@ -2527,42 +3194,25 @@ get_cell (void) { static char buf[NUMCELLS][CELLSIZE]; static int cell = 0; + if (++cell >= NUMCELLS) cell = 0; return buf[cell]; } -int -strlen_paddr (void) -{ - return (TARGET_ADDR_BIT / 8 * 2); -} - -char * -paddr (CORE_ADDR addr) -{ - return phex (addr, TARGET_ADDR_BIT / 8); -} - -char * -paddr_nz (CORE_ADDR addr) -{ - return phex_nz (addr, TARGET_ADDR_BIT / 8); -} - const char * -paddress (CORE_ADDR addr) +paddress (struct gdbarch *gdbarch, CORE_ADDR addr) { /* Truncate address to the size of a target address, avoiding shifts larger or equal than the width of a CORE_ADDR. The local variable ADDR_BIT stops the compiler reporting a shift overflow - when it won't occur. */ + when it won't occur. */ /* NOTE: This assumes that the significant address information is kept in the least significant bits of ADDR - the upper bits were - either zero or sign extended. Should ADDRESS_TO_POINTER() or + either zero or sign extended. Should gdbarch_address_to_pointer or some ADDRESS_TO_PRINTABLE() be used to do the conversion? */ - int addr_bit = TARGET_ADDR_BIT; + int addr_bit = gdbarch_addr_bit (gdbarch); if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) addr &= ((CORE_ADDR) 1 << addr_bit) - 1; @@ -2573,11 +3223,11 @@ static char * decimal2str (char *sign, ULONGEST addr, int width) { /* Steal code from valprint.c:print_decimal(). Should this worry - about the real size of addr as the above does? */ + about the real size of addr as the above does? */ unsigned long temp[3]; char *str = get_cell (); - int i = 0; + do { temp[i] = addr % (1000 * 1000 * 1000); @@ -2617,8 +3267,8 @@ octal2str (ULONGEST addr, int width) { unsigned long temp[3]; char *str = get_cell (); - int i = 0; + do { temp[i] = addr % (0100000 * 0100000); @@ -2656,18 +3306,18 @@ octal2str (ULONGEST addr, int width) } char * -paddr_u (CORE_ADDR addr) +pulongest (ULONGEST u) { - return decimal2str ("", addr, 0); + return decimal2str ("", u, 0); } char * -paddr_d (LONGEST addr) +plongest (LONGEST l) { - if (addr < 0) - return decimal2str ("-", -addr, 0); + if (l < 0) + return decimal2str ("-", -l, 0); else - return decimal2str ("", addr, 0); + return decimal2str ("", l, 0); } /* Eliminate warning from compiler on 32-bit systems. */ @@ -2712,6 +3362,7 @@ phex_nz (ULONGEST l, int sizeof_l) case 8: { unsigned long high = (unsigned long) (l >> thirty_two); + str = get_cell (); if (high == 0) xsnprintf (str, CELLSIZE, "%lx", @@ -2743,6 +3394,7 @@ char * hex_string (LONGEST num) { char *result = get_cell (); + xsnprintf (result, CELLSIZE, "0x%s", phex_nz (num, sizeof (num))); return result; } @@ -2762,8 +3414,8 @@ hex_string_custom (LONGEST num, int width) if (hex_len > width) width = hex_len; if (width + 2 >= CELLSIZE) - internal_error (__FILE__, __LINE__, - _("hex_string_custom: insufficient space to store result")); + internal_error (__FILE__, __LINE__, _("\ +hex_string_custom: insufficient space to store result")); strcpy (result_end - width - 2, "0x"); memset (result_end - width, '0', width); @@ -2776,7 +3428,7 @@ hex_string_custom (LONGEST num, int width) * otherwise VAL is interpreted as unsigned. If WIDTH is supplied, * it is the minimum width (0-padded if needed). USE_C_FORMAT means * to use C format in all cases. If it is false, then 'x' - * and 'o' formats do not include a prefix (0x or leading 0). */ + * and 'o' formats do not include a prefix (0x or leading 0). */ char * int_string (LONGEST val, int radix, int is_signed, int width, @@ -2787,6 +3439,7 @@ int_string (LONGEST val, int radix, int is_signed, int width, case 16: { char *result; + if (width == 0) result = hex_string (val); else @@ -2805,6 +3458,7 @@ int_string (LONGEST val, int radix, int is_signed, int width, case 8: { char *result = octal2str (val, width); + if (use_c_format || val == 0) return result; else @@ -2821,6 +3475,7 @@ const char * core_addr_to_string (const CORE_ADDR addr) { char *str = get_cell (); + strcpy (str, "0x"); strcat (str, phex (addr, sizeof (addr))); return str; @@ -2830,6 +3485,7 @@ const char * core_addr_to_string_nz (const CORE_ADDR addr) { char *str = get_cell (); + strcpy (str, "0x"); strcat (str, phex_nz (addr, sizeof (addr))); return str; @@ -2840,10 +3496,12 @@ CORE_ADDR string_to_core_addr (const char *my_string) { CORE_ADDR addr = 0; + if (my_string[0] == '0' && tolower (my_string[1]) == 'x') { /* Assume that it is in hex. */ int i; + for (i = 2; my_string[i] != '\0'; i++) { if (isdigit (my_string[i])) @@ -2858,6 +3516,7 @@ string_to_core_addr (const char *my_string) { /* Assume that it is in decimal. */ int i; + for (i = 0; my_string[i] != '\0'; i++) { if (isdigit (my_string[i])) @@ -2866,9 +3525,19 @@ string_to_core_addr (const char *my_string) error (_("invalid decimal \"%s\""), my_string); } } + return addr; } +const char * +host_address_to_string (const void *addr) +{ + char *str = get_cell (); + + xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((uintptr_t) addr, sizeof (addr))); + return str; +} + char * gdb_realpath (const char *filename) { @@ -2887,6 +3556,7 @@ gdb_realpath (const char *filename) # endif # if defined (USE_REALPATH) const char *rp = realpath (filename, buf); + if (rp == NULL) rp = filename; return xstrdup (rp); @@ -2900,6 +3570,7 @@ gdb_realpath (const char *filename) #if defined(HAVE_CANONICALIZE_FILE_NAME) { char *rp = canonicalize_file_name (filename); + if (rp == NULL) return xstrdup (filename); else @@ -2927,11 +3598,13 @@ gdb_realpath (const char *filename) { /* Find out the max path size. */ long path_max = pathconf ("/", _PC_PATH_MAX); + if (path_max > 0) { /* PATH_MAX is bounded. */ char *buf = alloca (path_max); char *rp = realpath (filename, buf); + return xstrdup (rp ? rp : filename); } } @@ -2953,14 +3626,14 @@ xfullpath (const char *filename) char *result; /* Extract the basename of filename, and return immediately - a copy of filename if it does not contain any directory prefix. */ + a copy of filename if it does not contain any directory prefix. */ if (base_name == filename) return xstrdup (filename); dir_name = alloca ((size_t) (base_name - filename + 2)); /* Allocate enough space to store the dir_name + plus one extra character sometimes needed under Windows (see below), and - then the closing \000 character */ + then the closing \000 character. */ strncpy (dir_name, filename, base_name - filename); dir_name[base_name - filename] = '\000'; @@ -2975,13 +3648,13 @@ xfullpath (const char *filename) #endif /* Canonicalize the directory prefix, and build the resulting - filename. If the dirname realpath already contains an ending + filename. If the dirname realpath already contains an ending directory separator, avoid doubling it. */ real_path = gdb_realpath (dir_name); if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1])) - result = concat (real_path, base_name, (char *)NULL); + result = concat (real_path, base_name, (char *) NULL); else - result = concat (real_path, SLASH_STRING, base_name, (char *)NULL); + result = concat (real_path, SLASH_STRING, base_name, (char *) NULL); xfree (real_path); return result; @@ -2996,7 +3669,7 @@ xfullpath (const char *filename) unsigned long gnu_debuglink_crc32 (unsigned long crc, unsigned char *buf, size_t len) { - static const unsigned long crc32_table[256] = { + static const unsigned int crc32_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, @@ -3082,6 +3755,7 @@ hashtab_obstack_allocate (void *data, size_t size, size_t count) { unsigned int total = size * count; void *ptr = obstack_alloc ((struct obstack *) data, total); + memset (ptr, 0, total); return ptr; } @@ -3223,3 +3897,97 @@ ldirname (const char *filename) dirname[base - filename] = '\0'; return dirname; } + +/* Call libiberty's buildargv, and return the result. + If buildargv fails due to out-of-memory, call nomem. + Therefore, the returned value is guaranteed to be non-NULL, + unless the parameter itself is NULL. */ + +char ** +gdb_buildargv (const char *s) +{ + char **argv = buildargv (s); + + if (s != NULL && argv == NULL) + nomem (0); + return argv; +} + +int +compare_positive_ints (const void *ap, const void *bp) +{ + /* Because we know we're comparing two ints which are positive, + there's no danger of overflow here. */ + return * (int *) ap - * (int *) bp; +} + +#define AMBIGUOUS_MESS1 ".\nMatching formats:" +#define AMBIGUOUS_MESS2 \ + ".\nUse \"set gnutarget format-name\" to specify the format." + +const char * +gdb_bfd_errmsg (bfd_error_type error_tag, char **matching) +{ + char *ret, *retp; + int ret_len; + char **p; + + /* Check if errmsg just need simple return. */ + if (error_tag != bfd_error_file_ambiguously_recognized || matching == NULL) + return bfd_errmsg (error_tag); + + ret_len = strlen (bfd_errmsg (error_tag)) + strlen (AMBIGUOUS_MESS1) + + strlen (AMBIGUOUS_MESS2); + for (p = matching; *p; p++) + ret_len += strlen (*p) + 1; + ret = xmalloc (ret_len + 1); + retp = ret; + make_cleanup (xfree, ret); + + strcpy (retp, bfd_errmsg (error_tag)); + retp += strlen (retp); + + strcpy (retp, AMBIGUOUS_MESS1); + retp += strlen (retp); + + for (p = matching; *p; p++) + { + sprintf (retp, " %s", *p); + retp += strlen (retp); + } + xfree (matching); + + strcpy (retp, AMBIGUOUS_MESS2); + + return ret; +} + +/* Return ARGS parsed as a valid pid, or throw an error. */ + +int +parse_pid_to_attach (char *args) +{ + unsigned long pid; + char *dummy; + + if (!args) + error_no_arg (_("process-id to attach")); + + dummy = args; + pid = strtoul (args, &dummy, 0); + /* Some targets don't set errno on errors, grrr! */ + if ((pid == 0 && dummy == args) || dummy != &args[strlen (args)]) + error (_("Illegal process-id: %s."), args); + + return pid; +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_utils; + +void +_initialize_utils (void) +{ + add_internal_problem_command (&internal_error_problem); + add_internal_problem_command (&internal_warning_problem); +}