From: Andrew Burgess Date: Sat, 15 Nov 2025 14:55:19 +0000 (+0000) Subject: gdb: shortcut 'list LINENO' X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c1859f4b6863655c84646816f0885d316d35871b;p=thirdparty%2Fbinutils-gdb.git gdb: shortcut 'list LINENO' While working on a test for a weird interaction between the DWARF parser, debuginfod, and the 'list' command, I noticed that performing 'list LINENO' can incur a significant amount of work trying to figure out which symtab the source should be listed from. This seems a little weird as a plain 'list' just uses the default symtab with no searching through all of the symtabs. The symtab lookup is all hidden behind the decode_line_1 call, which is made from list_command (cli/cli-cmds.c). The thing is, in list_command we already have code which (basically) checks if the argument to 'list' is a line number, here's the code: for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++); linenum_beg = (p == arg1); And we already have code within list_command which depends on the default symtab, look at how 'list .', 'list +', and 'list -' are handled. I think that 'list LINENO' is such a common use case that is makes sense to optimise this case in order to avoid the need to perform symtab lookup. I think this can be achieved without any significant changes to the list_command function; we'll just move the existing line number check (see above code) a little earlier in the function and change it to a strtol call so that the actual line number is recorded. Then there's a little error checking, before finally we can skip straight to listing the source code using the default symtab. For anything other than 'list LINENO' we will handle the command just as we've always done. I think there's actually scope for list_command to handle more cases internally, without calling out to decode_line_1, but I thought I'd see how happy people were with this smaller change first before I tried anything larger. There should be no user visible changes after this commit, other than 'list LINENO' might be a little faster. Reviewed-By: Keith Seitz --- diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 8b8f928e1a2..32bcf962e4c 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -1356,12 +1356,49 @@ list_command (const char *arg, int from_tty) std::vector sals; symtab_and_line sal, sal_end; bool dummy_beg = false; + bool linenum_beg = false; - const char *arg1 = arg; + const char *arg1 = skip_spaces (arg); if (*arg1 == ',') dummy_beg = true; else { + /* Are we looking at a number? */ + char *end_ptr; + long int lineno = strtol (arg1, &end_ptr, 10); + + /* If END_PTR is different to ARG1 then strtol parsed something, but + strtol will accept numbers with a '+' or '-' prefix, which we + don't want to handle here, hence the c_isdigit check. */ + if (end_ptr != arg1 && c_isdigit (*arg1)) + { + /* Some digits were found. */ + end_ptr = skip_spaces (end_ptr); + + /* Check for valid line format or for an invalid line number. */ + if (*end_ptr != '\0' && *end_ptr != ',') + error (_("Junk at end of line specification: %s"), end_ptr); + + if (*end_ptr == '\0') + { + /* Ensure LINENO isn't going to overflow when we convert it + to an integer below. */ + if (lineno >= INT_MAX || lineno <= INT_MIN) + error (_("Line number %.*s out of range"), + (int) (end_ptr - arg1), arg1); + + /* We only have a line number. */ + set_default_source_symtab_and_line (); + symtab_and_line cursal + = get_current_source_symtab_and_line (current_program_space); + cursal.line = static_cast (lineno); + list_around_line (nullptr, cursal); + return; + } + + linenum_beg = true; + } + location_spec_up locspec = string_to_location_spec (&arg1, current_language); @@ -1385,12 +1422,6 @@ list_command (const char *arg, int from_tty) sal = sals[0]; } - /* Record whether the BEG arg is all digits. */ - - const char *p; - for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++); - bool linenum_beg = (p == arg1); - /* Save the range of the first argument, in case we need to let the user know it was ambiguous. */ const char *beg = arg; @@ -1491,7 +1522,7 @@ list_command (const char *arg, int from_tty) imply a symtab, it must be an undebuggable symbol which means no source code. */ - if (!linenum_beg && sal.symtab == nullptr) + if (!dummy_beg && !linenum_beg && sal.symtab == nullptr) error (_("No line number known for %s."), arg); /* If this command is repeated with RET,