Index: gdb/utils.c |
diff --git a/gdb/utils.c b/gdb/utils.c |
index a838295aeab39e4efb1fa053de5acd236dc1a830..556614996b8bc14a804c105e210ebfe80c010b4f 100644 |
--- a/gdb/utils.c |
+++ b/gdb/utils.c |
@@ -22,9 +22,11 @@ |
#include "gdb_assert.h" |
#include <ctype.h> |
#include "gdb_string.h" |
+#include "gdb_wait.h" |
#include "event-top.h" |
#include "exceptions.h" |
#include "gdbthread.h" |
+#include "fnmatch.h" |
#ifdef HAVE_SYS_RESOURCE_H |
#include <sys/resource.h> |
#endif /* HAVE_SYS_RESOURCE_H */ |
@@ -98,8 +100,6 @@ static void vfprintf_maybe_filtered (struct ui_file *, const char *, |
static void fputs_maybe_filtered (const char *, struct ui_file *, int); |
-static void do_my_cleanups (struct cleanup **, struct cleanup *); |
- |
static void prompt_for_continue (void); |
static void set_screen_size (void); |
@@ -109,12 +109,6 @@ static void set_width (void); |
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 */ |
- |
/* Nonzero if we have job control. */ |
int job_control; |
@@ -171,31 +165,11 @@ show_pagination_enabled (struct ui_file *file, int from_tty, |
} |
+/* Cleanup utilities. |
-/* Add a new cleanup to the cleanup_chain, |
- and return the previous chain pointer |
- to be passed later to do_cleanups or discard_cleanups. |
- Args are FUNCTION to clean up with, and ARG to pass to it. */ |
- |
-struct cleanup * |
-make_cleanup (make_cleanup_ftype *function, void *arg) |
-{ |
- return make_my_cleanup (&cleanup_chain, function, arg); |
-} |
- |
-struct cleanup * |
-make_cleanup_dtor (make_cleanup_ftype *function, void *arg, |
- void (*dtor) (void *)) |
-{ |
- return make_my_cleanup2 (&cleanup_chain, |
- function, arg, dtor); |
-} |
- |
-struct cleanup * |
-make_final_cleanup (make_cleanup_ftype *function, void *arg) |
-{ |
- return make_my_cleanup (&final_cleanup_chain, function, arg); |
-} |
+ These are not defined in cleanups.c (nor declared in cleanups.h) |
+ because while they use the "cleanup API" they are not part of the |
+ "cleanup API". */ |
static void |
do_freeargv (void *arg) |
@@ -206,7 +180,7 @@ do_freeargv (void *arg) |
struct cleanup * |
make_cleanup_freeargv (char **arg) |
{ |
- return make_my_cleanup (&cleanup_chain, do_freeargv, arg); |
+ return make_cleanup (do_freeargv, arg); |
} |
static void |
@@ -218,7 +192,7 @@ do_dyn_string_delete (void *arg) |
struct cleanup * |
make_cleanup_dyn_string_delete (dyn_string_t arg) |
{ |
- return make_my_cleanup (&cleanup_chain, do_dyn_string_delete, arg); |
+ return make_cleanup (do_dyn_string_delete, arg); |
} |
static void |
@@ -295,7 +269,7 @@ do_ui_file_delete (void *arg) |
struct cleanup * |
make_cleanup_ui_file_delete (struct ui_file *arg) |
{ |
- return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg); |
+ return make_cleanup (do_ui_file_delete, arg); |
} |
/* Helper function for make_cleanup_ui_out_redirect_pop. */ |
@@ -315,7 +289,7 @@ do_ui_out_redirect_pop (void *arg) |
struct cleanup * |
make_cleanup_ui_out_redirect_pop (struct ui_out *uiout) |
{ |
- return make_my_cleanup (&cleanup_chain, do_ui_out_redirect_pop, uiout); |
+ return make_cleanup (do_ui_out_redirect_pop, uiout); |
} |
static void |
@@ -327,7 +301,7 @@ do_free_section_addr_info (void *arg) |
struct cleanup * |
make_cleanup_free_section_addr_info (struct section_addr_info *addrs) |
{ |
- return make_my_cleanup (&cleanup_chain, do_free_section_addr_info, addrs); |
+ return make_cleanup (do_free_section_addr_info, addrs); |
} |
struct restore_integer_closure |
@@ -356,8 +330,7 @@ make_cleanup_restore_integer (int *variable) |
c->variable = variable; |
c->value = *variable; |
- return make_my_cleanup2 (&cleanup_chain, restore_integer, (void *)c, |
- xfree); |
+ return make_cleanup_dtor (restore_integer, (void *) c, xfree); |
} |
/* Remember the current value of *VARIABLE and make it restored when |
@@ -384,7 +357,7 @@ do_unpush_target (void *arg) |
struct cleanup * |
make_cleanup_unpush_target (struct target_ops *ops) |
{ |
- return make_my_cleanup (&cleanup_chain, do_unpush_target, ops); |
+ return make_cleanup (do_unpush_target, ops); |
} |
/* Helper for make_cleanup_htab_delete compile time checking the types. */ |
@@ -447,7 +420,7 @@ do_value_free_to_mark (void *value) |
struct cleanup * |
make_cleanup_value_free_to_mark (struct value *mark) |
{ |
- return make_my_cleanup (&cleanup_chain, do_value_free_to_mark, mark); |
+ return make_cleanup (do_value_free_to_mark, mark); |
} |
/* Helper for make_cleanup_value_free. */ |
@@ -463,7 +436,7 @@ do_value_free (void *value) |
struct cleanup * |
make_cleanup_value_free (struct value *value) |
{ |
- return make_my_cleanup (&cleanup_chain, do_value_free, value); |
+ return make_cleanup (do_value_free, value); |
} |
/* Helper for make_cleanup_free_so. */ |
@@ -481,133 +454,7 @@ do_free_so (void *arg) |
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)); |
- struct cleanup *old_chain = *pmy_chain; |
- |
- 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. */ |
- |
-void |
-do_cleanups (struct cleanup *old_chain) |
-{ |
- do_my_cleanups (&cleanup_chain, old_chain); |
-} |
- |
-void |
-do_final_cleanups (struct cleanup *old_chain) |
-{ |
- do_my_cleanups (&final_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 in case of recursion. */ |
- (*ptr->function) (ptr->arg); |
- if (ptr->free_arg) |
- (*ptr->free_arg) (ptr->arg); |
- xfree (ptr); |
- } |
-} |
- |
-/* Discard cleanups, not doing the actions they describe, |
- until we get back to the point OLD_CHAIN in the cleanup_chain. */ |
- |
-void |
-discard_cleanups (struct cleanup *old_chain) |
-{ |
- discard_my_cleanups (&cleanup_chain, old_chain); |
-} |
- |
-void |
-discard_final_cleanups (struct cleanup *old_chain) |
-{ |
- discard_my_cleanups (&final_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); |
- } |
-} |
- |
-/* Set the cleanup_chain to 0, and return the old cleanup chain. */ |
-struct cleanup * |
-save_cleanups (void) |
-{ |
- return save_my_cleanups (&cleanup_chain); |
-} |
- |
-struct cleanup * |
-save_final_cleanups (void) |
-{ |
- return save_my_cleanups (&final_cleanup_chain); |
-} |
- |
-struct cleanup * |
-save_my_cleanups (struct cleanup **pmy_chain) |
-{ |
- struct cleanup *old_chain = *pmy_chain; |
- |
- *pmy_chain = 0; |
- return old_chain; |
-} |
- |
-/* Restore the cleanup chain from a previously saved chain. */ |
-void |
-restore_cleanups (struct cleanup *chain) |
-{ |
- restore_my_cleanups (&cleanup_chain, chain); |
-} |
- |
-void |
-restore_final_cleanups (struct cleanup *chain) |
-{ |
- restore_my_cleanups (&final_cleanup_chain, chain); |
-} |
- |
-void |
-restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain) |
-{ |
- *pmy_chain = chain; |
+ return make_cleanup (do_free_so, so); |
} |
/* This function is useful for cleanups. |
@@ -633,18 +480,6 @@ free_current_contents (void *ptr) |
} |
} |
-/* Provide a known function that does nothing, to use as a base for |
- 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. */ |
- |
-void |
-null_cleanup (void *arg) |
-{ |
-} |
- |
/* If nonzero, display time usage both at startup and for each command. */ |
static int display_time; |
@@ -885,7 +720,7 @@ can_dump_core (const char *reason) |
const char internal_problem_ask[] = "ask"; |
const char internal_problem_yes[] = "yes"; |
const char internal_problem_no[] = "no"; |
-static const char *internal_problem_modes[] = |
+static const char *const internal_problem_modes[] = |
{ |
internal_problem_ask, |
internal_problem_yes, |
@@ -969,7 +804,7 @@ internal_vproblem (struct internal_problem *problem, |
/* Default (yes/batch case) is to quit GDB. When in batch mode |
this lessens the likelihood of GDB going into an infinite |
loop. */ |
- if (caution == 0) |
+ if (!confirm) |
{ |
/* Emit the message and quit. */ |
fputs_unfiltered (reason, gdb_stderr); |
@@ -1383,7 +1218,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) |
/* Automatically answer the default value if the user did not want |
prompts or the command was issued with the server prefix. */ |
- if (! caution || server_command) |
+ if (!confirm || server_command) |
return def_value; |
/* If input isn't coming from the user directly, just say what |
@@ -2588,7 +2423,7 @@ print_spaces_filtered (int n, struct ui_file *stream) |
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; |
@@ -3338,6 +3173,25 @@ gdb_realpath (const char *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); |
} |
@@ -3782,6 +3636,254 @@ producer_is_gcc_ge_4 (const char *producer) |
return minor; |
} |
+/* Call 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 it got registered with this function |
+ by make_cleanup as the CHAR_PTR_VEC base address may change on its updates. |
+ Contrary to VEC_free this function does not (cannot) clear the pointer. */ |
+ |
+void |
+free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec) |
+{ |
+ int ix; |
+ char *name; |
+ |
+ for (ix = 0; VEC_iterate (char_ptr, char_ptr_vec, ix, name); ++ix) |
+ xfree (name); |
+ VEC_free (char_ptr, char_ptr_vec); |
+} |
+ |
+/* 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); |
+} |
+ |
+/* Extended version of dirnames_to_char_ptr_vec - additionally if *VECP is |
+ non-NULL the new list elements from DIRNAMES are appended to the existing |
+ *VECP list of entries. *VECP address will be updated by this call. */ |
+ |
+void |
+dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp, const char *dirnames) |
+{ |
+ do |
+ { |
+ size_t this_len; |
+ char *next_dir, *this_dir; |
+ |
+ next_dir = strchr (dirnames, DIRNAME_SEPARATOR); |
+ if (next_dir == NULL) |
+ this_len = strlen (dirnames); |
+ else |
+ { |
+ this_len = next_dir - dirnames; |
+ next_dir++; |
+ } |
+ |
+ this_dir = xmalloc (this_len + 1); |
+ memcpy (this_dir, dirnames, this_len); |
+ this_dir[this_len] = '\0'; |
+ VEC_safe_push (char_ptr, *vecp, this_dir); |
+ |
+ dirnames = next_dir; |
+ } |
+ while (dirnames != NULL); |
+} |
+ |
+/* Split DIRNAMES by DIRNAME_SEPARATOR delimiter and return a list of all the |
+ elements in their original order. For empty string ("") DIRNAMES return |
+ list of one empty string ("") element. |
+ |
+ You may modify the returned strings. |
+ Read free_char_ptr_vec for its cleanup. */ |
+ |
+VEC (char_ptr) * |
+dirnames_to_char_ptr_vec (const char *dirnames) |
+{ |
+ VEC (char_ptr) *retval = NULL; |
+ |
+ dirnames_to_char_ptr_vec_append (&retval, dirnames); |
+ |
+ return retval; |
+} |
+ |
+/* 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 |
+ located at the start or end of *STRINGP. */ |
+ |
+void |
+substitute_path_component (char **stringp, const char *from, const char *to) |
+{ |
+ char *string = *stringp, *s; |
+ const size_t from_len = strlen (from); |
+ const size_t to_len = strlen (to); |
+ |
+ for (s = string;;) |
+ { |
+ s = strstr (s, from); |
+ if (s == NULL) |
+ break; |
+ |
+ if ((s == string || IS_DIR_SEPARATOR (s[-1]) |
+ || s[-1] == DIRNAME_SEPARATOR) |
+ && (s[from_len] == '\0' || IS_DIR_SEPARATOR (s[from_len]) |
+ || s[from_len] == DIRNAME_SEPARATOR)) |
+ { |
+ char *string_new; |
+ |
+ string_new = xrealloc (string, (strlen (string) + to_len + 1)); |
+ |
+ /* Relocate the current S pointer. */ |
+ s = s - string + string_new; |
+ string = string_new; |
+ |
+ /* Replace from by to. */ |
+ memmove (&s[to_len], &s[from_len], strlen (&s[from_len]) + 1); |
+ memcpy (s, to, to_len); |
+ |
+ s += to_len; |
+ } |
+ else |
+ s++; |
+ } |
+ |
+ *stringp = string; |
+} |
+ |
+#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 fnmatch compatible function for FNM_FILE_NAME matching of host files. |
+ Both FNM_FILE_NAME and FNM_NOESCAPE must be set in FLAGS. |
+ |
+ It handles correctly HAVE_DOS_BASED_FILE_SYSTEM and |
+ HAVE_CASE_INSENSITIVE_FILE_SYSTEM. */ |
+ |
+int |
+gdb_filename_fnmatch (const char *pattern, const char *string, int flags) |
+{ |
+ gdb_assert ((flags & FNM_FILE_NAME) != 0); |
+ |
+ /* It is unclear how '\' escaping vs. directory separator should coexist. */ |
+ gdb_assert ((flags & FNM_NOESCAPE) != 0); |
+ |
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM |
+ { |
+ char *pattern_slash, *string_slash; |
+ |
+ /* Replace '\' by '/' in both strings. */ |
+ |
+ pattern_slash = 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); |
+ strcpy (string_slash, string); |
+ string = string_slash; |
+ for (; *string_slash != 0; string_slash++) |
+ if (IS_DIR_SEPARATOR (*string_slash)) |
+ *string_slash = '/'; |
+ } |
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ |
+ |
+#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM |
+ flags |= FNM_CASEFOLD; |
+#endif /* HAVE_CASE_INSENSITIVE_FILE_SYSTEM */ |
+ |
+ return fnmatch (pattern, string, flags); |
+} |
+ |
/* Provide a prototype to silence -Wmissing-prototypes. */ |
extern initialize_file_ftype _initialize_utils; |