X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Futils.c;h=577f9df4ecc6d0a5838daaa9c20a6e2d9ecca7a6;hb=815615463b1171cbff7c5e54f62fc708cc1bbc99;hp=24294be4f4989493350796d2ddfdbddff57f7293;hpb=b32b108aba2c0119d0e231d203d3284539da2379;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/utils.c b/gdb/utils.c index 24294be4f4..577f9df4ec 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1,6 +1,6 @@ /* General utility routines for GDB, the GNU debugger. - Copyright (C) 1986-2017 Free Software Foundation, Inc. + Copyright (C) 1986-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -68,6 +68,9 @@ #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 */ @@ -150,44 +153,6 @@ 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 - = (struct restore_integer_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 = XNEW (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 @@ -223,22 +188,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 ((struct value *) value); -} - -/* Free VALUE. */ - -struct cleanup * -make_cleanup_value_free (struct value *value) -{ - return make_cleanup (do_value_free, value); -} - /* This function is useful for cleanups. Do @@ -430,8 +379,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. */ { @@ -464,21 +412,17 @@ internal_vproblem (struct internal_problem *problem, 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, stderr); + fputs (reason.c_str (), stderr); abort_with_message ("\n"); } @@ -496,7 +440,7 @@ internal_vproblem (struct internal_problem *problem, if (problem->should_quit != internal_problem_ask || !confirm || !filtered_printing_initialized ()) - fprintf_unfiltered (gdb_stderr, "%s\n", reason); + fprintf_unfiltered (gdb_stderr, "%s\n", reason.c_str ()); if (problem->should_quit == internal_problem_ask) { @@ -506,7 +450,8 @@ internal_vproblem (struct internal_problem *problem, 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; @@ -523,7 +468,7 @@ internal_vproblem (struct internal_problem *problem, if (problem->should_dump_core == internal_problem_ask) { - if (!can_dump_core_warn (LIMIT_MAX, reason)) + if (!can_dump_core_warn (LIMIT_MAX, reason.c_str ())) dump_core_p = 0; else if (!filtered_printing_initialized ()) dump_core_p = 1; @@ -532,11 +477,12 @@ internal_vproblem (struct internal_problem *problem, /* 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_warn (LIMIT_MAX, 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 @@ -561,7 +507,6 @@ internal_vproblem (struct internal_problem *problem, } dejavu = 0; - do_cleanups (cleanup); } static struct internal_problem internal_error_problem = { @@ -608,12 +553,12 @@ demangler_warning (const char *file, int line, const char *string, ...) /* 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) { } @@ -651,14 +596,14 @@ 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, " ", @@ -786,8 +731,6 @@ print_sys_errmsg (const char *string, int errcode) void quit (void) { - struct ui *ui = current_ui; - if (sync_quit_force_run) { sync_quit_force_run = 0; @@ -948,13 +891,10 @@ private: static int ATTRIBUTE_PRINTF (1, 0) defaulted_query (const char *ctlstr, const char defchar, va_list args) { - int ans2; int retval; int def_value; char def_answer, not_def_answer; const char *y_string, *n_string; - char *question, *prompt; - struct cleanup *old_chain; /* Set up according to which answer is the default. */ if (defchar == '\0') @@ -1016,13 +956,12 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) } /* Format the question outside of the loop, to avoid reusing args. */ - question = xstrvprintf (ctlstr, args); - old_chain = make_cleanup (xfree, question); - prompt = xstrprintf (_("%s%s(%s or %s) %s"), - annotation_level > 1 ? "\n\032\032pre-query\n" : "", - question, y_string, n_string, - annotation_level > 1 ? "\n\032\032query\n" : ""); - make_cleanup (xfree, prompt); + 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. */ @@ -1036,7 +975,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) char *response, answer; gdb_flush (gdb_stdout); - response = gdb_readline_wrapper (prompt); + response = gdb_readline_wrapper (prompt.c_str ()); if (response == NULL) /* C-d */ { @@ -1076,7 +1015,6 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) if (annotation_level > 1) printf_filtered (("\n\032\032post-query\n")); - do_cleanups (old_chain); return retval; } @@ -1464,42 +1402,23 @@ filtered_printing_initialized (void) return wrap_buffer != NULL; } -/* Helper for make_cleanup_restore_page_info. */ - -static void -do_restore_page_info_cleanup (void *arg) -{ - set_screen_size (); - set_width (); -} - -/* Provide cleanup for restoring the terminal size. */ - -struct cleanup * -make_cleanup_restore_page_info (void) +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; - - 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; + batch_flag = 1; + init_page_info (); } -/* 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 () { - struct cleanup *back_to = make_cleanup_restore_page_info (); - - make_cleanup_restore_integer (&batch_flag); - batch_flag = 1; - init_page_info (); + batch_flag = m_save_batch_flag; + chars_per_line = m_save_chars_per_line; + lines_per_page = m_save_lines_per_page; - return back_to; + set_screen_size (); + set_width (); } /* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */ @@ -1540,14 +1459,14 @@ 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) +set_height_command (const char *args, int from_tty, struct cmd_list_element *c) { set_screen_size (); } @@ -2036,13 +1955,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); } @@ -2055,11 +1969,7 @@ 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) { using namespace std::chrono; @@ -2069,18 +1979,18 @@ vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args) 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'); std::string timestamp = string_printf ("%ld.%06ld %s%s", (long) s.count (), (long) us.count (), - linebuffer, need_nl ? "\n": ""); + 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 @@ -2246,34 +2156,292 @@ fprintf_symbol_filtered (struct ui_file *stream, const char *name, } } -/* Modes of operation for strncmp_iw_with_mode. */ +/* True if CH is a character that can be part of a symbol name. I.e., + either a number, a letter, or a '_'. */ -enum class strncmp_iw_mode +static bool +valid_identifier_name_char (int ch) { - /* Work like strncmp, while ignoring whitespace. */ - NORMAL, + return (isalnum (ch) || ch == '_'); +} - /* Like NORMAL, but also apply the strcmp_iw hack. I.e., - string1=="FOO(PARAMS)" matches string2=="FOO". */ - MATCH_PARAMS, -}; +/* Skip to end of token, or to END, whatever comes first. Input is + assumed to be a C++ operator name. */ + +static const char * +cp_skip_operator_token (const char *token, const char *end) +{ + const char *p = token; + while (p != end && !isspace (*p) && *p != '(') + { + if (valid_identifier_name_char (*p)) + { + 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; +} -/* Helper for strncmp_iw and strcmp_iw. */ +/* Advance STRING1/STRING2 past whitespace. */ -static int +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) + 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) { - while (isspace (*string1)) - string1++; - while (string2 < end_str2 && isspace (*string2)) - string2++; + 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++; + } + 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 @@ -2281,6 +2449,12 @@ strncmp_iw_with_mode (const char *string1, const char *string2, != tolower ((unsigned char) *string2))) break; + /* 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++; } @@ -2288,7 +2462,40 @@ strncmp_iw_with_mode (const char *string1, const char *string2, if (string2 == end_str2) { if (mode == strncmp_iw_mode::NORMAL) - return 0; + { + /* 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 != '('); } @@ -2302,7 +2509,7 @@ 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); + strncmp_iw_mode::NORMAL, language_minimal); } /* See utils.h. */ @@ -2311,7 +2518,7 @@ int strcmp_iw (const char *string1, const char *string2) { return strncmp_iw_with_mode (string1, string2, strlen (string2), - strncmp_iw_mode::MATCH_PARAMS); + strncmp_iw_mode::MATCH_PARAMS, language_minimal); } /* This is like strcmp except that it ignores whitespace and treats @@ -2518,6 +2725,23 @@ When set, debugging messages will be marked with seconds and microseconds."), &setdebuglist, &showdebuglist); } +/* See utils.h. */ + +CORE_ADDR +address_significant (gdbarch *gdbarch, CORE_ADDR addr) +{ + /* 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); + + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + addr &= ((CORE_ADDR) 1 << addr_bit) - 1; + + return addr; +} + const char * paddress (struct gdbarch *gdbarch, CORE_ADDR addr) { @@ -2615,57 +2839,6 @@ string_to_core_addr (const char *my_string) return addr; } -gdb::unique_xmalloc_ptr -gdb_realpath (const char *filename) -{ -/* On most hosts, we rely on canonicalize_file_name to compute - the FILENAME's realpath. - - But the situation is slightly more complex on Windows, due to some - versions of GCC which were reported to generate paths where - backlashes (the directory separator) were doubled. For instance: - c:\\some\\double\\slashes\\dir - ... instead of ... - c:\some\double\slashes\dir - Those double-slashes were getting in the way when comparing paths, - for instance when trying to insert a breakpoint as follow: - (gdb) b c:/some/double/slashes/dir/foo.c:4 - No source file named c:/some/double/slashes/dir/foo.c:4. - (gdb) b c:\some\double\slashes\dir\foo.c:4 - No source file named c:\some\double\slashes\dir\foo.c:4. - To prevent this from happening, we need this function to always - strip those extra backslashes. While canonicalize_file_name does - perform this simplification, it only works when the path is valid. - Since the simplification would be useful even if the path is not - valid (one can always set a breakpoint on a file, even if the file - does not exist locally), we rely instead on GetFullPathName to - perform the canonicalization. */ - -#if defined (_WIN32) - { - char buf[MAX_PATH]; - DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL); - - /* The file system is case-insensitive but case-preserving. - So it is important we do not lowercase the path. Otherwise, - we might not be able to display the original casing in a given - path. */ - if (len > 0 && len < MAX_PATH) - return gdb::unique_xmalloc_ptr (xstrdup (buf)); - } -#else - { - char *rp = canonicalize_file_name (filename); - - if (rp != NULL) - return gdb::unique_xmalloc_ptr (rp); - } -#endif - - /* This system is a lost cause, just dup the buffer. */ - return gdb::unique_xmalloc_ptr (xstrdup (filename)); -} - #if GDB_SELF_TEST static void @@ -2702,74 +2875,6 @@ gdb_realpath_tests () #endif /* GDB_SELF_TEST */ -/* Return a copy of FILENAME, with its directory prefix canonicalized - by gdb_realpath. */ - -gdb::unique_xmalloc_ptr -gdb_realpath_keepfile (const char *filename) -{ - const char *base_name = lbasename (filename); - char *dir_name; - 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 gdb::unique_xmalloc_ptr (xstrdup (filename)); - - dir_name = (char *) 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 - - /* Canonicalize the directory prefix, and build the resulting - filename. If the dirname realpath already contains an ending - directory separator, avoid doubling it. */ - gdb::unique_xmalloc_ptr path_storage = gdb_realpath (dir_name); - const char *real_path = path_storage.get (); - 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); - - return gdb::unique_xmalloc_ptr (result); -} - -/* 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. */ - -gdb::unique_xmalloc_ptr -gdb_abspath (const char *path) -{ - gdb_assert (path != NULL && path[0] != '\0'); - - if (path[0] == '~') - return gdb::unique_xmalloc_ptr (tilde_expand (path)); - - if (IS_ABSOLUTE_PATH (path)) - return gdb::unique_xmalloc_ptr (xstrdup (path)); - - /* Beware the // my son, the Emacs barfs, the botch that catch... */ - return gdb::unique_xmalloc_ptr - (concat (current_directory, - IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) - ? "" : SLASH_STRING, - path, (char *) NULL)); -} - ULONGEST align_up (ULONGEST v, int n) {