X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Futils.c;h=b957b0dc5c290546f52178f5183046659c30e3d9;hb=05b1d8d6fcde4805d25c9121f5b051f59580887a;hp=a802bfa20933176e1528e197c2e1ffcf85e86624;hpb=6dddc817c1680fc97756cbcb017fcf306fa5d07c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/utils.c b/gdb/utils.c index a802bfa209..b957b0dc5c 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1,6 +1,6 @@ /* General utility routines for GDB, the GNU debugger. - Copyright (C) 1986-2014 Free Software Foundation, Inc. + Copyright (C) 1986-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -18,13 +18,9 @@ along with this program. If not, see . */ #include "defs.h" -#include "dyn-string.h" -#include "gdb_assert.h" #include -#include #include "gdb_wait.h" #include "event-top.h" -#include "exceptions.h" #include "gdbthread.h" #include "fnmatch.h" #include "gdb_bfd.h" @@ -41,7 +37,6 @@ #endif #include -#include "timeval-utils.h" #include "gdbcmd.h" #include "serial.h" #include "bfd.h" @@ -65,12 +60,17 @@ #include "readline/readline.h" -#include -#include +#include #include "gdb_usleep.h" #include "interps.h" #include "gdb_regex.h" +#include "job-control.h" +#include "common/selftest.h" +#include "common/gdb_optional.h" +#include "cp-support.h" +#include +#include "common/pathstuff.h" #if !HAVE_DECL_MALLOC extern PTR malloc (); /* ARI: PTR */ @@ -102,29 +102,12 @@ static void set_width (void); Modified in prompt_for_continue and defaulted_query. Used in report_command_stats. */ -static struct timeval prompt_for_continue_wait_time; +static std::chrono::steady_clock::duration prompt_for_continue_wait_time; /* A flag indicating whether to timestamp debugging messages. */ static int debug_timestamp = 0; -/* Nonzero if we have job control. */ - -int job_control; - -/* Nonzero means quit immediately if Control-C is typed now, rather - than waiting until QUIT is executed. Be careful in setting this; - code which executes with immediate_quit set has to be very careful - about being able to deal with being interrupted at any time. It is - almost always better to use QUIT; the only exception I can think of - is being able to quit out of a system call (using EINTR loses if - the SIGINT happens between the previous QUIT and the system call). - To immediately quit in the case in which a SIGINT happens between - the previous QUIT and setting immediate_quit (desirable anytime we - expect to block), call QUIT after setting immediate_quit. */ - -int immediate_quit; - /* 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.) */ @@ -141,7 +124,7 @@ show_sevenbit_strings (struct ui_file *file, int from_tty, /* String to be printed before warning messages, if any. */ -char *warning_pre_print = "\nwarning: "; +const char *warning_pre_print = "\nwarning: "; int pagination_enabled = 1; static void @@ -158,241 +141,6 @@ show_pagination_enabled (struct ui_file *file, int from_tty, because while they use the "cleanup API" they are not part of the "cleanup API". */ -static void -do_freeargv (void *arg) -{ - freeargv ((char **) arg); -} - -struct cleanup * -make_cleanup_freeargv (char **arg) -{ - return make_cleanup (do_freeargv, arg); -} - -static void -do_dyn_string_delete (void *arg) -{ - dyn_string_delete ((dyn_string_t) arg); -} - -struct cleanup * -make_cleanup_dyn_string_delete (dyn_string_t arg) -{ - return make_cleanup (do_dyn_string_delete, arg); -} - -static void -do_bfd_close_cleanup (void *arg) -{ - gdb_bfd_unref (arg); -} - -struct cleanup * -make_cleanup_bfd_unref (bfd *abfd) -{ - return make_cleanup (do_bfd_close_cleanup, abfd); -} - -static void -do_close_cleanup (void *arg) -{ - int *fd = arg; - - close (*fd); -} - -struct cleanup * -make_cleanup_close (int fd) -{ - int *saved_fd = xmalloc (sizeof (fd)); - - *saved_fd = 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 -do_ui_file_delete (void *arg) -{ - ui_file_delete (arg); -} - -struct cleanup * -make_cleanup_ui_file_delete (struct ui_file *arg) -{ - return make_cleanup (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_cleanup (do_ui_out_redirect_pop, uiout); -} - -static void -do_free_section_addr_info (void *arg) -{ - free_section_addr_info (arg); -} - -struct cleanup * -make_cleanup_free_section_addr_info (struct section_addr_info *addrs) -{ - return make_cleanup (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_cleanup_restore_integer (int *variable) -{ - struct restore_integer_closure *c = - xmalloc (sizeof (struct restore_integer_closure)); - - c->variable = variable; - c->value = *variable; - - return make_cleanup_dtor (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_cleanup (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 @@ -410,62 +158,6 @@ make_cleanup_value_free_to_mark (struct value *mark) return make_cleanup (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_cleanup (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_cleanup (do_free_so, so); -} - -/* Helper for make_cleanup_restore_current_language. */ - -static void -do_restore_current_language (void *p) -{ - enum language saved_lang = (uintptr_t) p; - - set_language (saved_lang); -} - -/* Remember the current value of CURRENT_LANGUAGE and make it restored when - the cleanup is run. */ - -struct cleanup * -make_cleanup_restore_current_language (void) -{ - enum language saved_lang = current_language->la_language; - - return make_cleanup (do_restore_current_language, - (void *) (uintptr_t) saved_lang); -} - /* This function is useful for cleanups. Do @@ -477,7 +169,7 @@ make_cleanup_restore_current_language (void) void free_current_contents (void *ptr) { - void **location = ptr; + void **location = (void **) ptr; if (location == NULL) internal_error (__FILE__, __LINE__, @@ -504,33 +196,22 @@ vwarning (const char *string, va_list args) (*deprecated_warning_hook) (string, args); else { - target_terminal_ours (); - wrap_here (""); /* Force out any buffered output. */ + gdb::optional term_state; + if (target_supports_terminal_ours ()) + { + term_state.emplace (); + target_terminal::ours_for_output (); + } + if (filtered_printing_initialized ()) + wrap_here (""); /* Force out any buffered output. */ gdb_flush (gdb_stdout); if (warning_pre_print) fputs_unfiltered (warning_pre_print, gdb_stderr); vfprintf_unfiltered (gdb_stderr, string, args); fprintf_unfiltered (gdb_stderr, "\n"); - va_end (args); } } -/* Print a warning message. - The first argument STRING is the warning message, used as a fprintf string, - and the remaining args are passed as arguments to it. - The primary difference between warnings and errors is that a warning - does not force the return to command level. */ - -void -warning (const char *string, ...) -{ - va_list args; - - va_start (args, string); - vwarning (string, args); - va_end (args); -} - /* Print an error message and return to command level. The first argument STRING is the error message, used as a fprintf string, and the remaining args are passed as arguments to it. */ @@ -542,47 +223,27 @@ verror (const char *string, va_list args) } void -error (const char *string, ...) -{ - va_list args; - - va_start (args, string); - throw_verror (GENERIC_ERROR, string, args); - va_end (args); -} - -/* Print an error message and quit. - The first argument STRING is the error message, used as a fprintf string, - and the remaining args are passed as arguments to it. */ - -void -vfatal (const char *string, va_list args) +error_stream (const string_file &stream) { - throw_vfatal (string, args); + error (("%s"), stream.c_str ()); } -void -fatal (const char *string, ...) -{ - va_list args; +/* Emit a message and abort. */ - va_start (args, string); - throw_vfatal (string, args); - va_end (args); -} - -void -error_stream (struct ui_file *stream) +static void ATTRIBUTE_NORETURN +abort_with_message (const char *msg) { - char *message = ui_file_xstrdup (stream, NULL); + if (current_ui == NULL) + fputs (msg, stderr); + else + fputs_unfiltered (msg, gdb_stderr); - make_cleanup (xfree, message); - error (("%s"), message); + abort (); /* NOTE: GDB has only three calls to abort(). */ } /* Dump core trying to increase the core soft limit to hard limit first. */ -static void +void dump_core (void) { #ifdef HAVE_SETRLIMIT @@ -595,10 +256,12 @@ dump_core (void) } /* Check whether GDB will be able to dump core using the dump_core - function. */ + function. Returns zero if GDB cannot or should not dump core. + If LIMIT_KIND is LIMIT_CUR the user's soft limit will be respected. + If LIMIT_KIND is LIMIT_MAX only the hard limit will be respected. */ -static int -can_dump_core (const char *reason) +int +can_dump_core (enum resource_limit_kind limit_kind) { #ifdef HAVE_GETRLIMIT struct rlimit rlim; @@ -607,19 +270,47 @@ can_dump_core (const char *reason) if (getrlimit (RLIMIT_CORE, &rlim) != 0) return 1; - if (rlim.rlim_max == 0) + switch (limit_kind) { - fprintf_unfiltered (gdb_stderr, - _("%s\nUnable to dump core, use `ulimit -c" - " unlimited' before executing GDB next time.\n"), - reason); - return 0; + case LIMIT_CUR: + if (rlim.rlim_cur == 0) + return 0; + + case LIMIT_MAX: + if (rlim.rlim_max == 0) + return 0; } #endif /* HAVE_GETRLIMIT */ return 1; } +/* Print a warning that we cannot dump core. */ + +void +warn_cant_dump_core (const char *reason) +{ + fprintf_unfiltered (gdb_stderr, + _("%s\nUnable to dump core, use `ulimit -c" + " unlimited' before executing GDB next time.\n"), + reason); +} + +/* Check whether GDB will be able to dump core using the dump_core + function, and print a warning if we cannot. */ + +static int +can_dump_core_warn (enum resource_limit_kind limit_kind, + const char *reason) +{ + int core_dump_allowed = can_dump_core (limit_kind); + + if (!core_dump_allowed) + warn_cant_dump_core (reason); + + return core_dump_allowed; +} + /* Allow the user to configure the debugger behavior with respect to what to do when an internal problem is detected. */ @@ -641,7 +332,9 @@ static const char *const internal_problem_modes[] = struct internal_problem { const char *name; + int user_settable_should_quit; const char *should_quit; + int user_settable_should_dump_core; const char *should_dump_core; }; @@ -656,8 +349,7 @@ internal_vproblem (struct internal_problem *problem, static int dejavu; int quit_p; int dump_core_p; - char *reason; - struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); + std::string reason; /* Don't allow infinite error/warning recursion. */ { @@ -670,8 +362,7 @@ internal_vproblem (struct internal_problem *problem, break; case 1: dejavu = 2; - fputs_unfiltered (msg, gdb_stderr); - abort (); /* NOTE: GDB has only three calls to abort(). */ + abort_with_message (msg); default: dejavu = 3; /* Newer GLIBC versions put the warn_unused_result attribute @@ -685,41 +376,52 @@ internal_vproblem (struct internal_problem *problem, } } - /* Try to get the message out and at the start of a new line. */ - target_terminal_ours (); - begin_line (); - /* Create a string containing the full error/warning message. Need to call query with this full string, as otherwize the reason (error/warning) and question become separated. Format using a style similar to a compiler error message. Include extra detail 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); - xfree (msg); - make_cleanup (xfree, reason); + std::string msg = string_vprintf (fmt, ap); + reason = string_printf ("%s:%d: %s: %s\n" + "A problem internal to GDB has been detected,\n" + "further debugging may prove unreliable.", + file, line, problem->name, msg.c_str ()); } + /* Fall back to abort_with_message if gdb_stderr is not set up. */ + if (current_ui == NULL) + { + fputs (reason.c_str (), stderr); + abort_with_message ("\n"); + } + + /* Try to get the message out and at the start of a new line. */ + gdb::optional term_state; + if (target_supports_terminal_ours ()) + { + term_state.emplace (); + target_terminal::ours_for_output (); + } + if (filtered_printing_initialized ()) + begin_line (); + + /* Emit the message unless query will emit it below. */ + if (problem->should_quit != internal_problem_ask + || !confirm + || !filtered_printing_initialized ()) + fprintf_unfiltered (gdb_stderr, "%s\n", reason.c_str ()); + if (problem->should_quit == internal_problem_ask) { /* Default (yes/batch case) is to quit GDB. When in batch mode 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; - } + if (!confirm || !filtered_printing_initialized ()) + quit_p = 1; else - quit_p = query (_("%s\nQuit this debugging session? "), reason); + quit_p = query (_("%s\nQuit this debugging session? "), + reason.c_str ()); } else if (problem->should_quit == internal_problem_yes) quit_p = 1; @@ -728,20 +430,29 @@ internal_vproblem (struct internal_problem *problem, else internal_error (__FILE__, __LINE__, _("bad switch")); + fputs_unfiltered (_("\nThis is a bug, please report it."), gdb_stderr); + if (REPORT_BUGS_TO[0]) + fprintf_unfiltered (gdb_stderr, _(" For instructions, see:\n%s."), + REPORT_BUGS_TO); + fputs_unfiltered ("\n\n", gdb_stderr); + if (problem->should_dump_core == internal_problem_ask) { - if (!can_dump_core (reason)) + if (!can_dump_core_warn (LIMIT_MAX, reason.c_str ())) dump_core_p = 0; + else if (!filtered_printing_initialized ()) + dump_core_p = 1; 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); + dump_core_p = query (_("%s\nCreate a core file of GDB? "), + reason.c_str ()); } } else if (problem->should_dump_core == internal_problem_yes) - dump_core_p = can_dump_core (reason); + dump_core_p = can_dump_core_warn (LIMIT_MAX, reason.c_str ()); else if (problem->should_dump_core == internal_problem_no) dump_core_p = 0; else @@ -766,59 +477,58 @@ internal_vproblem (struct internal_problem *problem, } dejavu = 0; - do_cleanups (cleanup); } static struct internal_problem internal_error_problem = { - "internal-error", internal_problem_ask, internal_problem_ask + "internal-error", 1, internal_problem_ask, 1, internal_problem_ask }; void internal_verror (const char *file, int line, const char *fmt, va_list ap) { internal_vproblem (&internal_error_problem, file, line, fmt, ap); - fatal (_("Command aborted.")); + throw_quit (_("Command aborted.")); } +static struct internal_problem internal_warning_problem = { + "internal-warning", 1, internal_problem_ask, 1, internal_problem_ask +}; + void -internal_error (const char *file, int line, const char *string, ...) +internal_vwarning (const char *file, int line, const char *fmt, va_list ap) { - va_list ap; - - va_start (ap, string); - internal_verror (file, line, string, ap); - va_end (ap); + internal_vproblem (&internal_warning_problem, file, line, fmt, ap); } -static struct internal_problem internal_warning_problem = { - "internal-warning", internal_problem_ask, internal_problem_ask +static struct internal_problem demangler_warning_problem = { + "demangler-warning", 1, internal_problem_ask, 0, internal_problem_no }; void -internal_vwarning (const char *file, int line, const char *fmt, va_list ap) +demangler_vwarning (const char *file, int line, const char *fmt, va_list ap) { - internal_vproblem (&internal_warning_problem, file, line, fmt, ap); + internal_vproblem (&demangler_warning_problem, file, line, fmt, ap); } void -internal_warning (const char *file, int line, const char *string, ...) +demangler_warning (const char *file, int line, const char *string, ...) { va_list ap; va_start (ap, string); - internal_vwarning (file, line, string, ap); + demangler_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) +set_internal_problem_cmd (const char *args, int from_tty) { } static void -show_internal_problem_cmd (char *args, int from_tty) +show_internal_problem_cmd (const char *args, int from_tty) { } @@ -845,8 +555,8 @@ add_internal_problem_command (struct internal_problem *problem) 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 = XNEW (struct cmd_list_element *); + show_cmd_list = XNEW (struct cmd_list_element *); *set_cmd_list = NULL; *show_cmd_list = NULL; @@ -856,79 +566,77 @@ add_internal_problem_command (struct internal_problem *problem) show_doc = xstrprintf (_("Show what GDB does when %s is detected."), problem->name); - add_prefix_cmd ((char*) problem->name, + add_prefix_cmd (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, + add_prefix_cmd (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); + if (problem->user_settable_should_quit) + { + 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); + } + + if (problem->user_settable_should_dump_core) + { + 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); + } } /* Return a newly allocated string, containing the PREFIX followed - by the system error message for errno (separated by a colon). - - The result must be deallocated after use. */ + by the system error message for errno (separated by a colon). */ -static char * +static std::string perror_string (const char *prefix) { char *err; - char *combined; err = safe_strerror (errno); - combined = (char *) xmalloc (strlen (err) + strlen (prefix) + 3); - strcpy (combined, prefix); - strcat (combined, ": "); - strcat (combined, err); - - return combined; + return std::string (prefix) + ": " + err; } /* Print the system error message for errno, and also mention STRING @@ -938,10 +646,7 @@ perror_string (const char *prefix) void throw_perror_with_name (enum errors errcode, const char *string) { - char *combined; - - combined = perror_string (string); - make_cleanup (xfree, combined); + std::string combined = perror_string (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 @@ -949,7 +654,7 @@ throw_perror_with_name (enum errors errcode, const char *string) bfd_set_error (bfd_error_no_error); errno = 0; - throw_error (errcode, _("%s."), combined); + throw_error (errcode, _("%s."), combined.c_str ()); } /* See throw_perror_with_name, ERRCODE defaults here to GENERIC_ERROR. */ @@ -966,11 +671,8 @@ perror_with_name (const char *string) void perror_warning_with_name (const char *string) { - char *combined; - - combined = perror_string (string); - warning (_("%s"), combined); - xfree (combined); + std::string combined = perror_string (string); + warning (_("%s"), combined.c_str ()); } /* Print the system error message for ERRCODE, and also mention STRING @@ -999,21 +701,41 @@ print_sys_errmsg (const char *string, int errcode) void quit (void) { + if (sync_quit_force_run) + { + sync_quit_force_run = 0; + quit_force (NULL, 0); + } + #ifdef __MSDOS__ /* No steenking SIGINT will ever be coming our way when the program is resumed. Don't lie. */ - fatal ("Quit"); + throw_quit ("Quit"); #else if (job_control /* If there is no terminal switching for this target, then we can't possibly get screwed by the lack of job control. */ - || current_target.to_terminal_ours == NULL) - fatal ("Quit"); + || !target_supports_terminal_ours ()) + throw_quit ("Quit"); else - fatal ("Quit (expect signal SIGINT when the program is resumed)"); + throw_quit ("Quit (expect signal SIGINT when the program is resumed)"); #endif } +/* See defs.h. */ + +void +maybe_quit (void) +{ + if (sync_quit_force_run) + quit (); + + quit_handler (); + + if (deprecated_interactive_hook) + deprecated_interactive_hook (); +} + /* Called when a memory allocation fails, with the number of bytes of memory requested in SIZE. */ @@ -1064,63 +786,65 @@ print_spaces (int n, struct ui_file *file) /* Print a host address. */ void -gdb_print_host_address (const void *addr, struct ui_file *stream) +gdb_print_host_address_1 (const void *addr, struct ui_file *stream) { fprintf_filtered (stream, "%s", host_address_to_string (addr)); } - -/* A cleanup function that calls regfree. */ +/* See utils.h. */ -static void -do_regfree_cleanup (void *r) +char * +make_hex_string (const gdb_byte *data, size_t length) { - regfree (r); -} - -/* Create a new cleanup that frees the compiled regular expression R. */ + char *result = (char *) xmalloc (length * 2 + 1); + char *p; + size_t i; -struct cleanup * -make_regfree_cleanup (regex_t *r) -{ - return make_cleanup (do_regfree_cleanup, r); + p = result; + for (i = 0; i < length; ++i) + p += xsnprintf (p, 3, "%02x", data[i]); + *p = '\0'; + return result; } -/* Return an xmalloc'd error message resulting from a regular - expression compilation failure. */ + -char * -get_regcomp_error (int code, regex_t *rx) +/* An RAII class that sets up to handle input and then tears down + during destruction. */ + +class scoped_input_handler { - size_t length = regerror (code, rx, NULL, 0); - char *result = xmalloc (length); +public: - regerror (code, rx, result, length); - return result; -} + scoped_input_handler () + : m_quit_handler (&quit_handler, default_quit_handler), + m_ui (NULL) + { + target_terminal::ours (); + ui_register_input_event_handler (current_ui); + if (current_ui->prompt_state == PROMPT_BLOCKED) + m_ui = current_ui; + } -/* Compile a regexp and throw an exception on error. This returns a - cleanup to free the resulting pattern on success. RX must not be - NULL. */ + ~scoped_input_handler () + { + if (m_ui != NULL) + ui_unregister_input_event_handler (m_ui); + } -struct cleanup * -compile_rx_or_error (regex_t *pattern, const char *rx, const char *message) -{ - int code; + DISABLE_COPY_AND_ASSIGN (scoped_input_handler); - gdb_assert (rx != NULL); +private: - code = regcomp (pattern, rx, REG_NOSUB); - if (code != 0) - { - char *err = get_regcomp_error (code, pattern); + /* Save and restore the terminal state. */ + target_terminal::scoped_restore_terminal_state m_term_state; - make_cleanup (xfree, err); - error (("%s: %s"), message, err); - } + /* Save and restore the quit handler. */ + scoped_restore_tmpl m_quit_handler; - return make_regfree_cleanup (pattern); -} + /* The saved UI, if non-NULL. */ + struct ui *m_ui; +}; @@ -1137,15 +861,10 @@ compile_rx_or_error (regex_t *pattern, const char *rx, const char *message) static int ATTRIBUTE_PRINTF (1, 0) defaulted_query (const char *ctlstr, const char defchar, va_list args) { - int answer; - int ans2; int retval; int def_value; char def_answer, not_def_answer; - char *y_string, *n_string, *question; - /* Used to add duration we waited for user to respond to - prompt_for_continue_wait_time. */ - struct timeval prompt_started, prompt_ended, prompt_delta; + const char *y_string, *n_string; /* Set up according to which answer is the default. */ if (defchar == '\0') @@ -1182,8 +901,13 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) 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 ()) + if (current_ui->instream != current_ui->stdin_stream + || !input_interactive_p (current_ui) + /* Restrict queries to the main UI. */ + || current_ui != main_ui) { + target_terminal::scoped_restore_terminal_state term_state; + target_terminal::ours_for_output (); wrap_here (""); vfprintf_filtered (gdb_stdout, ctlstr, args); @@ -1197,67 +921,41 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) if (deprecated_query_hook) { + target_terminal::scoped_restore_terminal_state term_state; return deprecated_query_hook (ctlstr, args); } /* Format the question outside of the loop, to avoid reusing args. */ - question = xstrvprintf (ctlstr, args); + std::string question = string_vprintf (ctlstr, args); + std::string prompt + = string_printf (_("%s%s(%s or %s) %s"), + annotation_level > 1 ? "\n\032\032pre-query\n" : "", + question.c_str (), y_string, n_string, + annotation_level > 1 ? "\n\032\032query\n" : ""); + + /* Used to add duration we waited for user to respond to + prompt_for_continue_wait_time. */ + using namespace std::chrono; + steady_clock::time_point prompt_started = steady_clock::now (); - /* Used for calculating time spend waiting for user. */ - gettimeofday (&prompt_started, NULL); + scoped_input_handler prepare_input; while (1) { - wrap_here (""); /* Flush any buffered output. */ - gdb_flush (gdb_stdout); - - if (annotation_level > 1) - printf_filtered (("\n\032\032pre-query\n")); - - fputs_filtered (question, gdb_stdout); - printf_filtered (_("(%s or %s) "), y_string, n_string); - - if (annotation_level > 1) - printf_filtered (("\n\032\032query\n")); + char *response, answer; - wrap_here (""); gdb_flush (gdb_stdout); + response = gdb_readline_wrapper (prompt.c_str ()); - 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 */ + if (response == NULL) /* C-d */ { printf_filtered ("EOF [assumed %c]\n", def_answer); retval = def_value; break; } - /* Eat rest of input line, to EOF or newline. */ - if (answer != '\n') - do - { - ans2 = fgetc (stdin); - clearerr (stdin); - } - while (ans2 != EOF && ans2 != '\n' && ans2 != '\r'); + + answer = response[0]; + xfree (response); if (answer >= 'a') answer -= 040; @@ -1272,8 +970,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) specify the required input or have it default by entering nothing. */ if (answer == def_answer - || (defchar != '\0' && - (answer == '\n' || answer == '\r' || answer == EOF))) + || (defchar != '\0' && answer == '\0')) { retval = def_value; break; @@ -1284,12 +981,8 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) } /* Add time spend in this routine to prompt_for_continue_wait_time. */ - gettimeofday (&prompt_ended, NULL); - timeval_sub (&prompt_delta, &prompt_ended, &prompt_started); - timeval_add (&prompt_for_continue_wait_time, - &prompt_for_continue_wait_time, &prompt_delta); + prompt_for_continue_wait_time += steady_clock::now () - prompt_started; - xfree (question); if (annotation_level > 1) printf_filtered (("\n\032\032post-query\n")); return retval; @@ -1357,13 +1050,10 @@ query (const char *ctlstr, ...) static int host_char_to_target (struct gdbarch *gdbarch, int c, int *target_c) { - 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); + auto_obstack host_data; convert_between_encodings (target_charset (gdbarch), host_charset (), (gdb_byte *) &the_char, 1, 1, @@ -1375,7 +1065,6 @@ host_char_to_target (struct gdbarch *gdbarch, int c, int *target_c) *target_c = *(char *) obstack_base (&host_data); } - do_cleanups (cleanups); return result; } @@ -1471,13 +1160,17 @@ parse_escape (struct gdbarch *gdbarch, const char **string_ptr) /* 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. */ + be called for printing things which are independent of the language + of the program being debugged. + + printchar will normally escape backslashes and instances of QUOTER. If + QUOTER is 0, printchar won't escape backslashes or any quoting character. + As a side effect, if you pass the backslash character as the QUOTER, + printchar will escape backslashes as usual, but not any other quoting + character. */ 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) +printchar (int c, do_fputc_ftype do_fputc, ui_file *stream, int quoter) { c &= 0xFF; /* Avoid sign bit follies */ @@ -1485,39 +1178,45 @@ printchar (int c, void (*do_fputs) (const char *, struct ui_file *), (c >= 0x7F && c < 0xA0) || /* DEL, High controls */ (sevenbit_strings && c >= 0x80)) { /* high order bit set */ + do_fputc ('\\', stream); + switch (c) { case '\n': - do_fputs ("\\n", stream); + do_fputc ('n', stream); break; case '\b': - do_fputs ("\\b", stream); + do_fputc ('b', stream); break; case '\t': - do_fputs ("\\t", stream); + do_fputc ('t', stream); break; case '\f': - do_fputs ("\\f", stream); + do_fputc ('f', stream); break; case '\r': - do_fputs ("\\r", stream); + do_fputc ('r', stream); break; case '\033': - do_fputs ("\\e", stream); + do_fputc ('e', stream); break; case '\007': - do_fputs ("\\a", stream); + do_fputc ('a', stream); break; default: - do_fprintf (stream, "\\%.3o", (unsigned int) c); - break; + { + do_fputc ('0' + ((c >> 6) & 0x7), stream); + do_fputc ('0' + ((c >> 3) & 0x7), stream); + do_fputc ('0' + ((c >> 0) & 0x7), stream); + break; + } } } else { - if (c == '\\' || c == quoter) - do_fputs ("\\", stream); - do_fprintf (stream, "%c", c); + if (quoter != 0 && (c == '\\' || c == quoter)) + do_fputc ('\\', stream); + do_fputc (c, stream); } } @@ -1530,34 +1229,30 @@ void fputstr_filtered (const char *str, int quoter, struct ui_file *stream) { while (*str) - printchar (*str++, fputs_filtered, fprintf_filtered, stream, quoter); + printchar (*str++, fputc_filtered, stream, quoter); } void fputstr_unfiltered (const char *str, int quoter, struct ui_file *stream) { while (*str) - printchar (*str++, fputs_unfiltered, fprintf_unfiltered, stream, quoter); + printchar (*str++, fputc_unfiltered, stream, quoter); } void 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); + for (int i = 0; i < n; i++) + printchar (str[i], fputc_filtered, stream, quoter); } void fputstrn_unfiltered (const char *str, int n, int quoter, - struct ui_file *stream) + do_fputc_ftype do_fputc, struct ui_file *stream) { - int i; - - for (i = 0; i < n; i++) - printchar (str[i], fputs_unfiltered, fprintf_unfiltered, stream, quoter); + for (int i = 0; i < n; i++) + printchar (str[i], do_fputc, stream, quoter); } @@ -1605,14 +1300,14 @@ static char *wrap_pointer; /* String to indent by if the wrap occurs. Must not be NULL if wrap_column is non-zero. */ -static char *wrap_indent; +static const char *wrap_indent; /* Column number on the screen where wrap_buffer begins, or 0 if wrapping is not in effect. */ static int wrap_column; -/* Inialize the number of lines per page and chars per line. */ +/* Initialize the number of lines per page and chars per line. */ void init_page_info (void) @@ -1646,9 +1341,10 @@ init_page_info (void) /* Readline should have fetched the termcap entry for us. Only try to use tgetnum function if rl_get_screen_size did not return a useful value. */ - if (((rows <= 0) && (tgetnum ("li") < 0)) - /* Also disable paging if inside EMACS. */ - || getenv ("EMACS")) + if (((rows <= 0) && (tgetnum ((char *) "li") < 0)) + /* Also disable paging if inside Emacs. $EMACS was used + before Emacs v25.1, $INSIDE_EMACS is used since then. */ + || getenv ("EMACS") || getenv ("INSIDE_EMACS")) { /* The number of lines per page is not mentioned in the terminal description or EMACS evironment variable is set. This probably @@ -1662,46 +1358,37 @@ init_page_info (void) #endif } - set_screen_size (); - set_width (); -} - -/* Helper for make_cleanup_restore_page_info. */ + /* We handle SIGWINCH ourselves. */ + rl_catch_sigwinch = 0; -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) +/* Return nonzero if filtered printing is initialized. */ +int +filtered_printing_initialized (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; + return wrap_buffer != NULL; } -/* 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) +set_batch_flag_and_restore_page_info::set_batch_flag_and_restore_page_info () + : m_save_lines_per_page (lines_per_page), + m_save_chars_per_line (chars_per_line), + m_save_batch_flag (batch_flag) { - 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_batch_flag_and_restore_page_info::~set_batch_flag_and_restore_page_info () +{ + batch_flag = m_save_batch_flag; + chars_per_line = m_save_chars_per_line; + lines_per_page = m_save_lines_per_page; + + set_screen_size (); + set_width (); } /* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */ @@ -1742,31 +1429,43 @@ set_width (void) } static void -set_width_command (char *args, int from_tty, struct cmd_list_element *c) +set_width_command (const char *args, int from_tty, struct cmd_list_element *c) { set_screen_size (); set_width (); } -static void -set_height_command (char *args, int from_tty, struct cmd_list_element *c) +static void +set_height_command (const char *args, int from_tty, struct cmd_list_element *c) +{ + set_screen_size (); +} + +/* See utils.h. */ + +void +set_screen_width_and_height (int width, int height) { + lines_per_page = height; + chars_per_line = width; + set_screen_size (); + set_width (); } /* Wait, so the user can read what's on the screen. Prompt the user - to continue by pressing RETURN. */ + to continue by pressing RETURN. 'q' is also provided because + telling users what to do in the prompt is more user-friendly than + expecting them to think of Ctrl-C/SIGINT. */ static void prompt_for_continue (void) { - char *ignore; char cont_prompt[120]; /* Used to add duration we waited for user to respond to prompt_for_continue_wait_time. */ - struct timeval prompt_started, prompt_ended, prompt_delta; - - gettimeofday (&prompt_started, NULL); + using namespace std::chrono; + steady_clock::time_point prompt_started = steady_clock::now (); if (annotation_level > 1) printf_unfiltered (("\n\032\032pre-prompt-for-continue\n")); @@ -1776,45 +1475,33 @@ prompt_for_continue (void) if (annotation_level > 1) strcat (cont_prompt, "\n\032\032prompt-for-continue\n"); - /* We must do this *before* we call gdb_readline, else it will eventually - call us -- thinking that we're trying to print beyond the end of the - screen. */ + /* We must do this *before* we call gdb_readline_wrapper, else it + will eventually call us -- thinking that we're trying to print + beyond the end of the screen. */ reinitialize_more_filter (); - immediate_quit++; - QUIT; - /* On a real operating system, the user can quit with SIGINT. - But not on GO32. + scoped_input_handler prepare_input; - 'q' is provided on all systems so users don't have to change habits - from system to system, and because telling them what to do in - the prompt is more user-friendly than expecting them to think of - SIGINT. */ - /* Call readline, not gdb_readline, because GO32 readline handles control-C - whereas control-C to gdb_readline will cause the user to get dumped - out to DOS. */ - ignore = gdb_readline_wrapper (cont_prompt); + /* Call gdb_readline_wrapper, not readline, in order to keep an + event loop running. */ + gdb::unique_xmalloc_ptr ignore (gdb_readline_wrapper (cont_prompt)); /* Add time spend in this routine to prompt_for_continue_wait_time. */ - gettimeofday (&prompt_ended, NULL); - timeval_sub (&prompt_delta, &prompt_ended, &prompt_started); - timeval_add (&prompt_for_continue_wait_time, - &prompt_for_continue_wait_time, &prompt_delta); + prompt_for_continue_wait_time += steady_clock::now () - prompt_started; if (annotation_level > 1) printf_unfiltered (("\n\032\032post-prompt-for-continue\n")); - if (ignore) + if (ignore != NULL) { - char *p = ignore; + char *p = ignore.get (); while (*p == ' ' || *p == '\t') ++p; if (p[0] == 'q') - quit (); - xfree (ignore); + /* Do not call quit here; there is no possibility of SIGINT. */ + throw_quit ("Quit"); } - immediate_quit--; /* Now we have to do this again, so that GDB will know that it doesn't need to save the ---Type --- line at the top of the screen. */ @@ -1823,20 +1510,20 @@ prompt_for_continue (void) dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */ } -/* Initalize timer to keep track of how long we waited for the user. */ +/* Initialize timer to keep track of how long we waited for the user. */ void reset_prompt_for_continue_wait_time (void) { - static const struct timeval zero_timeval = { 0 }; + using namespace std::chrono; - prompt_for_continue_wait_time = zero_timeval; + prompt_for_continue_wait_time = steady_clock::duration::zero (); } /* Fetch the cumulative time spent in prompt_for_continue. */ -struct timeval -get_prompt_for_continue_wait_time (void) +std::chrono::steady_clock::duration +get_prompt_for_continue_wait_time () { return prompt_for_continue_wait_time; } @@ -1872,7 +1559,7 @@ reinitialize_more_filter (void) used to force out output from the wrap_buffer. */ void -wrap_here (char *indent) +wrap_here (const char *indent) { /* This should have been allocated, but be paranoid anyway. */ if (!wrap_buffer) @@ -1942,7 +1629,7 @@ puts_filtered_tabular (char *string, int width, int right) if (right) spaces += width - stringlen; - spacebuf = alloca (spaces + 1); + spacebuf = (char *) alloca (spaces + 1); spacebuf[spaces] = '\0'; while (spaces--) spacebuf[spaces] = ' '; @@ -1995,7 +1682,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream, || 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 ()))) + || interp_ui_out (top_level_interpreter ())->is_mi_like_p ()) { fputs_unfiltered (linebuffer, stream); return; @@ -2141,8 +1828,8 @@ puts_debug (char *prefix, char *string, char *suffix) /* Print prefix and suffix after each line. */ static int new_line = 1; static int return_p = 0; - static char *prev_prefix = ""; - static char *prev_suffix = ""; + static const char *prev_prefix = ""; + static const char *prev_suffix = ""; if (*string == '\n') return_p = 0; @@ -2233,13 +1920,8 @@ static void vfprintf_maybe_filtered (struct ui_file *stream, const char *format, va_list args, int filter) { - char *linebuffer; - struct cleanup *old_cleanups; - - linebuffer = xstrvprintf (format, args); - old_cleanups = make_cleanup (xfree, linebuffer); - fputs_maybe_filtered (linebuffer, stream, filter); - do_cleanups (old_cleanups); + std::string linebuffer = string_vprintf (format, args); + fputs_maybe_filtered (linebuffer.c_str (), stream, filter); } @@ -2252,32 +1934,28 @@ vfprintf_filtered (struct ui_file *stream, const char *format, va_list args) void vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args) { - char *linebuffer; - struct cleanup *old_cleanups; - - linebuffer = xstrvprintf (format, args); - old_cleanups = make_cleanup (xfree, linebuffer); + std::string linebuffer = string_vprintf (format, args); if (debug_timestamp && stream == gdb_stdlog) { - struct timeval tm; - char *timestamp; + using namespace std::chrono; int len, need_nl; - gettimeofday (&tm, NULL); + steady_clock::time_point now = steady_clock::now (); + seconds s = duration_cast (now.time_since_epoch ()); + microseconds us = duration_cast (now.time_since_epoch () - s); - len = strlen (linebuffer); + len = linebuffer.size (); 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); + std::string timestamp = string_printf ("%ld.%06ld %s%s", + (long) s.count (), + (long) us.count (), + linebuffer.c_str (), + need_nl ? "\n": ""); + fputs_unfiltered (timestamp.c_str (), stream); } else - fputs_unfiltered (linebuffer, stream); - do_cleanups (old_cleanups); + fputs_unfiltered (linebuffer.c_str (), stream); } void @@ -2443,41 +2121,369 @@ fprintf_symbol_filtered (struct ui_file *stream, const char *name, } } -/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any - differences in whitespace. Returns 0 if they match, non-zero if they - don't (slightly different than strcmp()'s range of return values). +/* True if CH is a character that can be part of a symbol name. I.e., + either a number, a letter, or a '_'. */ + +static bool +valid_identifier_name_char (int ch) +{ + return (isalnum (ch) || ch == '_'); +} - 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). */ +/* Skip to end of token, or to END, whatever comes first. Input is + assumed to be a C++ operator name. */ -int -strcmp_iw (const char *string1, const char *string2) +static const char * +cp_skip_operator_token (const char *token, const char *end) { - while ((*string1 != '\0') && (*string2 != '\0')) + const char *p = token; + while (p != end && !isspace (*p) && *p != '(') { - while (isspace (*string1)) + if (valid_identifier_name_char (*p)) { - string1++; + while (p != end && valid_identifier_name_char (*p)) + p++; + return p; + } + else + { + /* Note, ordered such that among ops that share a prefix, + longer comes first. This is so that the loop below can + bail on first match. */ + static const char *ops[] = + { + "[", + "]", + "~", + ",", + "-=", "--", "->", "-", + "+=", "++", "+", + "*=", "*", + "/=", "/", + "%=", "%", + "|=", "||", "|", + "&=", "&&", "&", + "^=", "^", + "!=", "!", + "<<=", "<=", "<<", "<", + ">>=", ">=", ">>", ">", + "==", "=", + }; + + for (const char *op : ops) + { + size_t oplen = strlen (op); + size_t lencmp = std::min (oplen, end - p); + + if (strncmp (p, op, lencmp) == 0) + return p + lencmp; + } + /* Some unidentified character. Return it. */ + return p + 1; + } + } + + return p; +} + +/* Advance STRING1/STRING2 past whitespace. */ + +static void +skip_ws (const char *&string1, const char *&string2, const char *end_str2) +{ + while (isspace (*string1)) + string1++; + while (string2 < end_str2 && isspace (*string2)) + string2++; +} + +/* True if STRING points at the start of a C++ operator name. START + is the start of the string that STRING points to, hence when + reading backwards, we must not read any character before START. */ + +static bool +cp_is_operator (const char *string, const char *start) +{ + return ((string == start + || !valid_identifier_name_char (string[-1])) + && strncmp (string, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0 + && !valid_identifier_name_char (string[CP_OPERATOR_LEN])); +} + +/* If *NAME points at an ABI tag, skip it and return true. Otherwise + leave *NAME unmodified and return false. (see GCC's abi_tag + attribute), such names are demangled as e.g., + "function[abi:cxx11]()". */ + +static bool +skip_abi_tag (const char **name) +{ + const char *p = *name; + + if (startswith (p, "[abi:")) + { + p += 5; + + while (valid_identifier_name_char (*p)) + p++; + + if (*p == ']') + { + p++; + *name = p; + return true; + } + } + return false; +} + +/* See utils.h. */ + +int +strncmp_iw_with_mode (const char *string1, const char *string2, + size_t string2_len, strncmp_iw_mode mode, + enum language language, + completion_match_for_lcd *match_for_lcd) +{ + const char *string1_start = string1; + const char *end_str2 = string2 + string2_len; + bool skip_spaces = true; + bool have_colon_op = (language == language_cplus + || language == language_rust + || language == language_fortran); + + while (1) + { + if (skip_spaces + || ((isspace (*string1) && !valid_identifier_name_char (*string2)) + || (isspace (*string2) && !valid_identifier_name_char (*string1)))) + { + skip_ws (string1, string2, end_str2); + skip_spaces = false; + } + + /* Skip [abi:cxx11] tags in the symbol name if the lookup name + doesn't include them. E.g.: + + string1: function[abi:cxx1](int) + string2: function + + string1: function[abi:cxx1](int) + string2: function(int) + + string1: Struct[abi:cxx1]::function() + string2: Struct::function() + + string1: function(Struct[abi:cxx1], int) + string2: function(Struct, int) + */ + if (string2 == end_str2 + || (*string2 != '[' && !valid_identifier_name_char (*string2))) + { + const char *abi_start = string1; + + /* There can be more than one tag. */ + while (*string1 == '[' && skip_abi_tag (&string1)) + ; + + if (match_for_lcd != NULL && abi_start != string1) + match_for_lcd->mark_ignored_range (abi_start, string1); + + while (isspace (*string1)) + string1++; } - while (isspace (*string2)) + + if (*string1 == '\0' || string2 == end_str2) + break; + + /* Handle the :: operator. */ + if (have_colon_op && string1[0] == ':' && string1[1] == ':') { + if (*string2 != ':') + return 1; + + string1++; + string2++; + + if (string2 == end_str2) + break; + + if (*string2 != ':') + return 1; + + string1++; string2++; + + while (isspace (*string1)) + string1++; + while (string2 < end_str2 && isspace (*string2)) + string2++; + continue; + } + + /* Handle C++ user-defined operators. */ + else if (language == language_cplus + && *string1 == 'o') + { + if (cp_is_operator (string1, string1_start)) + { + /* An operator name in STRING1. Check STRING2. */ + size_t cmplen + = std::min (CP_OPERATOR_LEN, end_str2 - string2); + if (strncmp (string1, string2, cmplen) != 0) + return 1; + + string1 += cmplen; + string2 += cmplen; + + if (string2 != end_str2) + { + /* Check for "operatorX" in STRING2. */ + if (valid_identifier_name_char (*string2)) + return 1; + + skip_ws (string1, string2, end_str2); + } + + /* Handle operator(). */ + if (*string1 == '(') + { + if (string2 == end_str2) + { + if (mode == strncmp_iw_mode::NORMAL) + return 0; + else + { + /* Don't break for the regular return at the + bottom, because "operator" should not + match "operator()", since this open + parentheses is not the parameter list + start. */ + return *string1 != '\0'; + } + } + + if (*string1 != *string2) + return 1; + + string1++; + string2++; + } + + while (1) + { + skip_ws (string1, string2, end_str2); + + /* Skip to end of token, or to END, whatever comes + first. */ + const char *end_str1 = string1 + strlen (string1); + const char *p1 = cp_skip_operator_token (string1, end_str1); + const char *p2 = cp_skip_operator_token (string2, end_str2); + + cmplen = std::min (p1 - string1, p2 - string2); + if (p2 == end_str2) + { + if (strncmp (string1, string2, cmplen) != 0) + return 1; + } + else + { + if (p1 - string1 != p2 - string2) + return 1; + if (strncmp (string1, string2, cmplen) != 0) + return 1; + } + + string1 += cmplen; + string2 += cmplen; + + if (*string1 == '\0' || string2 == end_str2) + break; + if (*string1 == '(' || *string2 == '(') + break; + } + + continue; + } } + 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') + + /* If we see any non-whitespace, non-identifier-name character + (any of "()<>*&" etc.), then skip spaces the next time + around. */ + if (!isspace (*string1) && !valid_identifier_name_char (*string1)) + skip_spaces = true; + + string1++; + string2++; + } + + if (string2 == end_str2) + { + if (mode == strncmp_iw_mode::NORMAL) { - string1++; - string2++; + /* Strip abi tag markers from the matched symbol name. + Usually the ABI marker will be found on function name + (automatically added because the function returns an + object marked with an ABI tag). However, it's also + possible to see a marker in one of the function + parameters, for example. + + string2 (lookup name): + func + symbol name: + function(some_struct[abi:cxx11], int) + + and for completion LCD computation we want to say that + the match was for: + function(some_struct, int) + */ + if (match_for_lcd != NULL) + { + while ((string1 = strstr (string1, "[abi:")) != NULL) + { + const char *abi_start = string1; + + /* There can be more than one tag. */ + while (skip_abi_tag (&string1) && *string1 == '[') + ; + + if (abi_start != string1) + match_for_lcd->mark_ignored_range (abi_start, string1); + } + } + + return 0; } + else + return (*string1 != '\0' && *string1 != '('); } - return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0'); + else + return 1; +} + +/* See utils.h. */ + +int +strncmp_iw (const char *string1, const char *string2, size_t string2_len) +{ + return strncmp_iw_with_mode (string1, string2, string2_len, + strncmp_iw_mode::NORMAL, language_minimal); +} + +/* See utils.h. */ + +int +strcmp_iw (const char *string1, const char *string2) +{ + return strncmp_iw_with_mode (string1, string2, strlen (string2), + strncmp_iw_mode::MATCH_PARAMS, language_minimal); } /* This is like strcmp except that it ignores whitespace and treats @@ -2595,13 +2601,22 @@ strcmp_iw_ordered (const char *string1, const char *string2) } } -/* A simple comparison function with opposite semantics to strcmp. */ +/* See utils.h. */ -int +bool streq (const char *lhs, const char *rhs) { return !strcmp (lhs, rhs); } + +/* See utils.h. */ + +int +streq_hash (const void *lhs, const void *rhs) +{ + return streq ((const char *) lhs, (const char *) rhs); +} + /* @@ -2611,32 +2626,19 @@ streq (const char *lhs, const char *rhs) ** at index 0. */ int -subset_compare (char *string_to_compare, char *template_string) +subset_compare (const char *string_to_compare, const char *template_string) { int match; if (template_string != (char *) NULL && string_to_compare != (char *) NULL && strlen (string_to_compare) <= strlen (template_string)) match = - (strncmp - (template_string, string_to_compare, strlen (string_to_compare)) == 0); + (startswith (template_string, string_to_compare)); else match = 0; return match; } -static void -pagination_on_command (char *arg, int from_tty) -{ - pagination_enabled = 1; -} - -static void -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) @@ -2668,8 +2670,6 @@ Setting this to \"unlimited\" or zero causes GDB never pause during output."), show_lines_per_page, &setlist, &showlist); - init_page_info (); - add_setshow_boolean_cmd ("pagination", class_support, &pagination_enabled, _("\ Set state of GDB output pagination."), _("\ @@ -2681,14 +2681,6 @@ Turning pagination off is an alternative to \"set height unlimited\"."), show_pagination_enabled, &setlist, &showlist); - if (xdb_commands) - { - add_com ("am", class_support, pagination_on_command, - _("Enable pagination")); - add_com ("sm", class_support, pagination_off_command, - _("Disable pagination")); - } - add_setshow_boolean_cmd ("sevenbit-strings", class_support, &sevenbit_strings, _("\ Set printing of 8-bit characters in strings as \\nnn."), _("\ @@ -2707,350 +2699,80 @@ When set, debugging messages will be marked with seconds and microseconds."), &setdebuglist, &showdebuglist); } -/* Print routines to handle variable size regs, etc. */ -/* Temporary storage using circular buffer. */ -#define NUMCELLS 16 -#define CELLSIZE 50 -static char * -get_cell (void) -{ - static char buf[NUMCELLS][CELLSIZE]; - static int cell = 0; - - if (++cell >= NUMCELLS) - cell = 0; - return buf[cell]; -} - -const char * -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. */ - /* 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 gdbarch_address_to_pointer or - some ADDRESS_TO_PRINTABLE() be used to do the conversion? */ - - 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? */ - unsigned long temp[3]; - char *str = get_cell (); - int i = 0; - - do - { - temp[i] = addr % (1000 * 1000 * 1000); - addr /= (1000 * 1000 * 1000); - i++; - width -= 9; - } - while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); - - width += 9; - if (width < 0) - width = 0; - - switch (i) - { - case 1: - xsnprintf (str, CELLSIZE, "%s%0*lu", sign, width, temp[0]); - break; - case 2: - xsnprintf (str, CELLSIZE, "%s%0*lu%09lu", sign, width, - temp[1], temp[0]); - break; - case 3: - xsnprintf (str, CELLSIZE, "%s%0*lu%09lu%09lu", sign, width, - temp[2], temp[1], temp[0]); - break; - default: - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - } - - return str; -} - -static char * -octal2str (ULONGEST addr, int width) -{ - unsigned long temp[3]; - char *str = get_cell (); - int i = 0; - - do - { - temp[i] = addr % (0100000 * 0100000); - addr /= (0100000 * 0100000); - i++; - width -= 10; - } - while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); - - width += 10; - if (width < 0) - width = 0; - - switch (i) - { - case 1: - if (temp[0] == 0) - xsnprintf (str, CELLSIZE, "%*o", width, 0); - else - xsnprintf (str, CELLSIZE, "0%0*lo", width, temp[0]); - break; - case 2: - xsnprintf (str, CELLSIZE, "0%0*lo%010lo", width, temp[1], temp[0]); - break; - case 3: - xsnprintf (str, CELLSIZE, "0%0*lo%010lo%010lo", width, - temp[2], temp[1], temp[0]); - break; - default: - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - } - - return str; -} - -char * -pulongest (ULONGEST u) -{ - return decimal2str ("", u, 0); -} - -char * -plongest (LONGEST l) -{ - if (l < 0) - return decimal2str ("-", -l, 0); - else - return decimal2str ("", l, 0); -} - -/* Eliminate warning from compiler on 32-bit systems. */ -static int thirty_two = 32; +/* See utils.h. */ -char * -phex (ULONGEST l, int sizeof_l) +CORE_ADDR +address_significant (gdbarch *gdbarch, CORE_ADDR addr) { - char *str; + /* Truncate address to the significant bits 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. */ + int addr_bit = gdbarch_significant_addr_bit (gdbarch); - switch (sizeof_l) - { - case 8: - str = get_cell (); - xsnprintf (str, CELLSIZE, "%08lx%08lx", - (unsigned long) (l >> thirty_two), - (unsigned long) (l & 0xffffffff)); - break; - case 4: - str = get_cell (); - xsnprintf (str, CELLSIZE, "%08lx", (unsigned long) l); - break; - case 2: - str = get_cell (); - xsnprintf (str, CELLSIZE, "%04x", (unsigned short) (l & 0xffff)); - break; - default: - str = phex (l, sizeof (l)); - break; - } + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + addr &= ((CORE_ADDR) 1 << addr_bit) - 1; - return str; + return addr; } -char * -phex_nz (ULONGEST l, int sizeof_l) +const char * +paddress (struct gdbarch *gdbarch, CORE_ADDR addr) { - char *str; + /* 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. */ + /* 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 gdbarch_address_to_pointer or + some ADDRESS_TO_PRINTABLE() be used to do the conversion? */ - switch (sizeof_l) - { - case 8: - { - unsigned long high = (unsigned long) (l >> thirty_two); - - str = get_cell (); - if (high == 0) - xsnprintf (str, CELLSIZE, "%lx", - (unsigned long) (l & 0xffffffff)); - else - xsnprintf (str, CELLSIZE, "%lx%08lx", high, - (unsigned long) (l & 0xffffffff)); - break; - } - case 4: - str = get_cell (); - xsnprintf (str, CELLSIZE, "%lx", (unsigned long) l); - break; - case 2: - str = get_cell (); - xsnprintf (str, CELLSIZE, "%x", (unsigned short) (l & 0xffff)); - break; - default: - str = phex_nz (l, sizeof (l)); - break; - } + int addr_bit = gdbarch_addr_bit (gdbarch); - return str; + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + addr &= ((CORE_ADDR) 1 << addr_bit) - 1; + return hex_string (addr); } -/* Converts a LONGEST to a C-format hexadecimal literal and stores it - in a static string. Returns a pointer to this string. */ -char * -hex_string (LONGEST num) -{ - char *result = get_cell (); - - xsnprintf (result, CELLSIZE, "0x%s", phex_nz (num, sizeof (num))); - return result; -} +/* This function is described in "defs.h". */ -/* Converts a LONGEST number to a C-format hexadecimal literal and - stores it in a static string. Returns a pointer to this string - that is valid until the next call. The number is padded on the - left with 0s to at least WIDTH characters. */ -char * -hex_string_custom (LONGEST num, int width) +const char * +print_core_address (struct gdbarch *gdbarch, CORE_ADDR address) { - char *result = get_cell (); - char *result_end = result + CELLSIZE - 1; - const char *hex = phex_nz (num, sizeof (num)); - int hex_len = strlen (hex); + int addr_bit = gdbarch_addr_bit (gdbarch); - if (hex_len > width) - width = hex_len; - if (width + 2 >= CELLSIZE) - internal_error (__FILE__, __LINE__, _("\ -hex_string_custom: insufficient space to store result")); + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + address &= ((CORE_ADDR) 1 << addr_bit) - 1; - strcpy (result_end - width - 2, "0x"); - memset (result_end - width, '0', width); - strcpy (result_end - hex_len, hex); - return result_end - width - 2; + /* 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); } -/* Convert VAL to a numeral in the given radix. For - * radix 10, IS_SIGNED may be true, indicating a signed quantity; - * 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). */ - -char * -int_string (LONGEST val, int radix, int is_signed, int width, - int use_c_format) -{ - switch (radix) - { - case 16: - { - char *result; - - if (width == 0) - result = hex_string (val); - else - result = hex_string_custom (val, width); - if (! use_c_format) - result += 2; - return result; - } - case 10: - { - if (is_signed && val < 0) - return decimal2str ("-", -val, width); - else - return decimal2str ("", val, width); - } - case 8: - { - char *result = octal2str (val, width); - - if (use_c_format || val == 0) - return result; - else - return result + 1; - } - default: - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - } -} +/* Callback hash_f for htab_create_alloc or htab_create_alloc_ex. */ -/* Convert a CORE_ADDR into a string. */ -const char * -core_addr_to_string (const CORE_ADDR addr) +hashval_t +core_addr_hash (const void *ap) { - char *str = get_cell (); + const CORE_ADDR *addrp = (const CORE_ADDR *) ap; - strcpy (str, "0x"); - strcat (str, phex (addr, sizeof (addr))); - return str; + return *addrp; } -const char * -core_addr_to_string_nz (const CORE_ADDR addr) +/* Callback eq_f for htab_create_alloc or htab_create_alloc_ex. */ + +int +core_addr_eq (const void *ap, const void *bp) { - char *str = get_cell (); + const CORE_ADDR *addr_ap = (const CORE_ADDR *) ap; + const CORE_ADDR *addr_bp = (const CORE_ADDR *) bp; - strcpy (str, "0x"); - strcat (str, phex_nz (addr, sizeof (addr))); - return str; + return *addr_ap == *addr_bp; } /* Convert a string back into a CORE_ADDR. */ @@ -3091,173 +2813,41 @@ string_to_core_addr (const char *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) -{ - /* Method 1: The system has a compile time upper bound on a filename - path. Use that and realpath() to canonicalize the name. This is - the most common case. Note that, if there isn't a compile time - upper bound, you want to avoid realpath() at all costs. */ -#if defined (HAVE_REALPATH) && defined (PATH_MAX) - { - char buf[PATH_MAX]; - const char *rp = realpath (filename, buf); - - if (rp == NULL) - rp = filename; - return xstrdup (rp); - } -#endif /* HAVE_REALPATH */ - - /* Method 2: The host system (i.e., GNU) has the function - canonicalize_file_name() which malloc's a chunk of memory and - returns that, use that. */ -#if defined(HAVE_CANONICALIZE_FILE_NAME) - { - char *rp = canonicalize_file_name (filename); - - if (rp == NULL) - return xstrdup (filename); - else - return rp; - } -#endif - - /* FIXME: cagney/2002-11-13: - - Method 2a: Use realpath() with a NULL buffer. Some systems, due - 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 - will likely core dump. */ - - /* Method 3: Now we're getting desperate! The system doesn't have a - compile time buffer size and no alternative function. Query the - OS, using pathconf(), for the buffer limit. Care is needed - though, some systems do not limit PATH_MAX (return -1 for - pathconf()) making it impossible to pass a correctly sized buffer - to realpath() (it could always overflow). On those systems, we - skip this. */ -#if defined (HAVE_REALPATH) && defined (_PC_PATH_MAX) && defined(HAVE_ALLOCA) - { - /* 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); -} - -/* Return a copy of FILENAME, with its directory prefix canonicalized - by gdb_realpath. */ +#if GDB_SELF_TEST -char * -gdb_realpath_keepfile (const char *filename) +static void +gdb_realpath_check_trailer (const char *input, const char *trailer) { - const char *base_name = lbasename (filename); - char *dir_name; - char *real_path; - char *result; - - /* Extract the basename of filename, and return immediately - 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. */ - strncpy (dir_name, filename, base_name - filename); - dir_name[base_name - filename] = '\000'; - -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - /* We need to be careful when filename is of the form 'd:foo', which - is equivalent of d:./foo, which is totally different from d:/foo. */ - if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':') - { - dir_name[2] = '.'; - dir_name[3] = '\000'; - } -#endif + gdb::unique_xmalloc_ptr result = gdb_realpath (input); - /* Canonicalize the directory prefix, and build the resulting - 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); - else - result = concat (real_path, SLASH_STRING, base_name, (char *) NULL); + size_t len = strlen (result.get ()); + size_t trail_len = strlen (trailer); - xfree (real_path); - return result; + SELF_CHECK (len >= trail_len + && strcmp (result.get () + len - trail_len, trailer) == 0); } -/* Return PATH in absolute form, performing tilde-expansion if necessary. - PATH cannot be NULL or the empty string. - This does not resolve symlinks however, use gdb_realpath for that. - Space for the result is allocated with malloc. - If the path is already absolute, it is strdup'd. - If there is a problem computing the absolute path, the path is returned - unchanged (still strdup'd). */ - -char * -gdb_abspath (const char *path) -{ - gdb_assert (path != NULL && path[0] != '\0'); - - if (path[0] == '~') - return tilde_expand (path); - - if (IS_ABSOLUTE_PATH (path)) - return xstrdup (path); - - /* Beware the // my son, the Emacs barfs, the botch that catch... */ - return concat (current_directory, - IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) - ? "" : SLASH_STRING, - path, (char *) NULL); -} +static void +gdb_realpath_tests () +{ + /* A file which contains a directory prefix. */ + gdb_realpath_check_trailer ("./xfullpath.exp", "/xfullpath.exp"); + /* A file which contains a directory prefix. */ + gdb_realpath_check_trailer ("../../defs.h", "/defs.h"); + /* A one-character filename. */ + gdb_realpath_check_trailer ("./a", "/a"); + /* A file in the root directory. */ + gdb_realpath_check_trailer ("/root_file_which_should_exist", + "/root_file_which_should_exist"); + /* A file which does not have a directory prefix. */ + gdb_realpath_check_trailer ("xfullpath.exp", "xfullpath.exp"); + /* A one-char filename without any directory prefix. */ + gdb_realpath_check_trailer ("a", "a"); + /* An empty filename. */ + gdb_realpath_check_trailer ("", ""); +} + +#endif /* GDB_SELF_TEST */ ULONGEST align_up (ULONGEST v, int n) @@ -3275,30 +2865,13 @@ align_down (ULONGEST v, int n) return (v & -n); } -/* See utils.h. */ - -LONGEST -gdb_sign_extend (LONGEST value, int bit) -{ - gdb_assert (bit >= 1 && bit <= 8 * sizeof (LONGEST)); - - if (((value >> (bit - 1)) & 1) != 0) - { - LONGEST signbit = ((LONGEST) 1) << (bit - 1); - - value = (value ^ signbit) - signbit; - } - - return value; -} - /* Allocation function for the libiberty hash table which uses an obstack. The obstack is passed as DATA. */ void * hashtab_obstack_allocate (void *data, size_t size, size_t count) { - unsigned int total = size * count; + size_t total = size * count; void *ptr = obstack_alloc ((struct obstack *) data, total); memset (ptr, 0, total); @@ -3316,122 +2889,22 @@ dummy_obstack_deallocate (void *object, void *data) return; } -/* The bit offset of the highest byte in a ULONGEST, for overflow - checking. */ - -#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) - -/* True (non-zero) iff DIGIT is a valid digit in radix BASE, - where 2 <= BASE <= 36. */ - -static int -is_digit_in_base (unsigned char digit, int base) -{ - if (!isalnum (digit)) - return 0; - if (base <= 10) - return (isdigit (digit) && digit < base + '0'); - else - return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); -} - -static int -digit_to_int (unsigned char c) -{ - if (isdigit (c)) - return c - '0'; - else - return tolower (c) - 'a' + 10; -} - -/* As for strtoul, but for ULONGEST results. */ - -ULONGEST -strtoulst (const char *num, const char **trailer, int base) -{ - unsigned int high_part; - ULONGEST result; - int minus = 0; - int i = 0; - - /* Skip leading whitespace. */ - while (isspace (num[i])) - i++; - - /* Handle prefixes. */ - if (num[i] == '+') - i++; - else if (num[i] == '-') - { - minus = 1; - i++; - } - - if (base == 0 || base == 16) - { - if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) - { - i += 2; - if (base == 0) - base = 16; - } - } - - if (base == 0 && num[i] == '0') - base = 8; - - if (base == 0) - base = 10; - - if (base < 2 || base > 36) - { - errno = EINVAL; - return 0; - } - - result = high_part = 0; - for (; is_digit_in_base (num[i], base); i += 1) - { - result = result * base + digit_to_int (num[i]); - high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); - result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; - if (high_part > 0xff) - { - errno = ERANGE; - result = ~ (ULONGEST) 0; - high_part = 0; - minus = 0; - break; - } - } - - if (trailer != NULL) - *trailer = &num[i]; - - result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); - if (minus) - return -result; - else - return result; -} - /* Simple, portable version of dirname that does not modify its argument. */ -char * +std::string ldirname (const char *filename) { + std::string dirname; const char *base = lbasename (filename); - char *dirname; while (base > filename && IS_DIR_SEPARATOR (base[-1])) --base; if (base == filename) - return NULL; + return dirname; - dirname = xmalloc (base - filename + 2); - memcpy (dirname, filename, base - filename); + dirname = std::string (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". */ @@ -3439,23 +2912,21 @@ ldirname (const char *filename) && !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. */ +/* See utils.h. */ -char ** -gdb_buildargv (const char *s) +void +gdb_argv::reset (const char *s) { char **argv = buildargv (s); if (s != NULL && argv == NULL) malloc_failure (0); - return argv; + + freeargv (m_argv); + m_argv = argv; } int @@ -3466,17 +2937,6 @@ compare_positive_ints (const void *ap, const void *bp) 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." @@ -3496,7 +2956,7 @@ gdb_bfd_errmsg (bfd_error_type error_tag, char **matching) + strlen (AMBIGUOUS_MESS2); for (p = matching; *p; p++) ret_len += strlen (*p) + 1; - ret = xmalloc (ret_len + 1); + ret = (char *) xmalloc (ret_len + 1); retp = ret; make_cleanup (xfree, ret); @@ -3521,7 +2981,7 @@ gdb_bfd_errmsg (bfd_error_type error_tag, char **matching) /* Return ARGS parsed as a valid pid, or throw an error. */ int -parse_pid_to_attach (char *args) +parse_pid_to_attach (const char *args) { unsigned long pid; char *dummy; @@ -3529,7 +2989,7 @@ parse_pid_to_attach (char *args) if (!args) error_no_arg (_("process-id to attach")); - dummy = args; + dummy = (char *) args; pid = strtoul (args, &dummy, 0); /* Some targets don't set errno on errors, grrr! */ if ((pid == 0 && dummy == args) || dummy != &args[strlen (args)]) @@ -3555,73 +3015,6 @@ 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; -} - -/* Helper for make_cleanup_free_char_ptr_vec. */ - -static void -do_free_char_ptr_vec (void *arg) -{ - VEC (char_ptr) *char_ptr_vec = arg; - - free_char_ptr_vec (char_ptr_vec); -} - -/* Make cleanup handler calling xfree for each element of CHAR_PTR_VEC and - final VEC_free for CHAR_PTR_VEC itself. - - You must not modify CHAR_PTR_VEC after this cleanup registration as the - CHAR_PTR_VEC base address may change on its updates. Contrary to VEC_free - this function does not (cannot) clear the pointer. */ - -struct cleanup * -make_cleanup_free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec) -{ - return make_cleanup (do_free_char_ptr_vec, char_ptr_vec); -} - /* Substitute all occurences of string FROM by string TO in *STRINGP. *STRINGP must come from xrealloc-compatible allocator and it may be updated. FROM needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be @@ -3647,7 +3040,8 @@ substitute_path_component (char **stringp, const char *from, const char *to) { char *string_new; - string_new = xrealloc (string, (strlen (string) + to_len + 1)); + string_new + = (char *) xrealloc (string, (strlen (string) + to_len + 1)); /* Relocate the current S pointer. */ s = s - string + string_new; @@ -3708,9 +3102,9 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout) sa.sa_flags = 0; sigaction (SIGALRM, &sa, &old_sa); #else - void (*ofunc) (); + sighandler_t ofunc; - ofunc = (void (*)()) signal (SIGALRM, sigalrm_handler); + ofunc = signal (SIGALRM, sigalrm_handler); #endif alarm (timeout); @@ -3758,14 +3152,14 @@ gdb_filename_fnmatch (const char *pattern, const char *string, int flags) /* Replace '\' by '/' in both strings. */ - pattern_slash = alloca (strlen (pattern) + 1); + pattern_slash = (char *) alloca (strlen (pattern) + 1); strcpy (pattern_slash, pattern); pattern = pattern_slash; for (; *pattern_slash != 0; pattern_slash++) if (IS_DIR_SEPARATOR (*pattern_slash)) *pattern_slash = '/'; - string_slash = alloca (strlen (string) + 1); + string_slash = (char *) alloca (strlen (string) + 1); strcpy (string_slash, string); string = string_slash; for (; *string_slash != 0; string_slash++) @@ -3781,12 +3175,91 @@ gdb_filename_fnmatch (const char *pattern, const char *string, int flags) return fnmatch (pattern, string, flags); } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_utils; +/* Return the number of path elements in PATH. + / = 1 + /foo = 2 + /foo/ = 2 + foo/bar = 2 + foo/ = 1 */ + +int +count_path_elements (const char *path) +{ + int count = 0; + const char *p = path; + + if (HAS_DRIVE_SPEC (p)) + { + p = STRIP_DRIVE_SPEC (p); + ++count; + } + + while (*p != '\0') + { + if (IS_DIR_SEPARATOR (*p)) + ++count; + ++p; + } + + /* Backup one if last character is /, unless it's the only one. */ + if (p > path + 1 && IS_DIR_SEPARATOR (p[-1])) + --count; + + /* Add one for the file name, if present. */ + if (p > path && !IS_DIR_SEPARATOR (p[-1])) + ++count; + + return count; +} + +/* Remove N leading path elements from PATH. + N must be non-negative. + If PATH has more than N path elements then return NULL. + If PATH has exactly N path elements then return "". + See count_path_elements for a description of how we do the counting. */ + +const char * +strip_leading_path_elements (const char *path, int n) +{ + int i = 0; + const char *p = path; + + gdb_assert (n >= 0); + + if (n == 0) + return p; + + if (HAS_DRIVE_SPEC (p)) + { + p = STRIP_DRIVE_SPEC (p); + ++i; + } + + while (i < n) + { + while (*p != '\0' && !IS_DIR_SEPARATOR (*p)) + ++p; + if (*p == '\0') + { + if (i + 1 == n) + return ""; + return NULL; + } + ++p; + ++i; + } + + return p; +} void _initialize_utils (void) { add_internal_problem_command (&internal_error_problem); add_internal_problem_command (&internal_warning_problem); + add_internal_problem_command (&demangler_warning_problem); + +#if GDB_SELF_TEST + selftests::register_test ("gdb_realpath", gdb_realpath_tests); +#endif }