📄 symtab.c
字号:
/* Search all symtabs for one whose file contains our pc */ ALL_SYMTABS (objfile, s) { bv = BLOCKVECTOR (s); b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); if (BLOCK_START (b) <= pc && BLOCK_END (b) > pc) goto found; } if (!s) { ps = find_pc_psymtab (pc); if (ps && ps->readin) { printf_filtered ("(Internal error: pc 0x%x in read in psymtab, but not in symtab.)\n", pc); } if (ps) { s = PSYMTAB_TO_SYMTAB (ps); } }found: return (s);}/* Find the source file and line number for a given PC value. Return a structure containing a symtab pointer, a line number, and a pc range for the entire source line. The value's .pc field is NOT the specified pc. NOTCURRENT nonzero means, if specified pc is on a line boundary, use the line that ends there. Otherwise, in that case, the line that begins there is used. */struct symtab_and_linefind_pc_line (pc, notcurrent) CORE_ADDR pc; int notcurrent;{ struct symtab *s; register struct linetable *l; register int len; register int i; register struct linetable_entry *item; struct symtab_and_line val; struct blockvector *bv; /* Info on best line seen so far, and where it starts, and its file. */ int best_line = 0; CORE_ADDR best_pc = 0; CORE_ADDR best_end = 0; struct symtab *best_symtab = 0; /* Store here the first line number of a file which contains the line at the smallest pc after PC. If we don't find a line whose range contains PC, we will use a line one less than this, with a range from the start of that file to the first line's pc. */ int alt_line = 0; CORE_ADDR alt_pc = 0; struct symtab *alt_symtab = 0; /* Info on best line seen in this file. */ int prev_line; CORE_ADDR prev_pc; /* Info on first line of this file. */ int first_line; CORE_ADDR first_pc; /* If this pc is not from the current frame, it is the address of the end of a call instruction. Quite likely that is the start of the following statement. But what we want is the statement containing the instruction. Fudge the pc to make sure we get that. */ if (notcurrent) pc -= 1; s = find_pc_symtab (pc); if (s == 0) { val.symtab = 0; val.line = 0; val.pc = pc; val.end = 0; return val; } bv = BLOCKVECTOR (s); /* Look at all the symtabs that share this blockvector. They all have the same apriori range, that we found was right; but they have different line tables. */ for (; s && BLOCKVECTOR (s) == bv; s = s->next) { /* Find the best line in this symtab. */ l = LINETABLE (s); if (!l) continue; len = l->nitems; prev_line = -1; first_line = -1; for (i = 0; i < len; i++) { item = &(l->item[i]); if (first_line < 0) { first_line = item->line; first_pc = item->pc; } /* Return the last line that did not start after PC. */ if (pc >= item->pc) { prev_line = item->line; prev_pc = item->pc; } else break; } /* Is this file's best line closer than the best in the other files? If so, record this file, and its best line, as best so far. */ if (prev_line >= 0 && prev_pc > best_pc) { best_pc = prev_pc; best_line = prev_line; best_symtab = s; /* If another line is in the linetable, and its PC is closer than the best_end we currently have, take it as best_end. */ if (i < len && (best_end == 0 || best_end > item->pc)) best_end = item->pc; } /* Is this file's first line closer than the first lines of other files? If so, record this file, and its first line, as best alternate. */ if (first_line >= 0 && first_pc > pc && (alt_pc == 0 || first_pc < alt_pc)) { alt_pc = first_pc; alt_line = first_line; alt_symtab = s; } } if (best_symtab == 0) { val.symtab = alt_symtab; val.line = alt_line - 1; val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); val.end = alt_pc; } else { val.symtab = best_symtab; val.line = best_line; val.pc = best_pc; if (best_end && (alt_pc == 0 || best_end < alt_pc)) val.end = best_end; else if (alt_pc) val.end = alt_pc; else val.end = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); } return val;}/* Find the PC value for a given source file and line number. Returns zero for invalid line number. The source file is specified with a struct symtab. */CORE_ADDRfind_line_pc (symtab, line) struct symtab *symtab; int line;{ register struct linetable *l; register int ind; int dummy; if (symtab == 0) return 0; l = LINETABLE (symtab); ind = find_line_common(l, line, &dummy); return (ind >= 0) ? l->item[ind].pc : 0;}/* Find the range of pc values in a line. Store the starting pc of the line into *STARTPTR and the ending pc (start of next line) into *ENDPTR. Returns 1 to indicate success. Returns 0 if could not find the specified line. */intfind_line_pc_range (symtab, thisline, startptr, endptr) struct symtab *symtab; int thisline; CORE_ADDR *startptr, *endptr;{ register struct linetable *l; register int ind; int exact_match; /* did we get an exact linenumber match */ if (symtab == 0) return 0; l = LINETABLE (symtab); ind = find_line_common (l, thisline, &exact_match); if (ind >= 0) { *startptr = l->item[ind].pc; /* If we have not seen an entry for the specified line, assume that means the specified line has zero bytes. */ if (!exact_match || ind == l->nitems-1) *endptr = *startptr; else /* Perhaps the following entry is for the following line. It's worth a try. */ if (ind+1 < l->nitems && l->item[ind+1].line == thisline + 1) *endptr = l->item[ind+1].pc; else *endptr = find_line_pc (symtab, thisline+1); return 1; } return 0;}/* Given a line table and a line number, return the index into the line table for the pc of the nearest line whose number is >= the specified one. Return -1 if none is found. The value is >= 0 if it is an index. Set *EXACT_MATCH nonzero if the value returned is an exact match. */static intfind_line_common (l, lineno, exact_match) register struct linetable *l; register int lineno; int *exact_match;{ register int i; register int len; /* BEST is the smallest linenumber > LINENO so far seen, or 0 if none has been seen so far. BEST_INDEX identifies the item for it. */ int best_index = -1; int best = 0; if (lineno <= 0) return -1; if (l == 0) return -1; len = l->nitems; for (i = 0; i < len; i++) { register struct linetable_entry *item = &(l->item[i]); if (item->line == lineno) { *exact_match = 1; return i; } if (item->line > lineno && (best == 0 || item->line < best)) { best = item->line; best_index = i; } } /* If we got here, we didn't get an exact match. */ *exact_match = 0; return best_index;}intfind_pc_line_pc_range (pc, startptr, endptr) CORE_ADDR pc; CORE_ADDR *startptr, *endptr;{ struct symtab_and_line sal; sal = find_pc_line (pc, 0); *startptr = sal.pc; *endptr = sal.end; return sal.symtab != 0;}/* If P is of the form "operator[ \t]+..." where `...' is some legitimate operator text, return a pointer to the beginning of the substring of the operator text. Otherwise, return "". */static char *operator_chars (p, end) char *p; char **end;{ *end = ""; if (strncmp (p, "operator", 8)) return *end; p += 8; /* Don't get faked out by `operator' being part of a longer identifier. */ if (isalpha(*p) || *p == '_' || *p == '$' || *p == '\0') return *end; /* Allow some whitespace between `operator' and the operator symbol. */ while (*p == ' ' || *p == '\t') p++; /* Recognize 'operator TYPENAME'. */ if (isalpha(*p) || *p == '_' || *p == '$') { register char *q = p+1; while (isalnum(*q) || *q == '_' || *q == '$') q++; *end = q; return p; } switch (*p) { case '!': case '=': case '*': case '/': case '%': case '^': if (p[1] == '=') *end = p+2; else *end = p+1; return p; case '<': case '>': case '+': case '-': case '&': case '|': if (p[1] == '=' || p[1] == p[0]) *end = p+2; else *end = p+1; return p; case '~': case ',': *end = p+1; return p; case '(': if (p[1] != ')') error ("`operator ()' must be specified without whitespace in `()'"); *end = p+2; return p; case '?': if (p[1] != ':') error ("`operator ?:' must be specified without whitespace in `?:'"); *end = p+2; return p; case '[': if (p[1] != ']') error ("`operator []' must be specified without whitespace in `[]'"); *end = p+2; return p; default: error ("`operator %s' not supported", p); break; } *end = ""; return *end;}/* Recursive helper function for decode_line_1. * Look for methods named NAME in type T. * Return number of matches. * Put matches in PHYSNAMES and SYM_ARR (which better be big enough!). * These allocations seem to define "big enough": * sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*)); * physnames = (char **) alloca (TYPE_NFN_FIELDS_TOTAL (t) * sizeof(char*)); */intfind_methods (t, name, physnames, sym_arr) struct type *t; char *name; char **physnames; struct symbol **sym_arr;{ int i1 = 0; int ibase; struct symbol *sym_class; char *class_name = type_name_no_tag (t); /* Ignore this class if it doesn't have a name. This prevents core dumps, but is just a workaround because we might not find the function in certain cases, such as struct D {virtual int f();} struct C : D {virtual int g();} (in this case g++ 1.35.1- does not put out a name for D as such, it defines type 19 (for example) in the same stab as C, and then does a .stabs "D:T19" and a .stabs "D:t19". Thus "break C::f" should not be looking for field f in the class named D, but just for the field f in the baseclasses of C (no matter what their names). However, I don't know how to replace the code below that depends on knowing the name of D. */ if (class_name && (sym_class = lookup_symbol (class_name, (struct block *)NULL, STRUCT_NAMESPACE, (int *)NULL, (struct symtab **)NULL))) { int method_counter; t = SYMBOL_TYPE (sym_class); for (method_counter = TYPE_NFN_FIELDS (t) - 1; method_counter >= 0; --method_counter) { int field_counter; struct fn_field *f = TYPE_FN_FIELDLIST1 (t, method_counter); char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter); if (!strcmp (name, method_name)) /* Find all the fields with that name. */ for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1; field_counter >= 0; --field_counter) { char *phys_name; if (TYPE_FN_FIELD_STUB (f, field_counter)) check_stub_method (t, method_counter, field_counter); phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter); physnames[i1] = (char*) alloca (strlen (phys_name) + 1); strcpy (physnames[i1], phys_name); sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL); if (sym_arr[i1]) i1++; else { fputs_filtered("(Cannot find method ", stdout); fputs_demangled(phys_name, stdout, DMGL_PARAMS); fputs_filtered(" - possibly inlined.)\n", stdout); } } } } /* Only search baseclasses if there is no match yet, * since names in derived classes override those in baseclasses. */ if (i1) return i1; for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++) i1 += find_methods(TYPE_BASECLASS(t, ibase), name, physnames + i1, sym_arr + i1); return i1;}/* Parse a string that specifies a line number. Pass the address of a char * variable; that variable will be advanced over the characters actually parsed. The string can be: LINENUM -- that line number in current file. PC returned is 0. FILE:LINENUM -- that line in that file. PC returned is 0. FUNCTION -- line number of openbrace of that function. PC returned is the start of the function. VARIABLE -- line number of definition of that variable. PC returned is 0. FILE:FUNCTION -- likewise, but prefer functions in that file.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -