123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049 |
- /* List lines of source files for GDB, the GNU debugger.
- Copyright (C) 1986-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "arch-utils.h"
- #include "symtab.h"
- #include "expression.h"
- #include "language.h"
- #include "command.h"
- #include "source.h"
- #include "gdbcmd.h"
- #include "frame.h"
- #include "value.h"
- #include "gdbsupport/filestuff.h"
- #include <sys/types.h>
- #include <fcntl.h>
- #include "gdbcore.h"
- #include "gdbsupport/gdb_regex.h"
- #include "symfile.h"
- #include "objfiles.h"
- #include "annotate.h"
- #include "gdbtypes.h"
- #include "linespec.h"
- #include "filenames.h" /* for DOSish file names */
- #include "completer.h"
- #include "ui-out.h"
- #include "readline/tilde.h"
- #include "gdbsupport/enum-flags.h"
- #include "gdbsupport/scoped_fd.h"
- #include <algorithm>
- #include "gdbsupport/pathstuff.h"
- #include "source-cache.h"
- #include "cli/cli-style.h"
- #include "observable.h"
- #include "build-id.h"
- #include "debuginfod-support.h"
- #include "gdbsupport/buildargv.h"
- #define OPEN_MODE (O_RDONLY | O_BINARY)
- #define FDOPEN_MODE FOPEN_RB
- /* Path of directories to search for source files.
- Same format as the PATH environment variable's value. */
- std::string source_path;
- /* Support for source path substitution commands. */
- struct substitute_path_rule
- {
- substitute_path_rule (const char *from_, const char *to_)
- : from (from_),
- to (to_)
- {
- }
- std::string from;
- std::string to;
- };
- static std::list<substitute_path_rule> substitute_path_rules;
- /* An instance of this is attached to each program space. */
- struct current_source_location
- {
- public:
- current_source_location () = default;
- /* Set the value. */
- void set (struct symtab *s, int l)
- {
- m_symtab = s;
- m_line = l;
- gdb::observers::current_source_symtab_and_line_changed.notify ();
- }
- /* Get the symtab. */
- struct symtab *symtab () const
- {
- return m_symtab;
- }
- /* Get the line number. */
- int line () const
- {
- return m_line;
- }
- private:
- /* Symtab of default file for listing lines of. */
- struct symtab *m_symtab = nullptr;
- /* Default next line to list. */
- int m_line = 0;
- };
- static program_space_key<current_source_location> current_source_key;
- /* Default number of lines to print with commands like "list".
- This is based on guessing how many long (i.e. more than chars_per_line
- characters) lines there will be. To be completely correct, "list"
- and friends should be rewritten to count characters and see where
- things are wrapping, but that would be a fair amount of work. */
- static int lines_to_list = 10;
- static void
- show_lines_to_list (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("Number of source lines gdb "
- "will list by default is %s.\n"),
- value);
- }
- /* Possible values of 'set filename-display'. */
- static const char filename_display_basename[] = "basename";
- static const char filename_display_relative[] = "relative";
- static const char filename_display_absolute[] = "absolute";
- static const char *const filename_display_kind_names[] = {
- filename_display_basename,
- filename_display_relative,
- filename_display_absolute,
- NULL
- };
- static const char *filename_display_string = filename_display_relative;
- static void
- show_filename_display_string (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Filenames are displayed as \"%s\".\n"), value);
- }
- /* When true GDB will stat and open source files as required, but when
- false, GDB will avoid accessing source files as much as possible. */
- static bool source_open = true;
- /* Implement 'show source open'. */
- static void
- show_source_open (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Source opening is \"%s\".\n"), value);
- }
- /* Line number of last line printed. Default for various commands.
- current_source_line is usually, but not always, the same as this. */
- static int last_line_listed;
- /* First line number listed by last listing command. If 0, then no
- source lines have yet been listed since the last time the current
- source line was changed. */
- static int first_line_listed;
- /* Saves the name of the last source file visited and a possible error code.
- Used to prevent repeating annoying "No such file or directories" msgs. */
- static struct symtab *last_source_visited = NULL;
- static bool last_source_error = false;
- /* Return the first line listed by print_source_lines.
- Used by command interpreters to request listing from
- a previous point. */
- int
- get_first_line_listed (void)
- {
- return first_line_listed;
- }
- /* Clear line listed range. This makes the next "list" center the
- printed source lines around the current source line. */
- static void
- clear_lines_listed_range (void)
- {
- first_line_listed = 0;
- last_line_listed = 0;
- }
- /* Return the default number of lines to print with commands like the
- cli "list". The caller of print_source_lines must use this to
- calculate the end line and use it in the call to print_source_lines
- as it does not automatically use this value. */
- int
- get_lines_to_list (void)
- {
- return lines_to_list;
- }
- /* A helper to return the current source location object for PSPACE,
- creating it if it does not exist. */
- static current_source_location *
- get_source_location (program_space *pspace)
- {
- current_source_location *loc
- = current_source_key.get (pspace);
- if (loc == nullptr)
- loc = current_source_key.emplace (pspace);
- return loc;
- }
- /* Return the current source file for listing and next line to list.
- NOTE: The returned sal pc and end fields are not valid. */
-
- struct symtab_and_line
- get_current_source_symtab_and_line (void)
- {
- symtab_and_line cursal;
- current_source_location *loc = get_source_location (current_program_space);
- cursal.pspace = current_program_space;
- cursal.symtab = loc->symtab ();
- cursal.line = loc->line ();
- cursal.pc = 0;
- cursal.end = 0;
-
- return cursal;
- }
- /* If the current source file for listing is not set, try and get a default.
- Usually called before get_current_source_symtab_and_line() is called.
- It may err out if a default cannot be determined.
- We must be cautious about where it is called, as it can recurse as the
- process of determining a new default may call the caller!
- Use get_current_source_symtab_and_line only to get whatever
- we have without erroring out or trying to get a default. */
-
- void
- set_default_source_symtab_and_line (void)
- {
- if (!have_full_symbols () && !have_partial_symbols ())
- error (_("No symbol table is loaded. Use the \"file\" command."));
- /* Pull in a current source symtab if necessary. */
- current_source_location *loc = get_source_location (current_program_space);
- if (loc->symtab () == nullptr)
- select_source_symtab (0);
- }
- /* Return the current default file for listing and next line to list
- (the returned sal pc and end fields are not valid.)
- and set the current default to whatever is in SAL.
- NOTE: The returned sal pc and end fields are not valid. */
-
- struct symtab_and_line
- set_current_source_symtab_and_line (const symtab_and_line &sal)
- {
- symtab_and_line cursal;
- current_source_location *loc = get_source_location (sal.pspace);
- cursal.pspace = sal.pspace;
- cursal.symtab = loc->symtab ();
- cursal.line = loc->line ();
- cursal.pc = 0;
- cursal.end = 0;
- loc->set (sal.symtab, sal.line);
- /* Force the next "list" to center around the current line. */
- clear_lines_listed_range ();
- return cursal;
- }
- /* Reset any information stored about a default file and line to print. */
- void
- clear_current_source_symtab_and_line (void)
- {
- current_source_location *loc = get_source_location (current_program_space);
- loc->set (nullptr, 0);
- }
- /* See source.h. */
- void
- select_source_symtab (struct symtab *s)
- {
- if (s)
- {
- current_source_location *loc
- = get_source_location (s->compunit ()->objfile ()->pspace);
- loc->set (s, 1);
- return;
- }
- current_source_location *loc = get_source_location (current_program_space);
- if (loc->symtab () != nullptr)
- return;
- /* Make the default place to list be the function `main'
- if one exists. */
- block_symbol bsym = lookup_symbol (main_name (), 0, VAR_DOMAIN, 0);
- if (bsym.symbol != nullptr && bsym.symbol->aclass () == LOC_BLOCK)
- {
- symtab_and_line sal = find_function_start_sal (bsym.symbol, true);
- if (sal.symtab == NULL)
- /* We couldn't find the location of `main', possibly due to missing
- line number info, fall back to line 1 in the corresponding file. */
- loc->set (symbol_symtab (bsym.symbol), 1);
- else
- loc->set (sal.symtab, std::max (sal.line - (lines_to_list - 1), 1));
- return;
- }
- /* Alright; find the last file in the symtab list (ignoring .h's
- and namespace symtabs). */
- struct symtab *new_symtab = nullptr;
- for (objfile *ofp : current_program_space->objfiles ())
- {
- for (compunit_symtab *cu : ofp->compunits ())
- {
- for (symtab *symtab : cu->filetabs ())
- {
- const char *name = symtab->filename;
- int len = strlen (name);
- if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
- || strcmp (name, "<<C++-namespaces>>") == 0)))
- new_symtab = symtab;
- }
- }
- }
- loc->set (new_symtab, 1);
- if (new_symtab != nullptr)
- return;
- for (objfile *objfile : current_program_space->objfiles ())
- {
- s = objfile->find_last_source_symtab ();
- if (s)
- new_symtab = s;
- }
- if (new_symtab != nullptr)
- {
- loc->set (new_symtab,1);
- return;
- }
- error (_("Can't find a default source file"));
- }
- /* Handler for "set directories path-list" command.
- "set dir mumble" doesn't prepend paths, it resets the entire
- path list. The theory is that set(show(dir)) should be a no-op. */
- static void
- set_directories_command (const char *args,
- int from_tty, struct cmd_list_element *c)
- {
- /* This is the value that was set.
- It needs to be processed to maintain $cdir:$cwd and remove dups. */
- std::string set_path = source_path;
- /* We preserve the invariant that $cdir:$cwd begins life at the end of
- the list by calling init_source_path. If they appear earlier in
- SET_PATH then mod_path will move them appropriately.
- mod_path will also remove duplicates. */
- init_source_path ();
- if (!set_path.empty ())
- mod_path (set_path.c_str (), source_path);
- }
- /* Print the list of source directories.
- This is used by the "ld" command, so it has the signature of a command
- function. */
- static void
- show_directories_1 (ui_file *file, char *ignore, int from_tty)
- {
- gdb_puts ("Source directories searched: ", file);
- gdb_puts (source_path.c_str (), file);
- gdb_puts ("\n", file);
- }
- /* Handler for "show directories" command. */
- static void
- show_directories_command (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- show_directories_1 (file, NULL, from_tty);
- }
- /* See source.h. */
- void
- forget_cached_source_info_for_objfile (struct objfile *objfile)
- {
- for (compunit_symtab *cu : objfile->compunits ())
- {
- for (symtab *s : cu->filetabs ())
- {
- if (s->fullname != NULL)
- {
- xfree (s->fullname);
- s->fullname = NULL;
- }
- }
- }
- objfile->forget_cached_source_info ();
- }
- /* See source.h. */
- void
- forget_cached_source_info (void)
- {
- for (struct program_space *pspace : program_spaces)
- for (objfile *objfile : pspace->objfiles ())
- {
- forget_cached_source_info_for_objfile (objfile);
- }
- g_source_cache.clear ();
- last_source_visited = NULL;
- }
- void
- init_source_path (void)
- {
- source_path = string_printf ("$cdir%c$cwd", DIRNAME_SEPARATOR);
- forget_cached_source_info ();
- }
- /* Add zero or more directories to the front of the source path. */
- static void
- directory_command (const char *dirname, int from_tty)
- {
- bool value_changed = false;
- dont_repeat ();
- /* FIXME, this goes to "delete dir"... */
- if (dirname == 0)
- {
- if (!from_tty || query (_("Reinitialize source path to empty? ")))
- {
- init_source_path ();
- value_changed = true;
- }
- }
- else
- {
- mod_path (dirname, source_path);
- forget_cached_source_info ();
- value_changed = true;
- }
- if (value_changed)
- {
- gdb::observers::command_param_changed.notify ("directories",
- source_path.c_str ());
- if (from_tty)
- show_directories_1 (gdb_stdout, (char *) 0, from_tty);
- }
- }
- /* Add a path given with the -d command line switch.
- This will not be quoted so we must not treat spaces as separators. */
- void
- directory_switch (const char *dirname, int from_tty)
- {
- add_path (dirname, source_path, 0);
- }
- /* Add zero or more directories to the front of an arbitrary path. */
- void
- mod_path (const char *dirname, std::string &which_path)
- {
- add_path (dirname, which_path, 1);
- }
- /* Workhorse of mod_path. Takes an extra argument to determine
- if dirname should be parsed for separators that indicate multiple
- directories. This allows for interfaces that pre-parse the dirname
- and allow specification of traditional separator characters such
- as space or tab. */
- void
- add_path (const char *dirname, char **which_path, int parse_separators)
- {
- char *old = *which_path;
- int prefix = 0;
- std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec;
- if (dirname == 0)
- return;
- if (parse_separators)
- {
- /* This will properly parse the space and tab separators
- and any quotes that may exist. */
- gdb_argv argv (dirname);
- for (char *arg : argv)
- dirnames_to_char_ptr_vec_append (&dir_vec, arg);
- }
- else
- dir_vec.emplace_back (xstrdup (dirname));
- for (const gdb::unique_xmalloc_ptr<char> &name_up : dir_vec)
- {
- char *name = name_up.get ();
- char *p;
- struct stat st;
- gdb::unique_xmalloc_ptr<char> new_name_holder;
- /* Spaces and tabs will have been removed by buildargv().
- NAME is the start of the directory.
- P is the '\0' following the end. */
- p = name + strlen (name);
- while (!(IS_DIR_SEPARATOR (*name) && p <= name + 1) /* "/" */
- #ifdef HAVE_DOS_BASED_FILE_SYSTEM
- /* On MS-DOS and MS-Windows, h:\ is different from h: */
- && !(p == name + 3 && name[1] == ':') /* "d:/" */
- #endif
- && p > name
- && IS_DIR_SEPARATOR (p[-1]))
- /* Sigh. "foo/" => "foo" */
- --p;
- *p = '\0';
- while (p > name && p[-1] == '.')
- {
- if (p - name == 1)
- {
- /* "." => getwd (). */
- name = current_directory;
- goto append;
- }
- else if (p > name + 1 && IS_DIR_SEPARATOR (p[-2]))
- {
- if (p - name == 2)
- {
- /* "/." => "/". */
- *--p = '\0';
- goto append;
- }
- else
- {
- /* "...foo/." => "...foo". */
- p -= 2;
- *p = '\0';
- continue;
- }
- }
- else
- break;
- }
- if (name[0] == '\0')
- goto skip_dup;
- if (name[0] == '~')
- new_name_holder.reset (tilde_expand (name));
- #ifdef HAVE_DOS_BASED_FILE_SYSTEM
- else if (IS_ABSOLUTE_PATH (name) && p == name + 2) /* "d:" => "d:." */
- new_name_holder.reset (concat (name, ".", (char *) NULL));
- #endif
- else if (!IS_ABSOLUTE_PATH (name) && name[0] != '$')
- new_name_holder = gdb_abspath (name);
- else
- new_name_holder.reset (savestring (name, p - name));
- name = new_name_holder.get ();
- /* Unless it's a variable, check existence. */
- if (name[0] != '$')
- {
- /* These are warnings, not errors, since we don't want a
- non-existent directory in a .gdbinit file to stop processing
- of the .gdbinit file.
- Whether they get added to the path is more debatable. Current
- answer is yes, in case the user wants to go make the directory
- or whatever. If the directory continues to not exist/not be
- a directory/etc, then having them in the path should be
- harmless. */
- if (stat (name, &st) < 0)
- {
- int save_errno = errno;
- gdb_printf (gdb_stderr, "Warning: ");
- print_sys_errmsg (name, save_errno);
- }
- else if ((st.st_mode & S_IFMT) != S_IFDIR)
- warning (_("%s is not a directory."), name);
- }
- append:
- {
- unsigned int len = strlen (name);
- char tinybuf[2];
- p = *which_path;
- while (1)
- {
- /* FIXME: we should use realpath() or its work-alike
- before comparing. Then all the code above which
- removes excess slashes and dots could simply go away. */
- if (!filename_ncmp (p, name, len)
- && (p[len] == '\0' || p[len] == DIRNAME_SEPARATOR))
- {
- /* Found it in the search path, remove old copy. */
- if (p > *which_path)
- {
- /* Back over leading separator. */
- p--;
- }
- if (prefix > p - *which_path)
- {
- /* Same dir twice in one cmd. */
- goto skip_dup;
- }
- /* Copy from next '\0' or ':'. */
- memmove (p, &p[len + 1], strlen (&p[len + 1]) + 1);
- }
- p = strchr (p, DIRNAME_SEPARATOR);
- if (p != 0)
- ++p;
- else
- break;
- }
- tinybuf[0] = DIRNAME_SEPARATOR;
- tinybuf[1] = '\0';
- /* If we have already tacked on a name(s) in this command,
- be sure they stay on the front as we tack on some
- more. */
- if (prefix)
- {
- std::string temp = std::string (old, prefix) + tinybuf + name;
- *which_path = concat (temp.c_str (), &old[prefix],
- (char *) nullptr);
- prefix = temp.length ();
- }
- else
- {
- *which_path = concat (name, (old[0] ? tinybuf : old),
- old, (char *)NULL);
- prefix = strlen (name);
- }
- xfree (old);
- old = *which_path;
- }
- skip_dup:
- ;
- }
- }
- /* add_path would need to be re-written to work on an std::string, but this is
- not trivial. Hence this overload which copies to a `char *` and back. */
- void
- add_path (const char *dirname, std::string &which_path, int parse_separators)
- {
- char *which_path_copy = xstrdup (which_path.data ());
- add_path (dirname, &which_path_copy, parse_separators);
- which_path = which_path_copy;
- xfree (which_path_copy);
- }
- static void
- info_source_command (const char *ignore, int from_tty)
- {
- current_source_location *loc
- = get_source_location (current_program_space);
- struct symtab *s = loc->symtab ();
- struct compunit_symtab *cust;
- if (!s)
- {
- gdb_printf (_("No current source file.\n"));
- return;
- }
- cust = s->compunit ();
- gdb_printf (_("Current source file is %s\n"), s->filename);
- if (s->compunit ()->dirname () != NULL)
- gdb_printf (_("Compilation directory is %s\n"), s->compunit ()->dirname ());
- if (s->fullname)
- gdb_printf (_("Located in %s\n"), s->fullname);
- const std::vector<off_t> *offsets;
- if (g_source_cache.get_line_charpos (s, &offsets))
- gdb_printf (_("Contains %d line%s.\n"), (int) offsets->size (),
- offsets->size () == 1 ? "" : "s");
- gdb_printf (_("Source language is %s.\n"),
- language_str (s->language ()));
- gdb_printf (_("Producer is %s.\n"),
- (cust->producer ()) != nullptr
- ? cust->producer () : _("unknown"));
- gdb_printf (_("Compiled with %s debugging format.\n"),
- cust->debugformat ());
- gdb_printf (_("%s preprocessor macro info.\n"),
- (cust->macro_table () != nullptr
- ? "Includes" : "Does not include"));
- }
- /* Helper function to remove characters from the start of PATH so that
- PATH can then be appended to a directory name. We remove leading drive
- letters (for dos) as well as leading '/' characters and './'
- sequences. */
- static const char *
- prepare_path_for_appending (const char *path)
- {
- /* For dos paths, d:/foo -> /foo, and d:foo -> foo. */
- if (HAS_DRIVE_SPEC (path))
- path = STRIP_DRIVE_SPEC (path);
- const char *old_path;
- do
- {
- old_path = path;
- /* /foo => foo, to avoid multiple slashes that Emacs doesn't like. */
- while (IS_DIR_SEPARATOR(path[0]))
- path++;
- /* ./foo => foo */
- while (path[0] == '.' && IS_DIR_SEPARATOR (path[1]))
- path += 2;
- }
- while (old_path != path);
- return path;
- }
- /* Open a file named STRING, searching path PATH (dir names sep by some char)
- using mode MODE in the calls to open. You cannot use this function to
- create files (O_CREAT).
- OPTS specifies the function behaviour in specific cases.
- If OPF_TRY_CWD_FIRST, try to open ./STRING before searching PATH.
- (ie pretend the first element of PATH is "."). This also indicates
- that, unless OPF_SEARCH_IN_PATH is also specified, a slash in STRING
- disables searching of the path (this is so that "exec-file ./foo" or
- "symbol-file ./foo" insures that you get that particular version of
- foo or an error message).
- If OPTS has OPF_SEARCH_IN_PATH set, absolute names will also be
- searched in path (we usually want this for source files but not for
- executables).
- If FILENAME_OPENED is non-null, set it to a newly allocated string naming
- the actual file opened (this string will always start with a "/"). We
- have to take special pains to avoid doubling the "/" between the directory
- and the file, sigh! Emacs gets confuzzed by this when we print the
- source file name!!!
- If OPTS has OPF_RETURN_REALPATH set return FILENAME_OPENED resolved by
- gdb_realpath. Even without OPF_RETURN_REALPATH this function still returns
- filename starting with "/". If FILENAME_OPENED is NULL this option has no
- effect.
- If a file is found, return the descriptor.
- Otherwise, return -1, with errno set for the last name we tried to open. */
- /* >>>> This should only allow files of certain types,
- >>>> eg executable, non-directory. */
- int
- openp (const char *path, openp_flags opts, const char *string,
- int mode, gdb::unique_xmalloc_ptr<char> *filename_opened)
- {
- int fd;
- char *filename;
- int alloclen;
- /* The errno set for the last name we tried to open (and
- failed). */
- int last_errno = 0;
- std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec;
- /* The open syscall MODE parameter is not specified. */
- gdb_assert ((mode & O_CREAT) == 0);
- gdb_assert (string != NULL);
- /* A file with an empty name cannot possibly exist. Report a failure
- without further checking.
- This is an optimization which also defends us against buggy
- implementations of the "stat" function. For instance, we have
- noticed that a MinGW debugger built on Windows XP 32bits crashes
- when the debugger is started with an empty argument. */
- if (string[0] == '\0')
- {
- errno = ENOENT;
- return -1;
- }
- if (!path)
- path = ".";
- mode |= O_BINARY;
- if ((opts & OPF_TRY_CWD_FIRST) || IS_ABSOLUTE_PATH (string))
- {
- int i, reg_file_errno;
- if (is_regular_file (string, ®_file_errno))
- {
- filename = (char *) alloca (strlen (string) + 1);
- strcpy (filename, string);
- fd = gdb_open_cloexec (filename, mode, 0).release ();
- if (fd >= 0)
- goto done;
- last_errno = errno;
- }
- else
- {
- filename = NULL;
- fd = -1;
- last_errno = reg_file_errno;
- }
- if (!(opts & OPF_SEARCH_IN_PATH))
- for (i = 0; string[i]; i++)
- if (IS_DIR_SEPARATOR (string[i]))
- goto done;
- }
- /* Remove characters from the start of PATH that we don't need when PATH
- is appended to a directory name. */
- string = prepare_path_for_appending (string);
- alloclen = strlen (path) + strlen (string) + 2;
- filename = (char *) alloca (alloclen);
- fd = -1;
- last_errno = ENOENT;
- dir_vec = dirnames_to_char_ptr_vec (path);
- for (const gdb::unique_xmalloc_ptr<char> &dir_up : dir_vec)
- {
- char *dir = dir_up.get ();
- size_t len = strlen (dir);
- int reg_file_errno;
- if (strcmp (dir, "$cwd") == 0)
- {
- /* Name is $cwd -- insert current directory name instead. */
- int newlen;
- /* First, realloc the filename buffer if too short. */
- len = strlen (current_directory);
- newlen = len + strlen (string) + 2;
- if (newlen > alloclen)
- {
- alloclen = newlen;
- filename = (char *) alloca (alloclen);
- }
- strcpy (filename, current_directory);
- }
- else if (strchr(dir, '~'))
- {
- /* See whether we need to expand the tilde. */
- int newlen;
- gdb::unique_xmalloc_ptr<char> tilde_expanded (tilde_expand (dir));
- /* First, realloc the filename buffer if too short. */
- len = strlen (tilde_expanded.get ());
- newlen = len + strlen (string) + 2;
- if (newlen > alloclen)
- {
- alloclen = newlen;
- filename = (char *) alloca (alloclen);
- }
- strcpy (filename, tilde_expanded.get ());
- }
- else
- {
- /* Normal file name in path -- just use it. */
- strcpy (filename, dir);
- /* Don't search $cdir. It's also a magic path like $cwd, but we
- don't have enough information to expand it. The user *could*
- have an actual directory named '$cdir' but handling that would
- be confusing, it would mean different things in different
- contexts. If the user really has '$cdir' one can use './$cdir'.
- We can get $cdir when loading scripts. When loading source files
- $cdir must have already been expanded to the correct value. */
- if (strcmp (dir, "$cdir") == 0)
- continue;
- }
- /* Remove trailing slashes. */
- while (len > 0 && IS_DIR_SEPARATOR (filename[len - 1]))
- filename[--len] = 0;
- strcat (filename + len, SLASH_STRING);
- strcat (filename, string);
- if (is_regular_file (filename, ®_file_errno))
- {
- fd = gdb_open_cloexec (filename, mode, 0).release ();
- if (fd >= 0)
- break;
- last_errno = errno;
- }
- else
- last_errno = reg_file_errno;
- }
- done:
- if (filename_opened)
- {
- /* If a file was opened, canonicalize its filename. */
- if (fd < 0)
- filename_opened->reset (NULL);
- else if ((opts & OPF_RETURN_REALPATH) != 0)
- *filename_opened = gdb_realpath (filename);
- else
- *filename_opened = gdb_abspath (filename);
- }
- errno = last_errno;
- return fd;
- }
- /* This is essentially a convenience, for clients that want the behaviour
- of openp, using source_path, but that really don't want the file to be
- opened but want instead just to know what the full pathname is (as
- qualified against source_path).
- The current working directory is searched first.
- If the file was found, this function returns 1, and FULL_PATHNAME is
- set to the fully-qualified pathname.
- Else, this functions returns 0, and FULL_PATHNAME is set to NULL. */
- int
- source_full_path_of (const char *filename,
- gdb::unique_xmalloc_ptr<char> *full_pathname)
- {
- int fd;
- fd = openp (source_path.c_str (),
- OPF_TRY_CWD_FIRST | OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH,
- filename, O_RDONLY, full_pathname);
- if (fd < 0)
- {
- full_pathname->reset (NULL);
- return 0;
- }
- close (fd);
- return 1;
- }
- /* Return non-zero if RULE matches PATH, that is if the rule can be
- applied to PATH. */
- static int
- substitute_path_rule_matches (const struct substitute_path_rule *rule,
- const char *path)
- {
- const int from_len = rule->from.length ();
- const int path_len = strlen (path);
- if (path_len < from_len)
- return 0;
- /* The substitution rules are anchored at the start of the path,
- so the path should start with rule->from. */
- if (filename_ncmp (path, rule->from.c_str (), from_len) != 0)
- return 0;
- /* Make sure that the region in the path that matches the substitution
- rule is immediately followed by a directory separator (or the end of
- string character). */
- if (path[from_len] != '\0' && !IS_DIR_SEPARATOR (path[from_len]))
- return 0;
- return 1;
- }
- /* Find the substitute-path rule that applies to PATH and return it.
- Return NULL if no rule applies. */
- static struct substitute_path_rule *
- get_substitute_path_rule (const char *path)
- {
- for (substitute_path_rule &rule : substitute_path_rules)
- if (substitute_path_rule_matches (&rule, path))
- return &rule;
- return nullptr;
- }
- /* If the user specified a source path substitution rule that applies
- to PATH, then apply it and return the new path.
- Return NULL if no substitution rule was specified by the user,
- or if no rule applied to the given PATH. */
- gdb::unique_xmalloc_ptr<char>
- rewrite_source_path (const char *path)
- {
- const struct substitute_path_rule *rule = get_substitute_path_rule (path);
- if (rule == nullptr)
- return nullptr;
- /* Compute the rewritten path and return it. */
- return (gdb::unique_xmalloc_ptr<char>
- (concat (rule->to.c_str (), path + rule->from.length (), nullptr)));
- }
- /* See source.h. */
- scoped_fd
- find_and_open_source (const char *filename,
- const char *dirname,
- gdb::unique_xmalloc_ptr<char> *fullname)
- {
- const char *path = source_path.c_str ();
- std::string expanded_path_holder;
- const char *p;
- /* If reading of source files is disabled then return a result indicating
- the attempt to read this source file failed. GDB will then display
- the filename and line number instead. */
- if (!source_open)
- return scoped_fd (-1);
- /* Quick way out if we already know its full name. */
- if (*fullname)
- {
- /* The user may have requested that source paths be rewritten
- according to substitution rules he provided. If a substitution
- rule applies to this path, then apply it. */
- gdb::unique_xmalloc_ptr<char> rewritten_fullname
- = rewrite_source_path (fullname->get ());
- if (rewritten_fullname != NULL)
- *fullname = std::move (rewritten_fullname);
- scoped_fd result = gdb_open_cloexec (fullname->get (), OPEN_MODE, 0);
- if (result.get () >= 0)
- {
- *fullname = gdb_realpath (fullname->get ());
- return result;
- }
- /* Didn't work -- free old one, try again. */
- fullname->reset (NULL);
- }
- gdb::unique_xmalloc_ptr<char> rewritten_dirname;
- if (dirname != NULL)
- {
- /* If necessary, rewrite the compilation directory name according
- to the source path substitution rules specified by the user. */
- rewritten_dirname = rewrite_source_path (dirname);
- if (rewritten_dirname != NULL)
- dirname = rewritten_dirname.get ();
- /* Replace a path entry of $cdir with the compilation directory
- name. */
- #define cdir_len 5
- p = strstr (source_path.c_str (), "$cdir");
- if (p && (p == path || p[-1] == DIRNAME_SEPARATOR)
- && (p[cdir_len] == DIRNAME_SEPARATOR || p[cdir_len] == '\0'))
- {
- int len = p - source_path.c_str ();
- /* Before $cdir */
- expanded_path_holder = source_path.substr (0, len);
- /* new stuff */
- expanded_path_holder += dirname;
- /* After $cdir */
- expanded_path_holder += source_path.c_str () + len + cdir_len;
- path = expanded_path_holder.c_str ();
- }
- }
- gdb::unique_xmalloc_ptr<char> rewritten_filename
- = rewrite_source_path (filename);
- if (rewritten_filename != NULL)
- filename = rewritten_filename.get ();
- /* Try to locate file using filename. */
- int result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, filename,
- OPEN_MODE, fullname);
- if (result < 0 && dirname != NULL)
- {
- /* Remove characters from the start of PATH that we don't need when
- PATH is appended to a directory name. */
- const char *filename_start = prepare_path_for_appending (filename);
- /* Try to locate file using compilation dir + filename. This is
- helpful if part of the compilation directory was removed,
- e.g. using gcc's -fdebug-prefix-map, and we have added the missing
- prefix to source_path. */
- std::string cdir_filename (dirname);
- /* Remove any trailing directory separators. */
- while (IS_DIR_SEPARATOR (cdir_filename.back ()))
- cdir_filename.pop_back ();
- /* Add our own directory separator. */
- cdir_filename.append (SLASH_STRING);
- cdir_filename.append (filename_start);
- result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH,
- cdir_filename.c_str (), OPEN_MODE, fullname);
- }
- if (result < 0)
- {
- /* Didn't work. Try using just the basename. */
- p = lbasename (filename);
- if (p != filename)
- result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, p,
- OPEN_MODE, fullname);
- }
- return scoped_fd (result);
- }
- /* Open a source file given a symtab S. Returns a file descriptor or
- negative number for error.
-
- This function is a convenience function to find_and_open_source. */
- scoped_fd
- open_source_file (struct symtab *s)
- {
- if (!s)
- return scoped_fd (-1);
- gdb::unique_xmalloc_ptr<char> fullname (s->fullname);
- s->fullname = NULL;
- scoped_fd fd = find_and_open_source (s->filename, s->compunit ()->dirname (),
- &fullname);
- if (fd.get () < 0)
- {
- if (s->compunit () != nullptr)
- {
- const objfile *ofp = s->compunit ()->objfile ();
- std::string srcpath;
- if (IS_ABSOLUTE_PATH (s->filename))
- srcpath = s->filename;
- else if (s->compunit ()->dirname () != nullptr)
- {
- srcpath = s->compunit ()->dirname ();
- srcpath += SLASH_STRING;
- srcpath += s->filename;
- }
- const struct bfd_build_id *build_id = build_id_bfd_get (ofp->obfd);
- /* Query debuginfod for the source file. */
- if (build_id != nullptr && !srcpath.empty ())
- fd = debuginfod_source_query (build_id->data,
- build_id->size,
- srcpath.c_str (),
- &fullname);
- }
- }
- s->fullname = fullname.release ();
- return fd;
- }
- /* See source.h. */
- gdb::unique_xmalloc_ptr<char>
- find_source_or_rewrite (const char *filename, const char *dirname)
- {
- gdb::unique_xmalloc_ptr<char> fullname;
- scoped_fd fd = find_and_open_source (filename, dirname, &fullname);
- if (fd.get () < 0)
- {
- /* rewrite_source_path would be applied by find_and_open_source, we
- should report the pathname where GDB tried to find the file. */
- if (dirname == nullptr || IS_ABSOLUTE_PATH (filename))
- fullname.reset (xstrdup (filename));
- else
- fullname.reset (concat (dirname, SLASH_STRING,
- filename, (char *) nullptr));
- gdb::unique_xmalloc_ptr<char> rewritten
- = rewrite_source_path (fullname.get ());
- if (rewritten != nullptr)
- fullname = std::move (rewritten);
- }
- return fullname;
- }
- /* Finds the fullname that a symtab represents.
- This functions finds the fullname and saves it in s->fullname.
- It will also return the value.
- If this function fails to find the file that this symtab represents,
- the expected fullname is used. Therefore the files does not have to
- exist. */
- const char *
- symtab_to_fullname (struct symtab *s)
- {
- /* Use cached copy if we have it.
- We rely on forget_cached_source_info being called appropriately
- to handle cases like the file being moved. */
- if (s->fullname == NULL)
- {
- scoped_fd fd = open_source_file (s);
- if (fd.get () < 0)
- {
- gdb::unique_xmalloc_ptr<char> fullname;
- /* rewrite_source_path would be applied by find_and_open_source, we
- should report the pathname where GDB tried to find the file. */
- if (s->compunit ()->dirname () == nullptr
- || IS_ABSOLUTE_PATH (s->filename))
- fullname.reset (xstrdup (s->filename));
- else
- fullname.reset (concat (s->compunit ()->dirname (), SLASH_STRING,
- s->filename, (char *) NULL));
- s->fullname = rewrite_source_path (fullname.get ()).release ();
- if (s->fullname == NULL)
- s->fullname = fullname.release ();
- }
- }
- return s->fullname;
- }
- /* See commentary in source.h. */
- const char *
- symtab_to_filename_for_display (struct symtab *symtab)
- {
- if (filename_display_string == filename_display_basename)
- return lbasename (symtab->filename);
- else if (filename_display_string == filename_display_absolute)
- return symtab_to_fullname (symtab);
- else if (filename_display_string == filename_display_relative)
- return symtab->filename;
- else
- internal_error (__FILE__, __LINE__, _("invalid filename_display_string"));
- }
- /* Print source lines from the file of symtab S,
- starting with line number LINE and stopping before line number STOPLINE. */
- static void
- print_source_lines_base (struct symtab *s, int line, int stopline,
- print_source_lines_flags flags)
- {
- bool noprint = false;
- int nlines = stopline - line;
- struct ui_out *uiout = current_uiout;
- /* Regardless of whether we can open the file, set current_source_symtab. */
- current_source_location *loc
- = get_source_location (current_program_space);
- loc->set (s, line);
- first_line_listed = line;
- last_line_listed = line;
- /* If printing of source lines is disabled, just print file and line
- number. */
- if (uiout->test_flags (ui_source_list) && source_open)
- {
- /* Only prints "No such file or directory" once. */
- if (s == last_source_visited)
- {
- if (last_source_error)
- {
- flags |= PRINT_SOURCE_LINES_NOERROR;
- noprint = true;
- }
- }
- else
- {
- last_source_visited = s;
- scoped_fd desc = open_source_file (s);
- last_source_error = desc.get () < 0;
- if (last_source_error)
- noprint = true;
- }
- }
- else
- {
- flags |= PRINT_SOURCE_LINES_NOERROR;
- noprint = true;
- }
- if (noprint)
- {
- if (!(flags & PRINT_SOURCE_LINES_NOERROR))
- {
- const char *filename = symtab_to_filename_for_display (s);
- int len = strlen (filename) + 100;
- char *name = (char *) alloca (len);
- xsnprintf (name, len, "%d\t%s", line, filename);
- print_sys_errmsg (name, errno);
- }
- else
- {
- uiout->field_signed ("line", line);
- uiout->text ("\tin ");
- /* CLI expects only the "file" field. TUI expects only the
- "fullname" field (and TUI does break if "file" is printed).
- MI expects both fields. ui_source_list is set only for CLI,
- not for TUI. */
- if (uiout->is_mi_like_p () || uiout->test_flags (ui_source_list))
- uiout->field_string ("file", symtab_to_filename_for_display (s),
- file_name_style.style ());
- if (uiout->is_mi_like_p () || !uiout->test_flags (ui_source_list))
- {
- const char *s_fullname = symtab_to_fullname (s);
- char *local_fullname;
- /* ui_out_field_string may free S_FULLNAME by calling
- open_source_file for it again. See e.g.,
- tui_field_string->tui_show_source. */
- local_fullname = (char *) alloca (strlen (s_fullname) + 1);
- strcpy (local_fullname, s_fullname);
- uiout->field_string ("fullname", local_fullname);
- }
- uiout->text ("\n");
- }
- return;
- }
- /* If the user requested a sequence of lines that seems to go backward
- (from high to low line numbers) then we don't print anything. */
- if (stopline <= line)
- return;
- std::string lines;
- if (!g_source_cache.get_source_lines (s, line, stopline - 1, &lines))
- {
- const std::vector<off_t> *offsets = nullptr;
- g_source_cache.get_line_charpos (s, &offsets);
- error (_("Line number %d out of range; %s has %d lines."),
- line, symtab_to_filename_for_display (s),
- offsets == nullptr ? 0 : (int) offsets->size ());
- }
- const char *iter = lines.c_str ();
- int new_lineno = loc->line ();
- while (nlines-- > 0 && *iter != '\0')
- {
- char buf[20];
- last_line_listed = loc->line ();
- if (flags & PRINT_SOURCE_LINES_FILENAME)
- {
- uiout->text (symtab_to_filename_for_display (s));
- uiout->text (":");
- }
- xsnprintf (buf, sizeof (buf), "%d\t", new_lineno++);
- uiout->text (buf);
- while (*iter != '\0')
- {
- /* Find a run of characters that can be emitted at once.
- This is done so that escape sequences are kept
- together. */
- const char *start = iter;
- while (true)
- {
- int skip_bytes;
- char c = *iter;
- if (c == '\033' && skip_ansi_escape (iter, &skip_bytes))
- iter += skip_bytes;
- else if (c >= 0 && c < 040 && c != '\t')
- break;
- else if (c == 0177)
- break;
- else
- ++iter;
- }
- if (iter > start)
- {
- std::string text (start, iter);
- uiout->text (text);
- }
- if (*iter == '\r')
- {
- /* Treat either \r or \r\n as a single newline. */
- ++iter;
- if (*iter == '\n')
- ++iter;
- break;
- }
- else if (*iter == '\n')
- {
- ++iter;
- break;
- }
- else if (*iter > 0 && *iter < 040)
- {
- xsnprintf (buf, sizeof (buf), "^%c", *iter + 0100);
- uiout->text (buf);
- ++iter;
- }
- else if (*iter == 0177)
- {
- uiout->text ("^?");
- ++iter;
- }
- }
- uiout->text ("\n");
- }
- loc->set (loc->symtab (), new_lineno);
- }
- /* See source.h. */
- void
- print_source_lines (struct symtab *s, int line, int stopline,
- print_source_lines_flags flags)
- {
- print_source_lines_base (s, line, stopline, flags);
- }
- /* See source.h. */
- void
- print_source_lines (struct symtab *s, source_lines_range line_range,
- print_source_lines_flags flags)
- {
- print_source_lines_base (s, line_range.startline (),
- line_range.stopline (), flags);
- }
- /* Print info on range of pc's in a specified line. */
- static void
- info_line_command (const char *arg, int from_tty)
- {
- CORE_ADDR start_pc, end_pc;
- std::vector<symtab_and_line> decoded_sals;
- symtab_and_line curr_sal;
- gdb::array_view<symtab_and_line> sals;
- if (arg == 0)
- {
- current_source_location *loc
- = get_source_location (current_program_space);
- curr_sal.symtab = loc->symtab ();
- curr_sal.pspace = current_program_space;
- if (last_line_listed != 0)
- curr_sal.line = last_line_listed;
- else
- curr_sal.line = loc->line ();
- sals = curr_sal;
- }
- else
- {
- decoded_sals = decode_line_with_last_displayed (arg,
- DECODE_LINE_LIST_MODE);
- sals = decoded_sals;
- dont_repeat ();
- }
- /* C++ More than one line may have been specified, as when the user
- specifies an overloaded function name. Print info on them all. */
- for (const auto &sal : sals)
- {
- if (sal.pspace != current_program_space)
- continue;
- if (sal.symtab == 0)
- {
- struct gdbarch *gdbarch = get_current_arch ();
- gdb_printf (_("No line number information available"));
- if (sal.pc != 0)
- {
- /* This is useful for "info line *0x7f34". If we can't tell the
- user about a source line, at least let them have the symbolic
- address. */
- gdb_printf (" for address ");
- gdb_stdout->wrap_here (2);
- print_address (gdbarch, sal.pc, gdb_stdout);
- }
- else
- gdb_printf (".");
- gdb_printf ("\n");
- }
- else if (sal.line > 0
- && find_line_pc_range (sal, &start_pc, &end_pc))
- {
- gdbarch *gdbarch = sal.symtab->compunit ()->objfile ()->arch ();
- if (start_pc == end_pc)
- {
- gdb_printf ("Line %d of \"%s\"",
- sal.line,
- symtab_to_filename_for_display (sal.symtab));
- gdb_stdout->wrap_here (2);
- gdb_printf (" is at address ");
- print_address (gdbarch, start_pc, gdb_stdout);
- gdb_stdout->wrap_here (2);
- gdb_printf (" but contains no code.\n");
- }
- else
- {
- gdb_printf ("Line %d of \"%s\"",
- sal.line,
- symtab_to_filename_for_display (sal.symtab));
- gdb_stdout->wrap_here (2);
- gdb_printf (" starts at address ");
- print_address (gdbarch, start_pc, gdb_stdout);
- gdb_stdout->wrap_here (2);
- gdb_printf (" and ends at ");
- print_address (gdbarch, end_pc, gdb_stdout);
- gdb_printf (".\n");
- }
- /* x/i should display this line's code. */
- set_next_address (gdbarch, start_pc);
- /* Repeating "info line" should do the following line. */
- last_line_listed = sal.line + 1;
- /* If this is the only line, show the source code. If it could
- not find the file, don't do anything special. */
- if (annotation_level > 0 && sals.size () == 1)
- annotate_source_line (sal.symtab, sal.line, 0, start_pc);
- }
- else
- /* Is there any case in which we get here, and have an address
- which the user would want to see? If we have debugging symbols
- and no line numbers? */
- gdb_printf (_("Line number %d is out of range for \"%s\".\n"),
- sal.line, symtab_to_filename_for_display (sal.symtab));
- }
- }
- /* Commands to search the source file for a regexp. */
- /* Helper for forward_search_command/reverse_search_command. FORWARD
- indicates direction: true for forward, false for
- backward/reverse. */
- static void
- search_command_helper (const char *regex, int from_tty, bool forward)
- {
- const char *msg = re_comp (regex);
- if (msg)
- error (("%s"), msg);
- current_source_location *loc
- = get_source_location (current_program_space);
- if (loc->symtab () == nullptr)
- select_source_symtab (0);
- if (!source_open)
- error (_("source code access disabled"));
- scoped_fd desc (open_source_file (loc->symtab ()));
- if (desc.get () < 0)
- perror_with_name (symtab_to_filename_for_display (loc->symtab ()));
- int line = (forward
- ? last_line_listed + 1
- : last_line_listed - 1);
- const std::vector<off_t> *offsets;
- if (line < 1
- || !g_source_cache.get_line_charpos (loc->symtab (), &offsets)
- || line > offsets->size ())
- error (_("Expression not found"));
- if (lseek (desc.get (), (*offsets)[line - 1], 0) < 0)
- perror_with_name (symtab_to_filename_for_display (loc->symtab ()));
- gdb_file_up stream = desc.to_file (FDOPEN_MODE);
- clearerr (stream.get ());
- gdb::def_vector<char> buf;
- buf.reserve (256);
- while (1)
- {
- buf.resize (0);
- int c = fgetc (stream.get ());
- if (c == EOF)
- break;
- do
- {
- buf.push_back (c);
- }
- while (c != '\n' && (c = fgetc (stream.get ())) >= 0);
- /* Remove the \r, if any, at the end of the line, otherwise
- regular expressions that end with $ or \n won't work. */
- size_t sz = buf.size ();
- if (sz >= 2 && buf[sz - 2] == '\r')
- {
- buf[sz - 2] = '\n';
- buf.resize (sz - 1);
- }
- /* We now have a source line in buf, null terminate and match. */
- buf.push_back ('\0');
- if (re_exec (buf.data ()) > 0)
- {
- /* Match! */
- print_source_lines (loc->symtab (), line, line + 1, 0);
- set_internalvar_integer (lookup_internalvar ("_"), line);
- loc->set (loc->symtab (), std::max (line - lines_to_list / 2, 1));
- return;
- }
- if (forward)
- line++;
- else
- {
- line--;
- if (line < 1)
- break;
- if (fseek (stream.get (), (*offsets)[line - 1], 0) < 0)
- {
- const char *filename
- = symtab_to_filename_for_display (loc->symtab ());
- perror_with_name (filename);
- }
- }
- }
- gdb_printf (_("Expression not found\n"));
- }
- static void
- forward_search_command (const char *regex, int from_tty)
- {
- search_command_helper (regex, from_tty, true);
- }
- static void
- reverse_search_command (const char *regex, int from_tty)
- {
- search_command_helper (regex, from_tty, false);
- }
- /* If the last character of PATH is a directory separator, then strip it. */
- static void
- strip_trailing_directory_separator (char *path)
- {
- const int last = strlen (path) - 1;
- if (last < 0)
- return; /* No stripping is needed if PATH is the empty string. */
- if (IS_DIR_SEPARATOR (path[last]))
- path[last] = '\0';
- }
- /* Add a new substitute-path rule at the end of the current list of rules.
- The new rule will replace FROM into TO. */
- void
- add_substitute_path_rule (const char *from, const char *to)
- {
- substitute_path_rules.emplace_back (from, to);
- }
- /* Implement the "show substitute-path" command. */
- static void
- show_substitute_path_command (const char *args, int from_tty)
- {
- char *from = NULL;
-
- gdb_argv argv (args);
- /* We expect zero or one argument. */
- if (argv != NULL && argv[0] != NULL && argv[1] != NULL)
- error (_("Too many arguments in command"));
- if (argv != NULL && argv[0] != NULL)
- from = argv[0];
- /* Print the substitution rules. */
- if (from != NULL)
- gdb_printf
- (_("Source path substitution rule matching `%s':\n"), from);
- else
- gdb_printf (_("List of all source path substitution rules:\n"));
- for (substitute_path_rule &rule : substitute_path_rules)
- {
- if (from == NULL || substitute_path_rule_matches (&rule, from) != 0)
- gdb_printf (" `%s' -> `%s'.\n", rule.from.c_str (),
- rule.to.c_str ());
- }
- }
- /* Implement the "unset substitute-path" command. */
- static void
- unset_substitute_path_command (const char *args, int from_tty)
- {
- gdb_argv argv (args);
- char *from = NULL;
- /* This function takes either 0 or 1 argument. */
- if (argv != NULL && argv[0] != NULL && argv[1] != NULL)
- error (_("Incorrect usage, too many arguments in command"));
- if (argv != NULL && argv[0] != NULL)
- from = argv[0];
- /* If the user asked for all the rules to be deleted, ask him
- to confirm and give him a chance to abort before the action
- is performed. */
- if (from == NULL
- && !query (_("Delete all source path substitution rules? ")))
- error (_("Canceled"));
- /* Delete the rule matching the argument. No argument means that
- all rules should be deleted. */
- if (from == nullptr)
- substitute_path_rules.clear ();
- else
- {
- auto iter
- = std::remove_if (substitute_path_rules.begin (),
- substitute_path_rules.end (),
- [&] (const substitute_path_rule &rule)
- {
- return FILENAME_CMP (from,
- rule.from.c_str ()) == 0;
- });
- bool rule_found = iter != substitute_path_rules.end ();
- substitute_path_rules.erase (iter, substitute_path_rules.end ());
- /* If the user asked for a specific rule to be deleted but
- we could not find it, then report an error. */
- if (!rule_found)
- error (_("No substitution rule defined for `%s'"), from);
- }
- forget_cached_source_info ();
- }
- /* Add a new source path substitution rule. */
- static void
- set_substitute_path_command (const char *args, int from_tty)
- {
- gdb_argv argv (args);
- if (argv == NULL || argv[0] == NULL || argv [1] == NULL)
- error (_("Incorrect usage, too few arguments in command"));
- if (argv[2] != NULL)
- error (_("Incorrect usage, too many arguments in command"));
- if (*(argv[0]) == '\0')
- error (_("First argument must be at least one character long"));
- /* Strip any trailing directory separator character in either FROM
- or TO. The substitution rule already implicitly contains them. */
- strip_trailing_directory_separator (argv[0]);
- strip_trailing_directory_separator (argv[1]);
- /* If a rule with the same "from" was previously defined, then
- delete it. This new rule replaces it. */
- auto iter
- = std::remove_if (substitute_path_rules.begin (),
- substitute_path_rules.end (),
- [&] (const substitute_path_rule &rule)
- {
- return FILENAME_CMP (argv[0], rule.from.c_str ()) == 0;
- });
- substitute_path_rules.erase (iter, substitute_path_rules.end ());
- /* Insert the new substitution rule. */
- add_substitute_path_rule (argv[0], argv[1]);
- forget_cached_source_info ();
- }
- /* See source.h. */
- source_lines_range::source_lines_range (int startline,
- source_lines_range::direction dir)
- {
- if (dir == source_lines_range::FORWARD)
- {
- LONGEST end = static_cast <LONGEST> (startline) + get_lines_to_list ();
- if (end > INT_MAX)
- end = INT_MAX;
- m_startline = startline;
- m_stopline = static_cast <int> (end);
- }
- else
- {
- LONGEST start = static_cast <LONGEST> (startline) - get_lines_to_list ();
- if (start < 1)
- start = 1;
- m_startline = static_cast <int> (start);
- m_stopline = startline;
- }
- }
- /* Handle the "set source" base command. */
- static void
- set_source (const char *arg, int from_tty)
- {
- help_list (setsourcelist, "set source ", all_commands, gdb_stdout);
- }
- /* Handle the "show source" base command. */
- static void
- show_source (const char *args, int from_tty)
- {
- help_list (showsourcelist, "show source ", all_commands, gdb_stdout);
- }
- void _initialize_source ();
- void
- _initialize_source ()
- {
- init_source_path ();
- /* The intention is to use POSIX Basic Regular Expressions.
- Always use the GNU regex routine for consistency across all hosts.
- Our current GNU regex.c does not have all the POSIX features, so this is
- just an approximation. */
- re_set_syntax (RE_SYNTAX_GREP);
- cmd_list_element *directory_cmd
- = add_cmd ("directory", class_files, directory_command, _("\
- Add directory DIR to beginning of search path for source files.\n\
- Forget cached info on source file locations and line positions.\n\
- DIR can also be $cwd for the current working directory, or $cdir for the\n\
- directory in which the source file was compiled into object code.\n\
- With no argument, reset the search path to $cdir:$cwd, the default."),
- &cmdlist);
- set_cmd_completer (directory_cmd, filename_completer);
- add_setshow_optional_filename_cmd ("directories",
- class_files,
- &source_path,
- _("\
- Set the search path for finding source files."),
- _("\
- Show the search path for finding source files."),
- _("\
- $cwd in the path means the current working directory.\n\
- $cdir in the path means the compilation directory of the source file.\n\
- GDB ensures the search path always ends with $cdir:$cwd by\n\
- appending these directories if necessary.\n\
- Setting the value to an empty string sets it to $cdir:$cwd, the default."),
- set_directories_command,
- show_directories_command,
- &setlist, &showlist);
- add_info ("source", info_source_command,
- _("Information about the current source file."));
- add_info ("line", info_line_command, _("\
- Core addresses of the code for a source line.\n\
- Line can be specified as\n\
- LINENUM, to list around that line in current file,\n\
- FILE:LINENUM, to list around that line in that file,\n\
- FUNCTION, to list around beginning of that function,\n\
- FILE:FUNCTION, to distinguish among like-named static functions.\n\
- Default is to describe the last source line that was listed.\n\n\
- This sets the default address for \"x\" to the line's first instruction\n\
- so that \"x/i\" suffices to start examining the machine code.\n\
- The address is also stored as the value of \"$_\"."));
- cmd_list_element *forward_search_cmd
- = add_com ("forward-search", class_files, forward_search_command, _("\
- Search for regular expression (see regex(3)) from last line listed.\n\
- The matching line number is also stored as the value of \"$_\"."));
- add_com_alias ("search", forward_search_cmd, class_files, 0);
- add_com_alias ("fo", forward_search_cmd, class_files, 1);
- cmd_list_element *reverse_search_cmd
- = add_com ("reverse-search", class_files, reverse_search_command, _("\
- Search backward for regular expression (see regex(3)) from last line listed.\n\
- The matching line number is also stored as the value of \"$_\"."));
- add_com_alias ("rev", reverse_search_cmd, class_files, 1);
- add_setshow_integer_cmd ("listsize", class_support, &lines_to_list, _("\
- Set number of source lines gdb will list by default."), _("\
- Show number of source lines gdb will list by default."), _("\
- Use this to choose how many source lines the \"list\" displays (unless\n\
- the \"list\" argument explicitly specifies some other number).\n\
- A value of \"unlimited\", or zero, means there's no limit."),
- NULL,
- show_lines_to_list,
- &setlist, &showlist);
- add_cmd ("substitute-path", class_files, set_substitute_path_command,
- _("\
- Add a substitution rule to rewrite the source directories.\n\
- Usage: set substitute-path FROM TO\n\
- The rule is applied only if the directory name starts with FROM\n\
- directly followed by a directory separator.\n\
- If a substitution rule was previously set for FROM, the old rule\n\
- is replaced by the new one."),
- &setlist);
- add_cmd ("substitute-path", class_files, unset_substitute_path_command,
- _("\
- Delete one or all substitution rules rewriting the source directories.\n\
- Usage: unset substitute-path [FROM]\n\
- Delete the rule for substituting FROM in source directories. If FROM\n\
- is not specified, all substituting rules are deleted.\n\
- If the debugger cannot find a rule for FROM, it will display a warning."),
- &unsetlist);
- add_cmd ("substitute-path", class_files, show_substitute_path_command,
- _("\
- Show one or all substitution rules rewriting the source directories.\n\
- Usage: show substitute-path [FROM]\n\
- Print the rule for substituting FROM in source directories. If FROM\n\
- is not specified, print all substitution rules."),
- &showlist);
- add_setshow_enum_cmd ("filename-display", class_files,
- filename_display_kind_names,
- &filename_display_string, _("\
- Set how to display filenames."), _("\
- Show how to display filenames."), _("\
- filename-display can be:\n\
- basename - display only basename of a filename\n\
- relative - display a filename relative to the compilation directory\n\
- absolute - display an absolute filename\n\
- By default, relative filenames are displayed."),
- NULL,
- show_filename_display_string,
- &setlist, &showlist);
- add_prefix_cmd ("source", no_class, set_source,
- _("Generic command for setting how sources are handled."),
- &setsourcelist, 0, &setlist);
- add_prefix_cmd ("source", no_class, show_source,
- _("Generic command for showing source settings."),
- &showsourcelist, 0, &showlist);
- add_setshow_boolean_cmd ("open", class_files, &source_open, _("\
- Set whether GDB should open source files."), _("\
- Show whether GDB should open source files."), _("\
- When this option is on GDB will open source files and display the\n\
- contents when appropriate, for example, when GDB stops, or the list\n\
- command is used.\n\
- When this option is off GDB will not try to open source files, instead\n\
- GDB will print the file and line number that would have been displayed.\n\
- This can be useful if access to source code files is slow, for example\n\
- due to the source being located over a slow network connection."),
- NULL,
- show_source_open,
- &setsourcelist, &showsourcelist);
- }
|