This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / gnu / usr.bin / gdb / source.c
CommitLineData
04497f0b
NW
1/*-
2 * This code is derived from software copyrighted by the Free Software
3 * Foundation.
4 *
5 * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
6 * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
7 */
8
9#ifndef lint
10static char sccsid[] = "@(#)source.c 6.3 (Berkeley) 5/8/91";
11#endif /* not lint */
12
13/* List lines of source files for GDB, the GNU debugger.
14 Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
15
16This file is part of GDB.
17
18GDB is free software; you can redistribute it and/or modify
19it under the terms of the GNU General Public License as published by
20the Free Software Foundation; either version 1, or (at your option)
21any later version.
22
23GDB is distributed in the hope that it will be useful,
24but WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with GDB; see the file COPYING. If not, write to
30the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
31
32#include <stdio.h>
39955f2e 33#include <string.h>
04497f0b 34#include "defs.h"
04497f0b 35#include "param.h"
39955f2e 36#include "symtab.h"
04497f0b
NW
37
38#ifdef USG
39#include <sys/types.h>
40#include <fcntl.h>
41#endif
42
43#include <sys/param.h>
44#include <sys/stat.h>
45#include <sys/file.h>
46
47/* Path of directories to search for source files.
48 Same format as the PATH environment variable's value. */
49
50static char *source_path;
51
52/* Symtab of default file for listing lines of. */
53
54struct symtab *current_source_symtab;
55
56/* Default next line to list. */
57
58int current_source_line;
59
60/* Line number of last line printed. Default for various commands.
61 current_source_line is usually, but not always, the same as this. */
62
63static int last_line_listed;
64
65/* First line number listed by last listing command. */
66
67static int first_line_listed;
68
69\f
70struct symtab *psymtab_to_symtab ();
71
72/* Set the source file default for the "list" command, specifying a
73 symtab. Sigh. Behaivior specification: If it is called with a
74 non-zero argument, that is the symtab to select. If it is not,
75 first lookup "main"; if it exists, use the symtab and line it
76 defines. If not, take the last symtab in the symtab_list (if it
77 exists) or the last symtab in the psytab_list (if *it* exists). If
78 none of this works, report an error. */
79
80void
81select_source_symtab (s)
82 register struct symtab *s;
83{
84 struct symtabs_and_lines sals;
85 struct symtab_and_line sal;
86 struct partial_symtab *ps, *cs_pst;
87
88 if (s)
89 {
90 current_source_symtab = s;
91 current_source_line = 1;
92 return;
93 }
94
95 /* Make the default place to list be the function `main'
96 if one exists. */
97 if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0))
98 {
99 sals = decode_line_spec ("main", 1);
100 sal = sals.sals[0];
101 free (sals.sals);
102 current_source_symtab = sal.symtab;
103 current_source_line = max (sal.line - 9, 1);
104 return;
105 }
106
107 /* All right; find the last file in the symtab list (ignoring .h's). */
108
109 if (s = symtab_list)
110 {
111 do
112 {
113 char *name = s->filename;
114 int len = strlen (name);
115 if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
116 current_source_symtab = s;
117 s = s->next;
118 }
119 while (s);
120 current_source_line = 1;
121 }
122 else if (partial_symtab_list)
123 {
124 ps = partial_symtab_list;
125 while (ps)
126 {
127 char *name = ps->filename;
128 int len = strlen (name);
129 if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
130 cs_pst = ps;
131 ps = ps->next;
132 }
133 if (cs_pst)
134 if (cs_pst->readin)
135 fatal ("Internal: select_source_symtab: readin pst found and no symtabs.");
136 else
137 current_source_symtab = psymtab_to_symtab (cs_pst);
138 else
139 current_source_symtab = 0;
140 current_source_line = 1;
141 }
142}
143\f
144static void
145directories_info ()
146{
147 printf ("Source directories searched: %s\n", source_path);
148}
149
150void
151init_source_path ()
152{
153 register struct symtab *s;
154
155 source_path = savestring (current_directory, strlen (current_directory));
156
157 /* Forget what we learned about line positions in source files;
158 must check again now since files may be found in
159 a different directory now. */
160 for (s = symtab_list; s; s = s->next)
161 if (s->line_charpos != 0)
162 {
163 free (s->line_charpos);
164 s->line_charpos = 0;
165 }
166}
167
168void
169directory_command (dirname, from_tty)
170 char *dirname;
171 int from_tty;
172{
173 char *old = source_path;
174
175 dont_repeat ();
176
177 if (dirname == 0)
178 {
179 if (query ("Reinitialize source path to %s? ", current_directory))
180 {
181 init_source_path ();
182 free (old);
183 }
184 }
185 else
186 {
187 dirname = tilde_expand (dirname);
188 make_cleanup (free, dirname);
189
190 do
191 {
04497f0b
NW
192 char *name = dirname;
193 register char *p;
194 struct stat st;
195
196 {
197 char *colon = index (name, ':');
198 char *space = index (name, ' ');
199 char *tab = index (name, '\t');
200 if (colon == 0 && space == 0 && tab == 0)
201 p = dirname = name + strlen (name);
202 else
203 {
204 p = 0;
205 if (colon != 0 && (p == 0 || colon < p))
206 p = colon;
207 if (space != 0 && (p == 0 || space < p))
208 p = space;
209 if (tab != 0 && (p == 0 || tab < p))
210 p = tab;
211 dirname = p + 1;
212 while (*dirname == ':' || *dirname == ' ' || *dirname == '\t')
213 ++dirname;
214 }
215 }
216
217 if (p[-1] == '/')
218 /* Sigh. "foo/" => "foo" */
219 --p;
220 *p = '\0';
221
222 while (p[-1] == '.')
223 {
224 if (p - name == 1)
225 {
226 /* "." => getwd (). */
227 name = current_directory;
228 goto append;
229 }
230 else if (p[-2] == '/')
231 {
232 if (p - name == 2)
233 {
234 /* "/." => "/". */
235 *--p = '\0';
236 goto append;
237 }
238 else
239 {
240 /* "...foo/." => "...foo". */
241 p -= 2;
242 *p = '\0';
243 continue;
244 }
245 }
246 else
247 break;
248 }
249
250 if (*name != '/')
251 name = concat (current_directory, "/", name);
252 else
253 name = savestring (name, p - name);
254 make_cleanup (free, name);
255
256 if (stat (name, &st) < 0)
257 perror_with_name (name);
258 if ((st.st_mode & S_IFMT) != S_IFDIR)
259 error ("%s is not a directory.", name);
260
261 append:
262 {
263 register unsigned int len = strlen (name);
264
265 p = source_path;
266 while (1)
267 {
268 if (!strncmp (p, name, len)
269 && (p[len] == '\0' || p[len] == ':'))
270 {
271 if (from_tty)
272 printf ("\"%s\" is already in the source path.\n", name);
273 break;
274 }
275 p = index (p, ':');
276 if (p != 0)
277 ++p;
278 else
279 break;
280 }
281 if (p == 0)
282 {
283 source_path = concat (old, ":", name);
284 free (old);
285 old = source_path;
286 }
287 }
288 } while (*dirname != '\0');
289 if (from_tty)
290 directories_info ();
291 }
292}
293\f
294/* Open a file named STRING, searching path PATH (dir names sep by colons)
295 using mode MODE and protection bits PROT in the calls to open.
296 If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
297 (ie pretend the first element of PATH is ".")
298 If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
299 the actual file opened (this string will always start with a "/"
300
301 If a file is found, return the descriptor.
302 Otherwise, return -1, with errno set for the last name we tried to open. */
303
304/* >>>> This should only allow files of certain types,
305 >>>> eg executable, non-directory */
306int
307openp (path, try_cwd_first, string, mode, prot, filename_opened)
308 char *path;
309 int try_cwd_first;
310 char *string;
311 int mode;
312 int prot;
313 char **filename_opened;
314{
315 register int fd;
316 register char *filename;
317 register char *p, *p1;
318 register int len;
319
320 if (!path)
321 path = ".";
322
323 /* ./foo => foo */
324 while (string[0] == '.' && string[1] == '/')
325 string += 2;
326
327 if (try_cwd_first || string[0] == '/')
328 {
329 filename = string;
330 fd = open (filename, mode, prot);
331 if (fd >= 0 || string[0] == '/')
332 goto done;
333 }
334
335 filename = (char *) alloca (strlen (path) + strlen (string) + 2);
336 fd = -1;
337 for (p = path; p; p = p1 ? p1 + 1 : 0)
338 {
339 p1 = (char *) index (p, ':');
340 if (p1)
341 len = p1 - p;
342 else
343 len = strlen (p);
344
345 strncpy (filename, p, len);
346 filename[len] = 0;
347 strcat (filename, "/");
348 strcat (filename, string);
349
350 fd = open (filename, mode, prot);
351 if (fd >= 0) break;
352 }
353
354 done:
355 if (filename_opened)
356 if (fd < 0)
357 *filename_opened = (char *) 0;
358 else if (filename[0] == '/')
359 *filename_opened = savestring (filename, strlen (filename));
360 else
361 {
362 *filename_opened = concat (current_directory, "/", filename);
363 }
364
365 return fd;
366}
367\f
368/* Create and initialize the table S->line_charpos that records
369 the positions of the lines in the source file, which is assumed
370 to be open on descriptor DESC.
371 All set S->nlines to the number of such lines. */
372
373static void
374find_source_lines (s, desc)
375 struct symtab *s;
376 int desc;
377{
378 struct stat st;
379 register char *data, *p, *end;
380 int nlines = 0;
381 int lines_allocated = 1000;
382 int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
383 extern int exec_mtime;
384
385 if (fstat (desc, &st) < 0)
386 perror_with_name (s->filename);
387 if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
388 printf ("Source file is more recent than executable.\n");
389
390 data = (char *) alloca (st.st_size);
391 if (myread (desc, data, st.st_size) < 0)
392 perror_with_name (s->filename);
393 end = data + st.st_size;
394 p = data;
395 line_charpos[0] = 0;
396 nlines = 1;
397 while (p != end)
398 {
399 if (*p++ == '\n'
400 /* A newline at the end does not start a new line. */
401 && p != end)
402 {
403 if (nlines == lines_allocated)
404 {
405 lines_allocated *= 2;
406 line_charpos = (int *) xrealloc (line_charpos,
407 sizeof (int) * lines_allocated);
408 }
409 line_charpos[nlines++] = p - data;
410 }
411 }
412 s->nlines = nlines;
413 s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
414}
415
416/* Return the character position of a line LINE in symtab S.
417 Return 0 if anything is invalid. */
418
419int
420source_line_charpos (s, line)
421 struct symtab *s;
422 int line;
423{
424 if (!s) return 0;
425 if (!s->line_charpos || line <= 0) return 0;
426 if (line > s->nlines)
427 line = s->nlines;
428 return s->line_charpos[line - 1];
429}
430
431/* Return the line number of character position POS in symtab S. */
432
433int
434source_charpos_line (s, chr)
435 register struct symtab *s;
436 register int chr;
437{
438 register int line = 0;
439 register int *lnp;
440
441 if (s == 0 || s->line_charpos == 0) return 0;
442 lnp = s->line_charpos;
443 /* Files are usually short, so sequential search is Ok */
444 while (line < s->nlines && *lnp <= chr)
445 {
446 line++;
447 lnp++;
448 }
449 if (line >= s->nlines)
450 line = s->nlines;
451 return line;
452}
453\f
454/* Get full pathname and line number positions for a symtab.
455 Return nonzero if line numbers may have changed.
456 Set *FULLNAME to actual name of the file as found by `openp',
457 or to 0 if the file is not found. */
458
459int
460get_filename_and_charpos (s, line, fullname)
461 struct symtab *s;
462 int line;
463 char **fullname;
464{
465 register int desc, linenums_changed = 0;
466
467 desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
468 if (desc < 0)
469 {
470 if (fullname)
471 *fullname = NULL;
472 return 0;
473 }
474 if (fullname)
475 *fullname = s->fullname;
476 if (s->line_charpos == 0) linenums_changed = 1;
477 if (linenums_changed) find_source_lines (s, desc);
478 close (desc);
479 return linenums_changed;
480}
481
482/* Print text describing the full name of the source file S
483 and the line number LINE and its corresponding character position.
484 The text starts with two Ctrl-z so that the Emacs-GDB interface
485 can easily find it.
486
487 MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
488
489 Return 1 if successful, 0 if could not find the file. */
490
491int
492identify_source_line (s, line, mid_statement)
493 struct symtab *s;
494 int line;
495 int mid_statement;
496{
497 if (s->line_charpos == 0)
498 get_filename_and_charpos (s, line, 0);
499 if (s->fullname == 0)
500 return 0;
501 printf ("\032\032%s:%d:%d:%s:0x%x\n", s->fullname,
502 line, s->line_charpos[line - 1],
503 mid_statement ? "middle" : "beg",
504 get_frame_pc (get_current_frame()));
505 current_source_line = line;
506 first_line_listed = line;
507 last_line_listed = line;
508 current_source_symtab = s;
509 return 1;
510}
511\f
512/* Print source lines from the file of symtab S,
513 starting with line number LINE and stopping before line number STOPLINE. */
514
515void
516print_source_lines (s, line, stopline, noerror)
517 struct symtab *s;
518 int line, stopline;
519 int noerror;
520{
521 register int c;
522 register int desc;
523 register FILE *stream;
524 int nlines = stopline - line;
525
526 desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
527 if (desc < 0)
528 {
529 extern int errno;
530 if (noerror && line + 1 == stopline)
531 {
532 /* can't find the file - tell user where we are anyway */
533 current_source_symtab = s;
534 current_source_line = line;
535 first_line_listed = line;
536 last_line_listed = line;
537 printf_filtered ("%d\t(%s)\n", current_source_line++, s->filename);
538 }
539 else
540 {
541 if (! noerror)
542 perror_with_name (s->filename);
543 print_sys_errmsg (s->filename, errno);
544 }
545 return;
546 }
547
548 if (s->line_charpos == 0)
549 find_source_lines (s, desc);
550
551 if (line < 1 || line > s->nlines)
552 {
553 close (desc);
554 error ("Line number %d out of range; %s has %d lines.",
555 line, s->filename, s->nlines);
556 }
557
558 if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
559 {
560 close (desc);
561 perror_with_name (s->filename);
562 }
563
564 current_source_symtab = s;
565 current_source_line = line;
566 first_line_listed = line;
567
568 stream = fdopen (desc, "r");
569 clearerr (stream);
570
571 while (nlines-- > 0)
572 {
573 c = fgetc (stream);
574 if (c == EOF) break;
575 last_line_listed = current_source_line;
576 printf_filtered ("%d\t", current_source_line++);
577 do
578 {
579 if (c < 040 && c != '\t' && c != '\n')
580 printf_filtered ("^%c", c + 0100);
581 else if (c == 0177)
582 printf_filtered ("^?");
583 else
584 printf_filtered ("%c", c);
585 } while (c != '\n' && (c = fgetc (stream)) >= 0);
586 }
587
588 fclose (stream);
589}
590\f
591
592
593/*
594 C++
595 Print a list of files and line numbers which a user may choose from
596 in order to list a function which was specified ambiguously
597 (as with `list classname::overloadedfuncname', for example).
598 The vector in SALS provides the filenames and line numbers.
599 */
600static void
601ambiguous_line_spec (sals)
602 struct symtabs_and_lines *sals;
603{
604 int i;
605
606 for (i = 0; i < sals->nelts; ++i)
607 printf("file: \"%s\", line number: %d\n",
608 sals->sals[i].symtab->filename, sals->sals[i].line);
609}
610
611
612static void
613file_command(arg, from_tty)
614 char *arg;
615 int from_tty;
616{
617 struct symtabs_and_lines sals;
618 struct symtab_and_line sal;
619 struct symbol *sym;
620 char *arg1;
621 int linenum_beg = 0;
622 char *p;
623
624 if (symtab_list == 0 && partial_symtab_list == 0)
625 error ("No symbol table is loaded. Use the \"symbol-file\" command.");
626
627 /* Pull in a current source symtab if necessary */
628 if (arg == 0 || arg[0] == 0) {
629 if (current_source_symtab == 0)
630 select_source_symtab(0);
631 else
632 printf("%s\n", current_source_symtab->filename);
633 return;
634 }
635 arg1 = arg;
636 sals = decode_line_1 (&arg1, 0, 0, 0);
637
638 if (! sals.nelts)
639 return; /* C++ */
640
641 if (sals.nelts > 1)
642 {
643 ambiguous_line_spec (&sals);
644 free (sals.sals);
645 return;
646 }
647
648 sal = sals.sals[0];
649 free (sals.sals);
650
651 /* Record whether the BEG arg is all digits. */
652
653 for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; ++p)
654 ;
655 linenum_beg = (p == arg1);
656
657 /* if line was specified by address,
658 print exactly which line, and which file.
659 In this case, sal.symtab == 0 means address is outside
660 of all known source files, not that user failed to give a filename. */
661 if (*arg == '*')
662 {
663 if (sal.symtab == 0)
664 error ("No source file for address 0x%x.", sal.pc);
665 sym = find_pc_function (sal.pc);
666 if (sym)
667 printf ("0x%x is in %s (%s, line %d).\n",
668 sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
669 else
670 printf ("0x%x is in %s, line %d.\n",
671 sal.pc, sal.symtab->filename, sal.line);
672 }
673
674 /* If line was not specified by just a line number,
675 and it does not imply a symtab, it must be an undebuggable symbol
676 which means no source code. */
677
678 if (sal.symtab == 0)
679 {
680 if (! linenum_beg)
681 error ("No line number known for %s.", arg);
682 else
683 error ("No default source file yet. Do \"help list\".");
684 }
685 else
686 {
687 current_source_symtab = sal.symtab;
688 current_source_line = sal.line;
689 first_line_listed = sal.line;
690 }
691}
692
693#define PUSH_STACK_SIZE 32
694static struct {
695 struct symtab *symtab;
696 int line;
697} push_stack[PUSH_STACK_SIZE];
698
699static unsigned int push_stack_ptr;
700
701static void
702push_to_file_command (arg, from_tty)
703 char *arg;
704 int from_tty;
705{
706 struct symtab *cursym = current_source_symtab;
707 int curline = current_source_line;
708 register unsigned int i;
709
710 file_command(arg, from_tty);
711
712 /* if we got back, command was successful */
713 i = push_stack_ptr;
714 push_stack[i].symtab = cursym;
715 push_stack[i].line = curline;
716 push_stack_ptr = (i + 1) & (PUSH_STACK_SIZE - 1);
717}
718
719static void
720pop_file_command (arg, from_tty)
721 char *arg;
722 int from_tty;
723{
724 register unsigned int i = push_stack_ptr;
725
726 /* if there's something on the stack, pop it & clear the slot. */
727 i = (i + (PUSH_STACK_SIZE - 1)) & (PUSH_STACK_SIZE - 1);
728 if (push_stack[i].symtab) {
729 current_source_symtab = push_stack[i].symtab;
730 first_line_listed = current_source_line = push_stack[i].line;
731 push_stack[i].symtab = NULL;
732 push_stack_ptr = i;
733 }
734}
735
736
737static void
738list_command (arg, from_tty)
739 char *arg;
740 int from_tty;
741{
742 struct symtabs_and_lines sals, sals_end;
743 struct symtab_and_line sal, sal_end;
744 struct symbol *sym;
745 char *arg1;
746 int no_end = 1;
747 int dummy_end = 0;
748 int dummy_beg = 0;
749 int linenum_beg = 0;
750 char *p;
751
752 if (symtab_list == 0 && partial_symtab_list == 0)
753 error ("No symbol table is loaded. Use the \"symbol-file\" command.");
754
755 /* Pull in a current source symtab if necessary */
756 if (current_source_symtab == 0 &&
757 (arg == 0 || arg[0] == '+' || arg[0] == '-'))
758 select_source_symtab (0);
759
760 /* "l" or "l +" lists next ten lines. */
761
762 if (arg == 0 || !strcmp (arg, "+"))
763 {
764 if (current_source_symtab == 0)
765 error ("No default source file yet. Do \"help list\".");
766 print_source_lines (current_source_symtab, current_source_line,
767 current_source_line + 10, 0);
768 return;
769 }
770
771 /* "l -" lists previous ten lines, the ones before the ten just listed. */
772 if (!strcmp (arg, "-"))
773 {
774 if (current_source_symtab == 0)
775 error ("No default source file yet. Do \"help list\".");
776 print_source_lines (current_source_symtab,
777 max (first_line_listed - 10, 1),
778 first_line_listed, 0);
779 return;
780 }
781
782 /* Now if there is only one argument, decode it in SAL
783 and set NO_END.
784 If there are two arguments, decode them in SAL and SAL_END
785 and clear NO_END; however, if one of the arguments is blank,
786 set DUMMY_BEG or DUMMY_END to record that fact. */
787
788 arg1 = arg;
789 if (*arg1 == ',')
790 dummy_beg = 1;
791 else
792 {
793 sals = decode_line_1 (&arg1, 0, 0, 0);
794
795 if (! sals.nelts) return; /* C++ */
796 if (sals.nelts > 1)
797 {
798 ambiguous_line_spec (&sals);
799 free (sals.sals);
800 return;
801 }
802
803 sal = sals.sals[0];
804 free (sals.sals);
805 }
806
807 /* Record whether the BEG arg is all digits. */
808
809 for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
810 linenum_beg = (p == arg1);
811
812 while (*arg1 == ' ' || *arg1 == '\t')
813 arg1++;
814 if (*arg1 == ',')
815 {
816 no_end = 0;
817 arg1++;
818 while (*arg1 == ' ' || *arg1 == '\t')
819 arg1++;
820 if (*arg1 == 0)
821 dummy_end = 1;
822 else
823 {
824 if (dummy_beg)
825 sals_end = decode_line_1 (&arg1, 0, 0, 0);
826 else
827 sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
828 if (sals_end.nelts == 0)
829 return;
830 if (sals_end.nelts > 1)
831 {
832 ambiguous_line_spec (&sals_end);
833 free (sals_end.sals);
834 return;
835 }
836 sal_end = sals_end.sals[0];
837 free (sals_end.sals);
838 }
839 }
840
841 if (*arg1)
842 error ("Junk at end of line specification.");
843
844 if (!no_end && !dummy_beg && !dummy_end
845 && sal.symtab != sal_end.symtab)
846 error ("Specified start and end are in different files.");
847 if (dummy_beg && dummy_end)
848 error ("Two empty args do not say what lines to list.");
849
850 /* if line was specified by address,
851 first print exactly which line, and which file.
852 In this case, sal.symtab == 0 means address is outside
853 of all known source files, not that user failed to give a filename. */
854 if (*arg == '*')
855 {
856 if (sal.symtab == 0)
857 error ("No source file for address 0x%x.", sal.pc);
858 sym = find_pc_function (sal.pc);
859 if (sym)
860 printf ("0x%x is in %s (%s, line %d).\n",
861 sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
862 else
863 printf ("0x%x is in %s, line %d.\n",
864 sal.pc, sal.symtab->filename, sal.line);
865 }
866
867 /* If line was not specified by just a line number,
868 and it does not imply a symtab, it must be an undebuggable symbol
869 which means no source code. */
870
871 if (! linenum_beg && sal.symtab == 0)
872 error ("No line number known for %s.", arg);
873
874 /* If this command is repeated with RET,
875 turn it into the no-arg variant. */
876
877 if (from_tty)
878 *arg = 0;
879
880 if (dummy_beg && sal_end.symtab == 0)
881 error ("No default source file yet. Do \"help list\".");
882 if (dummy_beg)
883 print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1),
884 sal_end.line + 1, 0);
885 else if (sal.symtab == 0)
886 error ("No default source file yet. Do \"help list\".");
887 else if (no_end)
888 print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5, 0);
889 else
890 print_source_lines (sal.symtab, sal.line,
891 dummy_end ? sal.line + 10 : sal_end.line + 1,
892 0);
893}
894\f
895/* Print info on range of pc's in a specified line. */
896
897static void
898line_info (arg, from_tty)
899 char *arg;
900 int from_tty;
901{
902 struct symtabs_and_lines sals;
903 struct symtab_and_line sal;
904 int start_pc, end_pc;
905 int i;
906
907 if (arg == 0)
908 {
909 sal.symtab = current_source_symtab;
910 sal.line = last_line_listed;
911 sals.nelts = 1;
912 sals.sals = (struct symtab_and_line *)
913 xmalloc (sizeof (struct symtab_and_line));
914 sals.sals[0] = sal;
915 }
916 else
917 {
918 sals = decode_line_spec_1 (arg, 0);
919
920 /* If this command is repeated with RET,
921 turn it into the no-arg variant. */
922 if (from_tty)
923 *arg = 0;
924 }
925
926 /* C++ More than one line may have been specified, as when the user
927 specifies an overloaded function name. Print info on them all. */
928 for (i = 0; i < sals.nelts; i++)
929 {
930 sal = sals.sals[i];
931
932 if (sal.symtab == 0)
933 error ("No source file specified.");
934
935 if (sal.line > 0
936 && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
937 {
938 if (start_pc == end_pc)
939 printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
940 sal.line, sal.symtab->filename, start_pc);
941 else
942 printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
943 sal.line, sal.symtab->filename, start_pc, end_pc);
944 /* x/i should display this line's code. */
945 set_next_address (start_pc);
946 /* Repeating "info line" should do the following line. */
947 last_line_listed = sal.line + 1;
948 }
949 else
950 printf ("Line number %d is out of range for \"%s\".\n",
951 sal.line, sal.symtab->filename);
952 }
953}
954\f
955/* Commands to search the source file for a regexp. */
956
957static void
958forward_search_command (regex, from_tty)
959 char *regex;
960{
961 register int c;
962 register int desc;
963 register FILE *stream;
964 int line = last_line_listed + 1;
965 char *msg;
966
967 msg = (char *) re_comp (regex);
968 if (msg)
969 error (msg);
970
971 if (current_source_symtab == 0)
972 select_source_symtab (0);
973
974 /* Search from last_line_listed+1 in current_source_symtab */
975
976 desc = openp (source_path, 0, current_source_symtab->filename,
977 O_RDONLY, 0, &current_source_symtab->fullname);
978 if (desc < 0)
979 perror_with_name (current_source_symtab->filename);
980
981 if (current_source_symtab->line_charpos == 0)
982 find_source_lines (current_source_symtab, desc);
983
984 if (line < 1 || line > current_source_symtab->nlines)
985 {
986 close (desc);
987 error ("Expression not found");
988 }
989
990 if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
991 {
992 close (desc);
993 perror_with_name (current_source_symtab->filename);
994 }
995
996 stream = fdopen (desc, "r");
997 clearerr (stream);
998 while (1) {
999 char buf[4096]; /* Should be reasonable??? */
1000 register char *p = buf;
1001
1002 c = fgetc (stream);
1003 if (c == EOF)
1004 break;
1005 do {
1006 *p++ = c;
1007 } while (c != '\n' && (c = fgetc (stream)) >= 0);
1008
1009 /* we now have a source line in buf, null terminate and match */
1010 *p = 0;
1011 if (re_exec (buf) > 0)
1012 {
1013 /* Match! */
1014 fclose (stream);
1015 print_source_lines (current_source_symtab,
1016 line, line+1, 0);
1017 current_source_line = max (line - 5, 1);
1018 return;
1019 }
1020 line++;
1021 }
1022
1023 printf ("Expression not found\n");
1024 fclose (stream);
1025}
1026
1027static void
1028reverse_search_command (regex, from_tty)
1029 char *regex;
1030{
1031 register int c;
1032 register int desc;
1033 register FILE *stream;
1034 int line = last_line_listed - 1;
1035 char *msg;
1036
1037 msg = (char *) re_comp (regex);
1038 if (msg)
1039 error (msg);
1040
1041 if (current_source_symtab == 0)
1042 select_source_symtab (0);
1043
1044 /* Search from last_line_listed-1 in current_source_symtab */
1045
1046 desc = openp (source_path, 0, current_source_symtab->filename,
1047 O_RDONLY, 0, &current_source_symtab->fullname);
1048 if (desc < 0)
1049 perror_with_name (current_source_symtab->filename);
1050
1051 if (current_source_symtab->line_charpos == 0)
1052 find_source_lines (current_source_symtab, desc);
1053
1054 if (line < 1 || line > current_source_symtab->nlines)
1055 {
1056 close (desc);
1057 error ("Expression not found");
1058 }
1059
1060 if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
1061 {
1062 close (desc);
1063 perror_with_name (current_source_symtab->filename);
1064 }
1065
1066 stream = fdopen (desc, "r");
1067 clearerr (stream);
1068 while (1)
1069 {
1070 char buf[4096]; /* Should be reasonable??? */
1071 register char *p = buf;
1072
1073 c = fgetc (stream);
1074 if (c == EOF)
1075 break;
1076 do {
1077 *p++ = c;
1078 } while (c != '\n' && (c = fgetc (stream)) >= 0);
1079
1080 /* We now have a source line in buf; null terminate and match. */
1081 *p = 0;
1082 if (re_exec (buf) > 0)
1083 {
1084 /* Match! */
1085 fclose (stream);
1086 print_source_lines (current_source_symtab,
1087 line, line+1, 0);
1088 current_source_line = max (line - 5, 1);
1089 return;
1090 }
1091 line--;
1092 if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
1093 {
1094 fclose (stream);
1095 perror_with_name (current_source_symtab->filename);
1096 }
1097 }
1098
1099 printf ("Expression not found\n");
1100 fclose (stream);
1101 return;
1102}
1103\f
1104void
1105_initialize_source ()
1106{
1107 current_source_symtab = 0;
1108 init_source_path ();
1109
1110 add_com ("directory", class_files, directory_command,
1111 "Add directory DIR to end of search path for source files.\n\
1112With no argument, reset the search path to just the working directory\n\
1113and forget cached info on line positions in source files.");
1114
1115 add_info ("directories", directories_info,
1116 "Current search path for finding source files.");
1117
1118 add_info ("line", line_info,
1119 "Core addresses of the code for a source line.\n\
1120Line can be specified as\n\
1121 LINENUM, to list around that line in current file,\n\
1122 FILE:LINENUM, to list around that line in that file,\n\
1123 FUNCTION, to list around beginning of that function,\n\
1124 FILE:FUNCTION, to distinguish among like-named static functions.\n\
1125Default is to describe the last source line that was listed.\n\n\
1126This sets the default address for \"x\" to the line's first instruction\n\
1127so that \"x/i\" suffices to start examining the machine code.\n\
1128The address is also stored as the value of \"$_\".");
1129
1130 add_com ("forward-search", class_files, forward_search_command,
1131 "Search for regular expression (see regex(3)) from last line listed.");
1132 add_com_alias ("search", "forward-search", class_files, 0);
1133
1134 add_com ("reverse-search", class_files, reverse_search_command,
1135 "Search backward for regular expression (see regex(3)) from last line listed.");
1136
1137 add_com ("list", class_files, list_command,
1138 "List specified function or line.\n\
1139With no argument, lists ten more lines after or around previous listing.\n\
1140\"list -\" lists the ten lines before a previous ten-line listing.\n\
1141One argument specifies a line, and ten lines are listed around that line.\n\
1142Two arguments with comma between specify starting and ending lines to list.\n\
1143Lines can be specified in these ways:\n\
1144 LINENUM, to list around that line in current file,\n\
1145 FILE:LINENUM, to list around that line in that file,\n\
1146 FUNCTION, to list around beginning of that function,\n\
1147 FILE:FUNCTION, to distinguish among like-named static functions.\n\
1148 *ADDRESS, to list around the line containing that address.\n\
1149With two args if one is empty it stands for ten lines away from the other arg.");
1150 add_com ("file", class_files, file_command,
1151 "Select current file, function and line for display or list.\n\
1152Specification can have the form:\n\
1153 LINENUM, to select that line in current file,\n\
1154 FILE:LINENUM, to select that line in that file,\n\
1155 FUNCTION, to select beginning of that function,\n\
1156 FILE:FUNCTION, to distinguish among like-named static functions.\n\
1157 *ADDRESS, to select the line containing that address.");
1158 add_com ("push-to-file", class_files, push_to_file_command,
1159 "Like \"file\" command but remembers current file & line on a stack.\n\
1160Can later return to current file with \"pop-file\" command.\n\
1161Up to 32 file positions can be pushed on stack.");
1162 add_com ("pop-file", class_files, pop_file_command,
1163 "Pops back to file position saved by most recent \"push-to-file\".\n\
1164If everything has been popped from stack, command does nothing.");
1165}
1166