/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc.
This file is part of GDB.
#include "event-top.h"
#include "exceptions.h"
#include "gdbthread.h"
+#include "fnmatch.h"
+#include "gdb_bfd.h"
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif /* HAVE_SYS_RESOURCE_H */
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);
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;
}
\f
+/* 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)
struct cleanup *
make_cleanup_freeargv (char **arg)
{
- return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
+ return make_cleanup (do_freeargv, arg);
}
static void
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
do_bfd_close_cleanup (void *arg)
{
- bfd_close (arg);
+ gdb_bfd_unref (arg);
}
struct cleanup *
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. */
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
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
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
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. */
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. */
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. */
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.
}
}
-/* 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;
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,
/* 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);
/* 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
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;
}
#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 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
#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;