Annotation of gdb/source.c, revision 1.1.1.5

1.1       root        1: /* List lines of source files for GDB, the GNU debugger.
1.1.1.3   root        2:    Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
1.1       root        3: 
                      4: GDB is distributed in the hope that it will be useful, but WITHOUT ANY
                      5: WARRANTY.  No author or distributor accepts responsibility to anyone
                      6: for the consequences of using it or for whether it serves any
                      7: particular purpose or works at all, unless he says so in writing.
                      8: Refer to the GDB General Public License for full details.
                      9: 
                     10: Everyone is granted permission to copy, modify and redistribute GDB,
                     11: but only under the conditions described in the GDB General Public
                     12: License.  A copy of this license is supposed to have been given to you
                     13: along with GDB so you can know your rights and responsibilities.  It
                     14: should be in a file named COPYING.  Among other things, the copyright
                     15: notice and this notice must be preserved on all copies.
                     16: 
                     17: In other words, go ahead and share GDB, but don't try to stop
                     18: anyone else from sharing it farther.  Help stamp out software hoarding!
                     19: */
                     20: 
                     21: #include <stdio.h>
                     22: #include <sys/param.h>
                     23: #include <sys/stat.h>
                     24: #include <sys/file.h>
                     25: #include "defs.h"
                     26: #include "initialize.h"
                     27: #include "symtab.h"
                     28: 
                     29: /* Path of directories to search for source files.
                     30:    Same format as the PATH environment variable's value.  */
                     31: 
                     32: static char *source_path;
                     33: 
                     34: /* Symtab of default file for listing lines of.  */
                     35: 
                     36: struct symtab *current_source_symtab;
                     37: 
                     38: /* Default next line to list.  */
                     39: 
                     40: int current_source_line;
                     41: 
1.1.1.3   root       42: /* Line number of last line printed.  Default for various commands.
                     43:    current_source_line is usually, but not always, the same as this.  */
1.1       root       44: 
1.1.1.3   root       45: static int last_line_listed;
1.1       root       46: 
                     47: /* First line number listed by last listing command.  */
                     48: 
                     49: static int first_line_listed;
                     50: 
                     51: START_FILE
1.1.1.2   root       52: 
                     53: /* Set the source file default for the "list" command,
                     54:    specifying a symtab.  */
1.1       root       55: 
1.1.1.2   root       56: void
                     57: select_source_symtab (s)
                     58:      register struct symtab *s;
                     59: {
                     60:   if (s)
                     61:     {
1.1.1.5 ! root       62:       struct symtabs_and_lines sals;
1.1.1.2   root       63:       struct symtab_and_line sal;
                     64: 
                     65:       /* Make the default place to list be the function `main'
                     66:         if one exists.  */
                     67:       if (lookup_symbol ("main", 0, VAR_NAMESPACE))
                     68:        {
1.1.1.5 ! root       69:          sals = decode_line_spec ("main", 1);
        !            70:          sal = sals.sals[0];
        !            71:          free (sals.sals);
1.1.1.2   root       72:          current_source_symtab = sal.symtab;
                     73:          current_source_line = sal.line - 9;
                     74:          return;
                     75:        }
                     76: 
                     77:       /* If there is no `main', use the last symtab in the list,
                     78:         which is actually the first found in the file's symbol table.
                     79:         But ignore .h files.  */
                     80:       do
                     81:        {
                     82:          char *name = s->filename;
                     83:          int len = strlen (name);
                     84:          if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
                     85:            current_source_symtab = s;
                     86:          s = s->next;
                     87:        }
                     88:       while (s);
                     89:       current_source_line = 1;
                     90:     }
                     91: }
                     92: 
1.1       root       93: static void
                     94: directories_info ()
                     95: {
                     96:   printf ("Source directories searched: %s\n", source_path);
                     97: }
                     98: 
1.1.1.4   root       99: void
1.1       root      100: init_source_path ()
                    101: {
                    102:   register struct symtab *s;
                    103: 
1.1.1.4   root      104:   source_path = savestring (current_directory, strlen (current_directory));
1.1       root      105: 
                    106:   /* Forget what we learned about line positions in source files;
                    107:      must check again now since files may be found in
                    108:      a different directory now.  */
                    109:   for (s = symtab_list; s; s = s->next)
                    110:     if (s->line_charpos != 0)
                    111:       {
                    112:        free (s->line_charpos);
                    113:        s->line_charpos = 0;
                    114:       }
                    115: }
                    116: 
                    117: void
                    118: directory_command (dirname, from_tty)
                    119:      char *dirname;
                    120:      int from_tty;
                    121: {
                    122:   char *old = source_path;
                    123: 
                    124:   if (dirname == 0)
                    125:     {
1.1.1.4   root      126:       if (query ("Reinitialize source path to %s? ", current_directory))
1.1       root      127:        {
                    128:          init_source_path ();
                    129:          free (old);
                    130:        }
                    131:     }
                    132:   else
                    133:     {
                    134:       struct stat st;
                    135:       register int len = strlen (dirname);
                    136:       register char *tem;
                    137:       extern char *index ();
                    138: 
                    139:       if (index (dirname, ':'))
                    140:        error ("Please add one directory at a time to the source path.");
                    141:       if (dirname[len - 1] == '/')
                    142:          /* Sigh. "foo/" => "foo" */
                    143:          dirname[--len] == '\0';
                    144: 
                    145:       while (dirname[len - 1] == '.')
                    146:        {
                    147:          if (len == 1)
                    148:            {
                    149:              /* "." => getwd () */
1.1.1.4   root      150:              dirname = current_directory;
1.1       root      151:              goto append;
                    152:            }
                    153:          else if (dirname[len - 2] == '/')
                    154:            {
                    155:              if (len == 2)
                    156:                {
                    157:                  /* "/." => "/" */
                    158:                  dirname[--len] = '\0';
                    159:                  goto append;
                    160:                }
                    161:              else
                    162:                {
                    163:                  /* "...foo/." => "...foo" */
                    164:                  dirname[len -= 2] = '\0';
                    165:                  continue;
                    166:                }
                    167:            }
                    168:          break;
                    169:        }
                    170: 
                    171:       if (dirname[0] != '/')
1.1.1.4   root      172:        dirname = concat (current_directory, "/", dirname);
1.1       root      173:       else
                    174:        dirname = savestring (dirname, len);
1.1.1.2   root      175:       make_cleanup (free, dirname);
1.1       root      176: 
                    177:       if (stat (dirname, &st) < 0)
                    178:        perror_with_name (dirname);
                    179:       if ((st.st_mode & S_IFMT) != S_IFDIR)
                    180:        error ("%s is not a directory.", dirname);
                    181: 
                    182:     append:
                    183:       len = strlen (dirname);
                    184:       tem = source_path;
                    185:       while (1)
                    186:        {
                    187:          if (!strncmp (tem, dirname, len)
                    188:              && (tem[len] == '\0' || tem[len] == ':'))
                    189:            {
                    190:              printf ("\"%s\" is already in the source path.\n",
                    191:                      dirname);
                    192:              break;
                    193:            }
                    194:          tem = index (tem, ':');
                    195:          if (tem)
                    196:            tem++;
                    197:          else
                    198:            {
                    199:              source_path = concat (old, ":", dirname);
                    200:              free (old);
                    201:              break;
                    202:            }
                    203:        }
                    204:       if (from_tty)
                    205:        directories_info ();
                    206:     }
                    207: }
                    208: 
                    209: /* Open a file named STRING, searching path PATH (dir names sep by colons)
                    210:    using mode MODE and protection bits PROT in the calls to open.
                    211:    If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
                    212:    (ie pretend the first element of PATH is ".")
                    213:    If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
                    214:    the actual file opened (this string will always start with a "/"
                    215: 
                    216:    If a file is found, return the descriptor.
                    217:    Otherwise, return -1, with errno set for the last name we tried to open.  */
                    218: 
                    219: /*  >>>> This should only allow files of certain types,
                    220:     >>>>  eg executable, non-directory */
                    221: int
                    222: openp (path, try_cwd_first, string, mode, prot, filename_opened)
                    223:      char *path;
                    224:      int try_cwd_first;
                    225:      char *string;
                    226:      int mode;
                    227:      int prot;
                    228:      char **filename_opened;
                    229: {
                    230:   register int fd;
                    231:   register char *filename;
                    232:   register char *p, *p1;
                    233:   register int len;
                    234: 
                    235:   /* ./foo => foo */
                    236:   while (string[0] == '.' && string[1] == '/')
                    237:     string += 2;
                    238: 
                    239:   if (try_cwd_first || string[0] == '/')
                    240:     {
                    241:       filename = string;
                    242:       fd = open (filename, mode, prot);
                    243:       if (fd >= 0 || string[0] == '/')
                    244:        goto done;
                    245:     }
                    246: 
                    247:   filename = (char *) alloca (strlen (path) + strlen (string) + 2);
                    248:   fd = -1;
                    249:   for (p = path; p; p = p1 ? p1 + 1 : 0)
                    250:     {
                    251:       p1 = (char *) index (p, ':');
                    252:       if (p1)
                    253:        len = p1 - p;
                    254:       else
                    255:        len = strlen (p);
                    256: 
                    257:       strncpy (filename, p, len);
                    258:       filename[len] = 0;
                    259:       strcat (filename, "/");
                    260:       strcat (filename, string);
                    261: 
                    262:       fd = open (filename, mode, prot);
                    263:       if (fd >= 0) break;
                    264:     }
                    265: 
                    266:  done:
                    267:   if (filename_opened)
                    268:     if (fd < 0)
                    269:       *filename_opened = (char *) 0;
                    270:     else if (filename[0] == '/')
                    271:       *filename_opened = savestring (filename, strlen (filename));
                    272:     else
                    273:       {
1.1.1.3   root      274:        *filename_opened = concat (current_directory, "/", filename);
1.1       root      275:       }
                    276: 
                    277:   return fd;
                    278: }
                    279: 
1.1.1.2   root      280: /* Create and initialize the table S->line_charpos that records
                    281:    the positions of the lines in the source file, which is assumed
                    282:    to be open on descriptor DESC.
                    283:    All set S->nlines to the number of such lines.  */
                    284: 
1.1       root      285: static void
                    286: find_source_lines (s, desc)
                    287:      struct symtab *s;
                    288:      int desc;
                    289: {
                    290:   struct stat st;
                    291:   register char *data, *p, *end;
                    292:   int nlines = 0;
                    293:   int lines_allocated = 1000;
                    294:   int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
                    295:   extern int exec_mtime;
                    296: 
                    297:   fstat (desc, &st);
1.1.1.4   root      298:   if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
1.1       root      299:     printf ("Source file is more recent than executable.\n");
                    300: 
                    301:   data = (char *) alloca (st.st_size);
1.1.1.2   root      302:   myread (desc, data, st.st_size);
1.1       root      303:   end = data + st.st_size;
                    304:   p = data;
                    305:   line_charpos[0] = 0;
                    306:   nlines = 1;
                    307:   while (p != end)
                    308:     {
1.1.1.4   root      309:       if (*p++ == '\n'
                    310:          /* A newline at the end does not start a new line.  */
                    311:          && p != end)
1.1       root      312:        {
                    313:          if (nlines == lines_allocated)
1.1.1.4   root      314:            {
                    315:              lines_allocated *= 2;
                    316:              line_charpos = (int *) xrealloc (line_charpos,
                    317:                                               sizeof (int) * lines_allocated);
                    318:            }
1.1       root      319:          line_charpos[nlines++] = p - data;
                    320:        }
                    321:     }
                    322:   s->nlines = nlines;
                    323:   s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
                    324: }
1.1.1.2   root      325: 
                    326: /* Return the character position of a line LINE in symtab S.
                    327:    Return 0 if anything is invalid.  */
                    328: 
                    329: int
                    330: source_line_charpos (s, line)
                    331:      struct symtab *s;
                    332:      int line;
                    333: {
                    334:   if (!s) return 0;
                    335:   if (!s->line_charpos || line <= 0) return 0;
                    336:   if (line > s->nlines)
                    337:     line = s->nlines;
                    338:   return s->line_charpos[line - 1];
                    339: }
                    340: 
                    341: /* Return the line number of character position POS in symtab S.  */
                    342: 
                    343: int
                    344: source_charpos_line (s, chr)
                    345:     register struct symtab *s;
                    346:     register int chr;
                    347: {
                    348:   register int line = 0;
                    349:   register int *lnp;
                    350:     
                    351:   if (s == 0 || s->line_charpos == 0) return 0;
                    352:   lnp = s->line_charpos;
                    353:   /* Files are usually short, so sequential search is Ok */
                    354:   while (line < s->nlines  && *lnp <= chr)
                    355:     {
                    356:       line++;
                    357:       lnp++;
                    358:     }
                    359:   if (line >= s->nlines)
                    360:     line = s->nlines;
                    361:   return line;
                    362: }
                    363: 
                    364: /* Get full pathname and line number positions for a symtab.
                    365:    Return nonzero if line numbers may have changed.
                    366:    Set *FULLNAME to actual name of the file as found by `openp',
                    367:    or to 0 if the file is not found.  */
                    368: 
                    369: int
                    370: get_filename_and_charpos (s, line, fullname)
                    371:      struct symtab *s;
                    372:      int line;
                    373:      char **fullname;
                    374: {
                    375:   register int desc, linenums_changed = 0;
                    376:   
1.1.1.3   root      377:   desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
1.1.1.2   root      378:   if (desc < 0)
                    379:     {
1.1.1.3   root      380:       if (fullname)
                    381:        *fullname = NULL;
1.1.1.2   root      382:       return 0;
                    383:     }  
1.1.1.3   root      384:   if (fullname)
                    385:     *fullname = s->fullname;
1.1.1.2   root      386:   if (s->line_charpos == 0) linenums_changed = 1;
                    387:   if (linenums_changed) find_source_lines (s, desc);
                    388:   close (desc);
                    389:   return linenums_changed;
                    390: }
1.1.1.3   root      391: 
                    392: /* Print text describing the full name of the source file S
                    393:    and the line number LINE and its corresponding character position.
                    394:    The text starts with two Ctrl-z so that the Emacs-GDB interface
                    395:    can easily find it.
                    396: 
1.1.1.4   root      397:    MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
                    398: 
1.1.1.3   root      399:    Return 1 if successful, 0 if could not find the file.  */
                    400: 
                    401: int
1.1.1.4   root      402: identify_source_line (s, line, mid_statement)
1.1.1.3   root      403:      struct symtab *s;
                    404:      int line;
1.1.1.4   root      405:      int mid_statement;
1.1.1.3   root      406: {
                    407:   if (s->line_charpos == 0)
                    408:     get_filename_and_charpos (s, line, 0);
                    409:   if (s->fullname == 0)
                    410:     return 0;
1.1.1.4   root      411:   printf ("\032\032%s:%d:%d:%s\n", s->fullname,
                    412:          line, s->line_charpos[line - 1],
                    413:          mid_statement ? "middle" : "beg");
                    414:   current_source_line = line;
                    415:   first_line_listed = line;
                    416:   last_line_listed = line;
                    417:   current_source_symtab = s;
1.1.1.3   root      418:   return 1;
                    419: }
1.1       root      420: 
                    421: /* Print source lines from the file of symtab S,
                    422:    starting with line number LINE and stopping before line number STOPLINE.  */
                    423: 
                    424: void
1.1.1.4   root      425: print_source_lines (s, line, stopline, noerror)
1.1       root      426:      struct symtab *s;
                    427:      int line, stopline;
1.1.1.4   root      428:      int noerror;
1.1       root      429: {
                    430:   register int c;
                    431:   register int desc;
                    432:   register FILE *stream;
                    433:   int nlines = stopline - line;
                    434: 
1.1.1.3   root      435:   desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
1.1       root      436:   if (desc < 0)
1.1.1.4   root      437:     {
                    438:       extern int errno;
                    439:       if (! noerror)
                    440:        perror_with_name (s->filename);
                    441:       print_sys_errmsg (s->filename, errno);
                    442:       return;
                    443:     }
1.1       root      444: 
                    445:   if (s->line_charpos == 0)
                    446:     find_source_lines (s, desc);
                    447: 
1.1.1.4   root      448:   if (line < 1 || line > s->nlines)
1.1       root      449:     {
                    450:       close (desc);
                    451:       error ("Line number out of range; %s has %d lines.",
                    452:             s->filename, s->nlines);
                    453:     }
                    454: 
                    455:   if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
                    456:     {
                    457:       close (desc);
                    458:       perror_with_name (s->filename);
                    459:     }
                    460: 
                    461:   current_source_symtab = s;
                    462:   current_source_line = line;
                    463:   first_line_listed = line;
                    464:   
                    465:   stream = fdopen (desc, "r");
                    466:   clearerr (stream);
                    467: 
                    468:   while (nlines-- > 0)
                    469:     {
                    470:       c = fgetc (stream);
                    471:       if (c == EOF) break;
1.1.1.3   root      472:       last_line_listed = current_source_line;
1.1       root      473:       printf ("%d\t", current_source_line++);
                    474:       do
                    475:        {
                    476:          if (c < 040 && c != '\t' && c != '\n')
                    477:            {
                    478:              fputc ('^', stdout);
                    479:              fputc (c + 0100, stdout);
                    480:            }
                    481:          else if (c == 0177)
                    482:            printf ("^?");
                    483:          else
                    484:            fputc (c, stdout);
                    485:        } while (c != '\n' && (c = fgetc (stream)) >= 0);
                    486:     }
                    487: 
                    488:   fclose (stream);
                    489: }
                    490: 
                    491: static void
                    492: list_command (arg, from_tty)
                    493:      char *arg;
                    494:      int from_tty;
                    495: {
1.1.1.5 ! root      496:   struct symtabs_and_lines sals, sals_end;
1.1       root      497:   struct symtab_and_line sal, sal_end;
                    498:   struct symbol *sym;
                    499:   char *arg1;
                    500:   int no_end = 1;
                    501:   int dummy_end = 0;
                    502:   int dummy_beg = 0;
1.1.1.2   root      503:   int linenum_beg = 0;
                    504:   char *p;
1.1       root      505: 
                    506:   if (symtab_list == 0)
                    507:     error ("Listing source lines requires symbols.");
                    508: 
                    509:   /* "l" or "l +" lists next ten lines.  */
                    510: 
                    511:   if (arg == 0 || !strcmp (arg, "+"))
                    512:     {
                    513:       if (current_source_symtab == 0)
1.1.1.2   root      514:        error ("No default source file yet.  Do \"help list\".");
1.1       root      515:       print_source_lines (current_source_symtab, current_source_line,
1.1.1.4   root      516:                          current_source_line + 10, 0);
1.1       root      517:       return;
                    518:     }
                    519: 
                    520:   /* "l -" lists previous ten lines, the ones before the ten just listed.  */
                    521:   if (!strcmp (arg, "-"))
                    522:     {
                    523:       if (current_source_symtab == 0)
1.1.1.2   root      524:        error ("No default source file yet.  Do \"help list\".");
1.1       root      525:       print_source_lines (current_source_symtab,
                    526:                          max (first_line_listed - 10, 1),
1.1.1.4   root      527:                          first_line_listed, 0);
1.1       root      528:       return;
                    529:     }
                    530: 
                    531:   /* Now if there is only one argument, decode it in SAL
                    532:      and set NO_END.
                    533:      If there are two arguments, decode them in SAL and SAL_END
                    534:      and clear NO_END; however, if one of the arguments is blank,
                    535:      set DUMMY_BEG or DUMMY_END to record that fact.  */
                    536: 
                    537:   arg1 = arg;
                    538:   if (*arg1 == ',')
                    539:     dummy_beg = 1;
                    540:   else
1.1.1.5 ! root      541:     {
        !           542:       sals = decode_line_1 (&arg1, 0, 0, 0);
        !           543: 
        !           544:       if (! sals.nelts) return;  /*  C++  */
        !           545:       if (sals.nelts != 1)
        !           546:        {
        !           547:          error ("Unreasonable listing request");
        !           548:        }
        !           549: 
        !           550:       sal = sals.sals[0];
        !           551:       free (sals.sals);
        !           552:     }
1.1       root      553: 
1.1.1.2   root      554:   /* Record whether the BEG arg is all digits.  */
                    555: 
                    556:   for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
                    557:   linenum_beg = (p == arg1);
                    558: 
1.1       root      559:   while (*arg1 == ' ' || *arg1 == '\t')
                    560:     arg1++;
                    561:   if (*arg1 == ',')
                    562:     {
                    563:       no_end = 0;
                    564:       arg1++;
                    565:       while (*arg1 == ' ' || *arg1 == '\t')
                    566:        arg1++;
                    567:       if (*arg1 == 0)
                    568:        dummy_end = 1;
                    569:       else
1.1.1.5 ! root      570:        {
        !           571:          if (dummy_beg)
        !           572:            sals_end = decode_line_1 (&arg1, 0, 0, 0);
        !           573:          else
        !           574:            sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
        !           575:          if (! sals_end.nelts) return;  /* C++ */
        !           576:          sal_end = sals_end.sals[0];
        !           577:          free (sals_end.sals);
        !           578:        }
1.1       root      579:     }
                    580: 
                    581:   if (*arg1)
                    582:     error ("Junk at end of line specification.");
                    583: 
                    584:   if (!no_end && !dummy_beg && !dummy_end
                    585:       && sal.symtab != sal_end.symtab)
                    586:     error ("Specified start and end are in different files.");
                    587:   if (dummy_beg && dummy_end)
                    588:     error ("Two empty args do not say what lines to list.");
                    589:  
                    590:   /* if line was specified by address,
                    591:      first print exactly which line, and which file.
                    592:      In this case, sal.symtab == 0 means address is outside
                    593:      of all known source files, not that user failed to give a filename.  */
                    594:   if (*arg == '*')
                    595:     {
                    596:       if (sal.symtab == 0)
                    597:        error ("No source file for address 0x%x.", sal.pc);
                    598:       sym = find_pc_function (sal.pc);
                    599:       if (sym)
                    600:        printf ("0x%x is in %s (%s, line %d).\n",
                    601:                sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
                    602:       else
                    603:        printf ("0x%x is in %s, line %d.\n",
                    604:                sal.pc, sal.symtab->filename, sal.line);
                    605:     }
                    606: 
1.1.1.2   root      607:   /* If line was not specified by just a line number,
                    608:      and it does not imply a symtab, it must be an undebuggable symbol
                    609:      which means no source code.  */
                    610: 
                    611:   if (! linenum_beg && sal.symtab == 0)
                    612:     error ("No line number known for %s.", arg);
                    613: 
1.1       root      614:   /* If this command is repeated with RET,
                    615:      turn it into the no-arg variant.  */
                    616: 
                    617:   if (from_tty)
                    618:     *arg = 0;
                    619: 
                    620:   if (dummy_beg && sal_end.symtab == 0)
1.1.1.2   root      621:     error ("No default source file yet.  Do \"help list\".");
1.1       root      622:   if (dummy_beg)
                    623:     print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1),
1.1.1.4   root      624:                        sal_end.line + 1, 0);
1.1       root      625:   else if (sal.symtab == 0)
1.1.1.2   root      626:     error ("No default source file yet.  Do \"help list\".");
1.1       root      627:   else if (no_end)
1.1.1.4   root      628:     print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5, 0);
1.1       root      629:   else
                    630:     print_source_lines (sal.symtab, sal.line,
1.1.1.5 ! root      631:                        dummy_end ? sal.line + 10 : sal_end.line + 1, 0);
1.1       root      632: }
                    633: 
                    634: /* Print info on range of pc's in a specified line.  */
                    635: 
                    636: static void
                    637: line_info (arg, from_tty)
                    638:      char *arg;
                    639:      int from_tty;
                    640: {
1.1.1.5 ! root      641:   struct symtabs_and_lines sals;
1.1       root      642:   struct symtab_and_line sal;
                    643:   int start_pc, end_pc;
                    644: 
                    645:   if (arg == 0)
                    646:     {
                    647:       sal.symtab = current_source_symtab;
1.1.1.3   root      648:       sal.line = last_line_listed;
1.1       root      649:     }
                    650:   else
                    651:     {
1.1.1.5 ! root      652:       sals = decode_line_spec (arg);
1.1       root      653: 
1.1.1.5 ! root      654:       if (sals.nelts == 0)
        !           655:        return;                 /* C++ */
        !           656:       if (sals.nelts != 1)
        !           657:        error ("unreasonable line info request");
        !           658:       
        !           659:       sal = sals.sals[0];
        !           660:       free (sals.sals);
1.1       root      661:       /* If this command is repeated with RET,
                    662:         turn it into the no-arg variant.  */
                    663: 
                    664:       if (from_tty)
                    665:        *arg = 0;
                    666:     }
                    667: 
                    668:   if (sal.symtab == 0)
                    669:     error ("No source file specified.");
                    670:   if (sal.line > 0
                    671:       && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
                    672:     {
                    673:       if (start_pc == end_pc)
                    674:        printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
                    675:                sal.line, sal.symtab->filename, start_pc);
                    676:       else
                    677:        printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
                    678:                sal.line, sal.symtab->filename, start_pc, end_pc);
                    679:       /* x/i should display this line's code.  */
                    680:       set_next_address (start_pc);
                    681:       /* Repeating "info line" should do the following line.  */
1.1.1.3   root      682:       last_line_listed = sal.line + 1;
1.1       root      683:     }
                    684:   else
                    685:     printf ("Line number %d is out of range for \"%s\".\n",
                    686:            sal.line, sal.symtab->filename);
                    687: }
1.1.1.2   root      688: 
1.1.1.3   root      689: /* Commands to search the source file for a regexp.  */
                    690: 
                    691: static void
                    692: forward_search_command (regex, from_tty)
                    693:      char *regex;
                    694: {
                    695:   register int c;
                    696:   register int desc;
                    697:   register FILE *stream;
                    698:   int line = last_line_listed + 1;
                    699:   char *msg;
                    700: 
                    701:   msg = (char *) re_comp (regex);
                    702:   if (msg)
                    703:     error (msg);
                    704: 
                    705:   if (current_source_symtab == 0) 
                    706:     error ("No default source file yet.  Do \"help list\".");
                    707: 
                    708:   /* Search from last_line_listed+1 in current_source_symtab */
                    709: 
                    710:   desc = openp (source_path, 0, current_source_symtab->filename,
                    711:                O_RDONLY, 0, &current_source_symtab->fullname);
                    712:   if (desc < 0)
                    713:     perror_with_name (current_source_symtab->filename);
                    714: 
                    715:   if (current_source_symtab->line_charpos == 0)
                    716:     find_source_lines (current_source_symtab, desc);
                    717: 
1.1.1.4   root      718:   if (line < 1 || line > current_source_symtab->nlines)
1.1.1.3   root      719:     {
                    720:       close (desc);
                    721:       error ("Expression not found");
                    722:     }
                    723: 
                    724:   if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
                    725:     {
                    726:       close (desc);
                    727:       perror_with_name (current_source_symtab->filename);
                    728:     }
                    729: 
                    730:   stream = fdopen (desc, "r");
                    731:   clearerr (stream);
                    732:   while (1) {
                    733:     char buf[4096];            /* Should be reasonable??? */
                    734:     register char *p = buf;
                    735: 
                    736:     c = fgetc (stream);
                    737:     if (c == EOF)
                    738:       break;
                    739:     do {
                    740:       *p++ = c;
                    741:     } while (c != '\n' && (c = fgetc (stream)) >= 0);
                    742: 
                    743:     /* we now have a source line in buf, null terminate and match */
                    744:     *p = 0;
                    745:     if (re_exec (buf) > 0)
                    746:       {
                    747:        /* Match! */
                    748:        fclose (stream);
                    749:        print_source_lines (current_source_symtab,
1.1.1.4   root      750:                           line, line+1, 0);
1.1.1.3   root      751:        current_source_line = max (line - 5, 1);
                    752:        return;
                    753:       }
                    754:     line++;
                    755:   }
                    756: 
                    757:   printf ("Expression not found\n");
                    758:   fclose (stream);
                    759: }
                    760: 
                    761: static void
                    762: reverse_search_command (regex, from_tty)
                    763:      char *regex;
                    764: {
                    765:   register int c;
                    766:   register int desc;
                    767:   register FILE *stream;
                    768:   int line = last_line_listed - 1;
                    769:   char *msg;
                    770: 
                    771:   msg = (char *) re_comp (regex);
                    772:   if (msg)
                    773:     error (msg);
                    774: 
                    775:   if (current_source_symtab == 0) 
                    776:     error ("No default source file yet.  Do \"help list\".");
                    777: 
                    778:   /* Search from last_line_listed-1 in current_source_symtab */
                    779: 
                    780:   desc = openp (source_path, 0, current_source_symtab->filename,
                    781:                O_RDONLY, 0, &current_source_symtab->fullname);
                    782:   if (desc < 0)
                    783:     perror_with_name (current_source_symtab->filename);
                    784: 
                    785:   if (current_source_symtab->line_charpos == 0)
                    786:     find_source_lines (current_source_symtab, desc);
                    787: 
1.1.1.4   root      788:   if (line < 1 || line > current_source_symtab->nlines)
1.1.1.3   root      789:     {
                    790:       close (desc);
                    791:       error ("Expression not found");
                    792:     }
                    793: 
                    794:   if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
                    795:     {
                    796:       close (desc);
                    797:       perror_with_name (current_source_symtab->filename);
                    798:     }
                    799: 
                    800:   stream = fdopen (desc, "r");
                    801:   clearerr (stream);
                    802:   while (1)
                    803:     {
                    804:       char buf[4096];          /* Should be reasonable??? */
                    805:       register char *p = buf;
                    806: 
                    807:       c = fgetc (stream);
                    808:       if (c == EOF)
                    809:        break;
                    810:       do {
                    811:        *p++ = c;
                    812:       } while (c != '\n' && (c = fgetc (stream)) >= 0);
                    813: 
                    814:       /* We now have a source line in buf; null terminate and match.  */
                    815:       *p = 0;
                    816:       if (re_exec (buf) > 0)
                    817:        {
                    818:          /* Match! */
                    819:          fclose (stream);
                    820:          print_source_lines (current_source_symtab,
1.1.1.4   root      821:                              line, line+1, 0);
1.1.1.3   root      822:          current_source_line = max (line - 5, 1);
                    823:          return;
                    824:        }
                    825:       line--;
                    826:       if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
                    827:        {
                    828:          fclose (stream);
                    829:          perror_with_name (current_source_symtab->filename);
                    830:        }
                    831:     }
                    832: 
                    833:   printf ("Expression not found\n");
                    834:   fclose (stream);
                    835:   return;
                    836: }
                    837: 
1.1       root      838: static
                    839: initialize ()
                    840: {
                    841:   current_source_symtab = 0;
                    842:   init_source_path ();
                    843: 
                    844:   add_com ("directory", class_files, directory_command,
                    845:           "Add directory DIR to end of search path for source files.\n\
                    846: With no argument, reset the search path to just the working directory\n\
                    847: and forget cached info on line positions in source files.");
                    848: 
                    849:   add_info ("directories", directories_info,
                    850:            "Current search path for finding source files.");
                    851: 
                    852:   add_info ("line", line_info,
                    853:            "Core addresses of the code for a source line.\n\
                    854: Line can be specified as\n\
                    855:   LINENUM, to list around that line in current file,\n\
                    856:   FILE:LINENUM, to list around that line in that file,\n\
                    857:   FUNCTION, to list around beginning of that function,\n\
                    858:   FILE:FUNCTION, to distinguish among like-named static functions.\n\
                    859: Default is to describe the last source line that was listed.\n\n\
                    860: This sets the default address for \"x\" to the line's first instruction\n\
                    861: so that \"x/i\" suffices to start examining the machine code.\n\
                    862: The address is also stored as the value of \"$_\".");
                    863: 
1.1.1.3   root      864:   add_com ("forward-search", class_files, forward_search_command,
                    865:           "Search for regular expression (see regex(3)) from last line listed.");
                    866:   add_com_alias ("search", "forward-search", class_files, 0);
                    867: 
                    868:   add_com ("reverse-search", class_files, reverse_search_command,
                    869:           "Search backward for regular expression (see regex(3)) from last line listed.");
                    870: 
1.1       root      871:   add_com ("list", class_files, list_command,
                    872:           "List specified function or line.\n\
                    873: With no argument, lists ten more lines after or around previous listing.\n\
                    874: \"list -\" lists the ten lines before a previous ten-line listing.\n\
                    875: One argument specifies a line, and ten lines are listed around that line.\n\
                    876: Two arguments with comma between specify starting and ending lines to list.\n\
                    877: Lines can be specified in these ways:\n\
                    878:   LINENUM, to list around that line in current file,\n\
                    879:   FILE:LINENUM, to list around that line in that file,\n\
                    880:   FUNCTION, to list around beginning of that function,\n\
                    881:   FILE:FUNCTION, to distinguish among like-named static functions.\n\
                    882:   *ADDRESS, to list around the line containing that address.\n\
                    883: With two args if one is empty it stands for ten lines away from the other arg.");
                    884: }
                    885: 
                    886: END_FILE

unix.superglobalmegacorp.com