X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Futils.c;h=1096b3ad12eb18dc46cb3aa00eed65ca7423a739;hb=2479f722a449340bcd8465474090339c1e004e9e;hp=ccb92bd9ceae18117b04adaa40d7ba838d8492d6;hpb=0fe514e3a0202999dea5f06dcfd4bfcb726013cf;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/utils.c b/gdb/utils.c index ccb92bd9ce..1096b3ad12 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1,14 +1,12 @@ /* 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. + Copyright (C) 1986, 1988-2012 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,16 +15,20 @@ 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 "dyn-string.h" #include "gdb_assert.h" #include #include "gdb_string.h" +#include "gdb_wait.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,17 +38,18 @@ #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 #include +#include "timeval-utils.h" #include "gdbcmd.h" #include "serial.h" #include "bfd.h" #include "target.h" -#include "demangle.h" +#include "gdb-demangle.h" #include "expression.h" #include "language.h" #include "charset.h" @@ -54,7 +57,10 @@ #include "filenames.h" #include "symfile.h" #include "gdb_obstack.h" +#include "gdbcore.h" #include "top.h" +#include "main.h" +#include "solist.h" #include "inferior.h" /* for signed_pointer_to_address */ @@ -64,11 +70,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 +95,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 +106,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; @@ -131,33 +137,6 @@ int quit_flag; int immediate_quit; -/* Nonzero means that encoded C++/ObjC names should be printed out in their - C++/ObjC form rather than raw. */ - -int demangle = 1; -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"), - value); -} - -/* Nonzero means that encoded C++/ObjC names should be printed out in their - C++/ObjC form even in assembler language displays. If this is set, but - DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls. */ - -int asm_demangle = 0; -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"), - value); -} - /* Nonzero means that strings with character values >0x7F should be printed as octal escapes. Zero means just print the value (e.g. it's an international character, and the terminal or window can cope.) */ @@ -167,8 +146,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,39 +185,41 @@ 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) +make_final_cleanup (make_cleanup_ftype *function, void *arg) { - return make_my_cleanup (&run_cleanup_chain, function, arg); + return make_my_cleanup (&final_cleanup_chain, function, arg); } -struct cleanup * -make_exec_cleanup (make_cleanup_ftype *function, void *arg) +static void +do_freeargv (void *arg) { - return make_my_cleanup (&exec_cleanup_chain, function, arg); + freeargv ((char **) arg); } struct cleanup * -make_exec_error_cleanup (make_cleanup_ftype *function, void *arg) +make_cleanup_freeargv (char **arg) { - return make_my_cleanup (&exec_error_cleanup_chain, function, arg); + return make_my_cleanup (&cleanup_chain, do_freeargv, arg); } static void -do_freeargv (void *arg) +do_dyn_string_delete (void *arg) { - freeargv ((char **) arg); + dyn_string_delete ((dyn_string_t) arg); } struct cleanup * -make_cleanup_freeargv (char **arg) +make_cleanup_dyn_string_delete (dyn_string_t arg) { - return make_my_cleanup (&cleanup_chain, do_freeargv, arg); + return make_my_cleanup (&cleanup_chain, do_dyn_string_delete, arg); } static void @@ -257,16 +238,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 +299,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 +331,163 @@ 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); +} + +/* Helper for make_cleanup_htab_delete compile time checking the types. */ + +static void +do_htab_delete_cleanup (void *htab_voidp) +{ + htab_t htab = htab_voidp; + + htab_delete (htab); +} + +/* Return a new cleanup that deletes HTAB. */ + +struct cleanup * +make_cleanup_htab_delete (htab_t htab) +{ + return make_cleanup (do_htab_delete_cleanup, htab); +} + +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); +} + +/* Helper for make_cleanup_value_free_to_mark. */ + +static void +do_value_free_to_mark (void *value) +{ + value_free_to_mark ((struct value *) value); +} + +/* Free all values allocated since MARK was obtained by value_mark + (except for those released) when the cleanup is run. */ + +struct cleanup * +make_cleanup_value_free_to_mark (struct value *mark) +{ + return make_my_cleanup (&cleanup_chain, do_value_free_to_mark, mark); +} + +/* Helper for make_cleanup_value_free. */ + +static void +do_value_free (void *value) +{ + value_free (value); +} + +/* Free VALUE. */ + +struct cleanup * +make_cleanup_value_free (struct value *value) +{ + return make_my_cleanup (&cleanup_chain, do_value_free, value); +} + +/* Helper for make_cleanup_free_so. */ + +static void +do_free_so (void *arg) +{ + struct so_list *so = arg; + + free_so (so); +} + +/* Make cleanup handler calling free_so for SO. */ + +struct cleanup * +make_cleanup_free_so (struct so_list *so) +{ + return make_my_cleanup (&cleanup_chain, do_free_so, so); +} + +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 +495,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 +524,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 +555,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 +623,7 @@ void free_current_contents (void *ptr) { void **location = ptr; + if (location == NULL) internal_error (__FILE__, __LINE__, _("free_current_contents: NULL pointer")); @@ -453,141 +635,118 @@ free_current_contents (void *ptr) } /* Provide a known function that does nothing, to use as a base for - for a possibly long chain of cleanups. This is useful where we + a possibly long chain of cleanups. This is useful where we 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.*/ -void -add_continuation (void (*continuation_hook) (struct continuation_arg *), - struct continuation_arg *arg_list) -{ - struct continuation *continuation_ptr; - - 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; -} - -/* 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. */ -void -do_all_continuations (void) -{ - struct continuation *continuation_ptr; - struct continuation *saved_continuation; +/* If nonzero, display time usage both at startup and for each command. */ - /* 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; +static int display_time; - /* 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); - } -} +/* If nonzero, display space usage both at startup and for each command. */ -/* Walk down the cmd_continuation list, and get rid of all the - continuations. */ -void -discard_all_continuations (void) +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 { - struct continuation *continuation_ptr; + int msg_type; + long start_cpu_time; + struct timeval start_wall_time; + long start_space; +}; - while (cmd_continuation) - { - continuation_ptr = cmd_continuation; - cmd_continuation = continuation_ptr->next; - xfree (continuation_ptr); - } +/* Set whether to display time statistics to NEW_VALUE (non-zero + means true). */ +void +set_display_time (int new_value) +{ + display_time = new_value; } -/* Add a continuation to the continuation list, the global list - intermediate_continuation. The new continuation will be added at - the front. */ -void -add_intermediate_continuation (void (*continuation_hook) - (struct continuation_arg *), - struct continuation_arg *arg_list) -{ - struct continuation *continuation_ptr; - - 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; -} - -/* 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.*/ +/* Set whether to display space statistics to NEW_VALUE (non-zero + means true). */ void -do_all_intermediate_continuations (void) +set_display_space (int new_value) { - struct continuation *continuation_ptr; - struct continuation *saved_continuation; + display_space = new_value; +} - /* 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; +/* 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; - /* Work now on the list we have set aside. */ - while (continuation_ptr) + if (display_time) { - (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); - saved_continuation = continuation_ptr; - continuation_ptr = continuation_ptr->next; - xfree (saved_continuation); + long cmd_time = get_run_time () - start_stats->start_cpu_time; + struct timeval now_wall_time, delta_wall_time; + + gettimeofday (&now_wall_time, NULL); + timeval_sub (&delta_wall_time, + &now_wall_time, &start_stats->start_wall_time); + + printf_unfiltered (msg_type == 0 + ? _("Startup time: %ld.%06ld (cpu), %ld.%06ld (wall)\n") + : _("Command execution time: %ld.%06ld (cpu), %ld.%06ld (wall)\n"), + cmd_time / 1000000, cmd_time % 1000000, + (long) delta_wall_time.tv_sec, + (long) delta_wall_time.tv_usec); + } + + 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 (%s%ld during startup)\n") + : _("Space used: %ld (%s%ld for this command)\n"), + space_now, + (space_diff >= 0 ? "+" : ""), + space_diff); +#endif } } -/* Walk down the cmd_continuation list, and get rid of all the - continuations. */ -void -discard_all_intermediate_continuations (void) +/* 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 continuation *continuation_ptr; + 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 - while (intermediate_continuation) - { - continuation_ptr = intermediate_continuation; - intermediate_continuation = continuation_ptr->next; - xfree (continuation_ptr); - } + new_stat->msg_type = msg_type; + new_stat->start_cpu_time = get_run_time (); + gettimeofday (&new_stat->start_wall_time, NULL); + + return make_cleanup_dtor (report_command_stats, new_stat, xfree); } @@ -606,7 +765,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 +785,7 @@ void warning (const char *string, ...) { va_list args; + va_start (args, string); vwarning (string, args); va_end (args); @@ -635,16 +795,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 +815,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 *const 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 +921,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 +933,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 +955,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 (!confirm) + { + /* 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 +1019,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 +1028,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 +1062,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 +1187,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,10 +1237,10 @@ quit (void) /* Called when a memory allocation fails, with the number of bytes of - memory requested in SIZE. */ + memory requested in SIZE. */ -NORETURN void -nomem (long size) +void +malloc_failure (long size) { if (size > 0) { @@ -925,143 +1254,6 @@ nomem (long size) } } -/* The xmalloc() (libiberty.h) family of memory management routines. - - These are like the ISO-C malloc() family except that they implement - consistent semantics and guard against typical memory management - problems. */ - -/* NOTE: These are declared using PTR to ensure consistency with - "libiberty.h". xfree() is GDB local. */ - -PTR /* OK: PTR */ -xmalloc (size_t size) -{ - void *val; - - /* See libiberty/xmalloc.c. This function need's to match that's - semantics. It never returns NULL. */ - if (size == 0) - size = 1; - - val = malloc (size); /* OK: malloc */ - if (val == NULL) - nomem (size); - - return (val); -} - -void * -xzalloc (size_t size) -{ - return xcalloc (1, size); -} - -PTR /* OK: PTR */ -xrealloc (PTR ptr, size_t size) /* OK: PTR */ -{ - void *val; - - /* See libiberty/xmalloc.c. This function need's to match that's - semantics. It never returns NULL. */ - if (size == 0) - size = 1; - - if (ptr != NULL) - val = realloc (ptr, size); /* OK: realloc */ - else - val = malloc (size); /* OK: malloc */ - if (val == NULL) - nomem (size); - - return (val); -} - -PTR /* OK: PTR */ -xcalloc (size_t number, size_t size) -{ - void *mem; - - /* See libiberty/xmalloc.c. This function need's to match that's - semantics. It never returns NULL. */ - if (number == 0 || size == 0) - { - number = 1; - size = 1; - } - - mem = calloc (number, size); /* OK: xcalloc */ - if (mem == NULL) - nomem (number * size); - - return mem; -} - -void -xfree (void *ptr) -{ - if (ptr != NULL) - free (ptr); /* OK: free */ -} - - -/* Like asprintf/vasprintf but get an internal_error if the call - fails. */ - -char * -xstrprintf (const char *format, ...) -{ - char *ret; - va_list args; - va_start (args, format); - ret = xstrvprintf (format, args); - va_end (args); - return ret; -} - -void -xasprintf (char **ret, const char *format, ...) -{ - va_list args; - va_start (args, format); - (*ret) = xstrvprintf (format, args); - va_end (args); -} - -void -xvasprintf (char **ret, const char *format, va_list ap) -{ - (*ret) = xstrvprintf (format, ap); -} - -char * -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 - happen, but just to be sure. */ - if (ret == NULL || status < 0) - internal_error (__FILE__, __LINE__, _("vasprintf call failed")); - return ret; -} - -int -xsnprintf (char *str, size_t size, const char *format, ...) -{ - va_list args; - int ret; - - va_start (args, format); - ret = vsnprintf (str, size, format, args); - gdb_assert (ret < size); - va_end (args); - - return ret; -} - /* My replacement for the read system call. Used like `read' but keeps going if `read' returns too soon. */ @@ -1083,7 +1275,7 @@ myread (int desc, char *addr, int len) } return orglen; } - + /* Make a copy of the string at PTR with SIZE characters (and add a null character at the end in the copy). Uses malloc to get the space. Returns the address of the copy. */ @@ -1092,6 +1284,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 +1301,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); +} - /* 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. */ +/* Create a new cleanup that frees the compiled regular expression R. */ - fprintf_filtered (stream, "0x%lx", (unsigned long) addr); +struct cleanup * +make_regfree_cleanup (regex_t *r) +{ + return make_cleanup (do_regfree_cleanup, r); } + +/* 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); + + regerror (code, rx, result, length); + return result; +} + /* This function supports the query, nquery, and yquery functions. @@ -1127,7 +1346,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 +1383,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 (!confirm || 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 +1396,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 +1414,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 +1430,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 +1456,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 { @@ -1272,10 +1506,12 @@ int nquery (const char *ctlstr, ...) { va_list args; + int ret; va_start (args, ctlstr); - return defaulted_query (ctlstr, 'n', args); + ret = defaulted_query (ctlstr, 'n', args); va_end (args); + return ret; } /* Ask user a y-or-n question and return 0 if answer is no, 1 if @@ -1288,10 +1524,12 @@ int yquery (const char *ctlstr, ...) { va_list args; + int ret; va_start (args, ctlstr); - return defaulted_query (ctlstr, 'y', args); + ret = defaulted_query (ctlstr, 'y', args); va_end (args); + return ret; } /* Ask user a y-or-n question and return 1 iff answer is yes. @@ -1303,27 +1541,41 @@ int query (const char *ctlstr, ...) { va_list args; + int ret; va_start (args, ctlstr); - return defaulted_query (ctlstr, '\0', args); + ret = defaulted_query (ctlstr, '\0', args); va_end (args); + return ret; } -/* 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); - error (_("There is no control character `\\%s' in the `%s' character set."), - copy, target_charset ()); + if (obstack_object_size (&host_data) == 1) + { + result = 1; + *target_c = *(char *) obstack_base (&host_data); + } + + do_cleanups (cleanups); + return result; } /* Parse a C escape sequence. STRING_PTR points to a variable @@ -1342,57 +1594,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 +1616,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 +1634,50 @@ 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\nin 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 +1723,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 +1744,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 +1754,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 +1766,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 +1777,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 +1816,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 @@ -1611,14 +1856,52 @@ init_page_info (void) SIGWINCH_HANDLER (SIGWINCH); #endif - /* If the output is not a terminal, don't paginate it. */ - if (!ui_file_isatty (gdb_stdout)) - lines_per_page = UINT_MAX; -#endif - } + /* If the output is not a terminal, don't paginate it. */ + if (!ui_file_isatty (gdb_stdout)) + lines_per_page = UINT_MAX; +#endif + } + + set_screen_size (); + 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. */ - set_screen_size (); - set_width (); +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. */ @@ -1633,7 +1916,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 +1995,7 @@ prompt_for_continue (void) if (ignore) { char *p = ignore; + while (*p == ' ' || *p == '\t') ++p; if (p[0] == 'q') @@ -1724,7 +2008,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 +2021,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 +2044,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 +2056,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 +2078,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 +2123,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 +2160,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 + || batch_flag + || (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 +2223,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 +2247,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 +2266,7 @@ int putchar_unfiltered (int c) { char buf = c; + ui_file_write (gdb_stdout, &buf, 1); return c; } @@ -1993,6 +2284,7 @@ int fputc_unfiltered (int c, struct ui_file *stream) { char buf = c; + ui_file_write (stream, &buf, 1); return c; } @@ -2135,7 +2427,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 +2466,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 +2476,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 +2490,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 +2503,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 +2514,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 +2527,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,10 +2586,10 @@ 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, +fprintf_symbol_filtered (struct ui_file *stream, const char *name, enum language lang, int arg_mode) { char *demangled; @@ -2303,7 +2620,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) @@ -2318,10 +2635,12 @@ strcmp_iw (const char *string1, const char *string2) { string2++; } - if (*string1 != *string2) - { - break; - } + if (case_sensitivity == case_sensitive_on && *string1 != *string2) + break; + if (case_sensitivity == case_sensitive_off + && (tolower ((unsigned char) *string1) + != tolower ((unsigned char) *string2))) + break; if (*string1 != '\0') { string1++; @@ -2342,6 +2661,10 @@ strcmp_iw (const char *string1, const char *string2) strcmp_iw(LIST_ELT, NAME), then the place to start looking is right where this function would put NAME. + This function must be neutral to the CASE_SENSITIVITY setting as the user + may choose it during later lookup. Therefore this function always sorts + primarily case-insensitively and secondarily case-sensitively. + Here are some examples of why using strcmp to sort is a bad idea: Whitespace example: @@ -2367,47 +2690,78 @@ strcmp_iw (const char *string1, const char *string2) int strcmp_iw_ordered (const char *string1, const char *string2) { - while ((*string1 != '\0') && (*string2 != '\0')) + const char *saved_string1 = string1, *saved_string2 = string2; + enum case_sensitivity case_pass = case_sensitive_off; + + for (;;) { - while (isspace (*string1)) - { - string1++; - } - while (isspace (*string2)) - { - string2++; - } - if (*string1 != *string2) + /* C1 and C2 are valid only if *string1 != '\0' && *string2 != '\0'. + Provide stub characters if we are already at the end of one of the + strings. */ + char c1 = 'X', c2 = 'X'; + + while (*string1 != '\0' && *string2 != '\0') { - break; + while (isspace (*string1)) + string1++; + while (isspace (*string2)) + string2++; + + switch (case_pass) + { + case case_sensitive_off: + c1 = tolower ((unsigned char) *string1); + c2 = tolower ((unsigned char) *string2); + break; + case case_sensitive_on: + c1 = *string1; + c2 = *string2; + break; + } + if (c1 != c2) + break; + + if (*string1 != '\0') + { + string1++; + string2++; + } } - if (*string1 != '\0') + + switch (*string1) { - string1++; - string2++; + /* Characters are non-equal unless they're both '\0'; we want to + make sure we get the comparison right according to our + comparison in the cases where one of them is '\0' or '('. */ + case '\0': + if (*string2 == '\0') + break; + else + return -1; + case '(': + if (*string2 == '\0') + return 1; + else + return -1; + default: + if (*string2 == '\0' || *string2 == '(') + return 1; + else if (c1 > c2) + return 1; + else if (c1 < c2) + return -1; + /* PASSTHRU */ } - } - switch (*string1) - { - /* Characters are non-equal unless they're both '\0'; we want to - make sure we get the comparison right according to our - comparison in the cases where one of them is '\0' or '('. */ - case '\0': - if (*string2 == '\0') + if (case_pass == case_sensitive_on) return 0; - else - return -1; - case '(': - if (*string2 == '\0') - return 1; - else - return -1; - default: - if (*string2 == '(') - return 1; - else - return *string1 - *string2; + + /* Otherwise the strings were equal in case insensitive way, make + a more fine grained comparison in a case sensitive way. */ + + case_pass = case_sensitive_on; + string1 = saved_string1; + string2 = saved_string2; } } @@ -2430,6 +2784,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 +2806,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, @@ -2474,13 +2835,6 @@ Show number of lines gdb thinks are in a page."), NULL, init_page_info (); - add_setshow_boolean_cmd ("demangle", class_support, &demangle, _("\ -Set demangling of encoded C++/ObjC names when displaying symbols."), _("\ -Show demangling of encoded C++/ObjC names when displaying symbols."), NULL, - NULL, - show_demangle, - &setprintlist, &showprintlist); - add_setshow_boolean_cmd ("pagination", class_support, &pagination_enabled, _("\ Set state of pagination."), _("\ @@ -2505,21 +2859,23 @@ Show printing of 8-bit characters in strings as \\nnn."), NULL, show_sevenbit_strings, &setprintlist, &showprintlist); - add_setshow_boolean_cmd ("asm-demangle", class_support, &asm_demangle, _("\ -Set demangling of C++/ObjC names in disassembly listings."), _("\ -Show demangling of C++/ObjC names in disassembly listings."), NULL, + 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_asm_demangle, - &setprintlist, &showprintlist); + 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,57 +2883,80 @@ 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; return hex_string (addr); } +/* This function is described in "defs.h". */ + +const char * +print_core_address (struct gdbarch *gdbarch, CORE_ADDR address) +{ + int addr_bit = gdbarch_addr_bit (gdbarch); + + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + address &= ((CORE_ADDR) 1 << addr_bit) - 1; + + /* FIXME: cagney/2002-05-03: Need local_address_string() function + that returns the language localized string formatted to a width + based on gdbarch_addr_bit. */ + if (addr_bit <= 32) + return hex_string_custom (address, 8); + else + return hex_string_custom (address, 16); +} + +/* Callback hash_f for htab_create_alloc or htab_create_alloc_ex. */ + +hashval_t +core_addr_hash (const void *ap) +{ + const CORE_ADDR *addrp = ap; + + return *addrp; +} + +/* Callback eq_f for htab_create_alloc or htab_create_alloc_ex. */ + +int +core_addr_eq (const void *ap, const void *bp) +{ + const CORE_ADDR *addr_ap = ap; + const CORE_ADDR *addr_bp = bp; + + return *addr_ap == *addr_bp; +} + 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 +2996,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 +3035,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 +3091,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 +3123,7 @@ char * hex_string (LONGEST num) { char *result = get_cell (); + xsnprintf (result, CELLSIZE, "0x%s", phex_nz (num, sizeof (num))); return result; } @@ -2762,8 +3143,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 +3157,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 +3168,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 +3187,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 +3204,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 +3214,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 +3225,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 decimal. */ + /* Assume that it is in hex. */ int i; + for (i = 2; my_string[i] != '\0'; i++) { if (isdigit (my_string[i])) @@ -2858,6 +3245,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 +3254,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 +3285,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 +3299,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 @@ -2910,7 +3310,7 @@ gdb_realpath (const char *filename) /* FIXME: cagney/2002-11-13: Method 2a: Use realpath() with a NULL buffer. Some systems, due - to the problems described in in method 3, have modified their + to the problems described in method 3, have modified their realpath() implementation so that it will allocate a buffer when NULL is passed in. Before this can be used, though, some sort of configure time test would need to be added. Otherwize the code @@ -2927,16 +3327,37 @@ 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); } } #endif + /* The MS Windows method. If we don't have realpath, we assume we + don't have symlinks and just canonicalize to a Windows absolute + path. GetFullPath converts ../ and ./ in relative paths to + absolute paths, filling in current drive if one is not given + or using the current directory of a specified drive (eg, "E:foo"). + It also converts all forward slashes to back slashes. */ + /* The file system is case-insensitive but case-preserving. + So we do not lowercase the path. Otherwise, we might not + be able to display the original casing in a given path. */ +#if defined (_WIN32) + { + char buf[MAX_PATH]; + DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL); + + if (len > 0 && len < MAX_PATH) + return xstrdup (buf); + } +#endif + /* This system is a lost cause, just dup the buffer. */ return xstrdup (filename); } @@ -2953,14 +3374,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 +3396,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 +3417,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, @@ -3055,7 +3476,7 @@ gnu_debuglink_crc32 (unsigned long crc, unsigned char *buf, size_t len) crc = ~crc & 0xffffffff; for (end = buf + len; buf < end; ++buf) crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return ~crc & 0xffffffff;; + return ~crc & 0xffffffff; } ULONGEST @@ -3082,6 +3503,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; } @@ -3195,3 +3617,269 @@ strtoulst (const char *num, const char **trailer, int base) else return result; } + +/* Simple, portable version of dirname that does not modify its + argument. */ + +char * +ldirname (const char *filename) +{ + const char *base = lbasename (filename); + char *dirname; + + while (base > filename && IS_DIR_SEPARATOR (base[-1])) + --base; + + if (base == filename) + return NULL; + + dirname = xmalloc (base - filename + 2); + memcpy (dirname, filename, base - filename); + + /* On DOS based file systems, convert "d:foo" to "d:.", so that we + create "d:./bar" later instead of the (different) "d:/bar". */ + if (base - filename == 2 && IS_ABSOLUTE_PATH (base) + && !IS_DIR_SEPARATOR (filename[0])) + dirname[base++ - 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) + malloc_failure (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; +} + +/* String compare function for qsort. */ + +int +compare_strings (const void *arg1, const void *arg2) +{ + const char **s1 = (const char **) arg1; + const char **s2 = (const char **) arg2; + + return strcmp (*s1, *s2); +} + +#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; +} + +/* Helper for make_bpstat_clear_actions_cleanup. */ + +static void +do_bpstat_clear_actions_cleanup (void *unused) +{ + bpstat_clear_actions (); +} + +/* Call bpstat_clear_actions for the case an exception is throw. You should + discard_cleanups if no exception is caught. */ + +struct cleanup * +make_bpstat_clear_actions_cleanup (void) +{ + return make_cleanup (do_bpstat_clear_actions_cleanup, NULL); +} + +/* Check for GCC >= 4.x according to the symtab->producer string. Return minor + version (x) of 4.x in such case. If it is not GCC or it is GCC older than + 4.x return -1. If it is GCC 5.x or higher return INT_MAX. */ + +int +producer_is_gcc_ge_4 (const char *producer) +{ + const char *cs; + int major, minor; + + if (producer == NULL) + { + /* For unknown compilers expect their behavior is not compliant. For GCC + this case can also happen for -gdwarf-4 type units supported since + gcc-4.5. */ + + return -1; + } + + /* Skip any identifier after "GNU " - such as "C++" or "Java". */ + + if (strncmp (producer, "GNU ", strlen ("GNU ")) != 0) + { + /* For non-GCC compilers expect their behavior is not compliant. */ + + return -1; + } + cs = &producer[strlen ("GNU ")]; + while (*cs && !isdigit (*cs)) + cs++; + if (sscanf (cs, "%d.%d", &major, &minor) != 2) + { + /* Not recognized as GCC. */ + + return -1; + } + + if (major < 4) + return -1; + if (major > 4) + return INT_MAX; + return minor; +} + +#ifdef HAVE_WAITPID + +#ifdef SIGALRM + +/* SIGALRM handler for waitpid_with_timeout. */ + +static void +sigalrm_handler (int signo) +{ + /* Nothing to do. */ +} + +#endif + +/* Wrapper to wait for child PID to die with TIMEOUT. + TIMEOUT is the time to stop waiting in seconds. + If TIMEOUT is zero, pass WNOHANG to waitpid. + Returns PID if it was successfully waited for, otherwise -1. + + Timeouts are currently implemented with alarm and SIGALRM. + If the host does not support them, this waits "forever". + It would be odd though for a host to have waitpid and not SIGALRM. */ + +pid_t +wait_to_die_with_timeout (pid_t pid, int *status, int timeout) +{ + pid_t waitpid_result; + + gdb_assert (pid > 0); + gdb_assert (timeout >= 0); + + if (timeout > 0) + { +#ifdef SIGALRM +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + struct sigaction sa, old_sa; + + sa.sa_handler = sigalrm_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGALRM, &sa, &old_sa); +#else + void (*ofunc) (); + + ofunc = (void (*)()) signal (SIGALRM, sigalrm_handler); +#endif + + alarm (timeout); +#endif + + waitpid_result = waitpid (pid, status, 0); + +#ifdef SIGALRM + alarm (0); +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + sigaction (SIGALRM, &old_sa, NULL); +#else + signal (SIGALRM, ofunc); +#endif +#endif + } + else + waitpid_result = waitpid (pid, status, WNOHANG); + + if (waitpid_result == pid) + return pid; + else + return -1; +} + +#endif /* HAVE_WAITPID */ + +/* 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); +}