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