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