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