if (!srcline_full_filename)
file = gnu_basename(file);
if (asprintf(&srcline, "%s:%u", file, line) < 0) return NULL;
return srcline;
}
staticstruct symbol *new_inline_sym(struct dso *dso, struct symbol *base_sym, constchar *funcname)
{ struct symbol *inline_sym; char *demangled = NULL;
if (!funcname)
funcname = "??";
if (dso) {
demangled = dso__demangle_sym(dso, 0, funcname); if (demangled)
funcname = demangled;
}
if (base_sym && strcmp(funcname, base_sym->name) == 0) { /* reuse the real, existing symbol */
inline_sym = base_sym; /* ensure that we don't alias an inlined symbol, which could * lead to double frees in inline_node__delete
*/
assert(!base_sym->inlined);
} else { /* create a fake symbol for the inline frame */
inline_sym = symbol__new(base_sym ? base_sym->start : 0,
base_sym ? (base_sym->end - base_sym->start) : 0,
base_sym ? base_sym->binding : 0,
base_sym ? base_sym->type : 0,
funcname); if (inline_sym)
inline_sym->inlined = 1;
}
free(demangled);
return inline_sym;
}
#define MAX_INLINE_NEST 1024
#ifdef HAVE_LIBLLVM_SUPPORT
staticvoid free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames, int num_frames)
{ if (inline_frames != NULL) { for (int i = 0; i < num_frames; ++i) {
zfree(&inline_frames[i].filename);
zfree(&inline_frames[i].funcname);
}
zfree(&inline_frames);
}
}
staticint read_addr2line_record(struct io *io, enum a2l_style style, constchar *dso_name,
u64 addr, bool first, char **function, char **filename, unsignedint *line_nr)
{ /* * Returns: * -1 ==> error * 0 ==> sentinel (or other ill-formed) record read * 1 ==> a genuine record read
*/ char *line = NULL;
size_t line_len = 0; unsignedint dummy_line_nr = 0; int ret = -1;
if (function != NULL)
zfree(function);
if (filename != NULL)
zfree(filename);
if (line_nr != NULL)
*line_nr = 0;
/* * Read the first line. Without an error this will be: * - for the first line an address like 0x1234, * - the binutils sentinel 0x0000000000000000, * - the llvm-addr2line the sentinel ',' character, * - the function name line for an inlined function.
*/ if (io__getline(io, &line, &line_len) < 0 || !line_len) goto error;
pr_debug3("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line); if (style == LLVM && line_len == 2 && line[0] == ',') { /* Found the llvm-addr2line sentinel character. */
zfree(&line); return 0;
} elseif (style == GNU_BINUTILS && (!first || addr != 0)) { int zero_count = 0, non_zero_count = 0; /* * Check for binutils sentinel ignoring it for the case the * requested address is 0.
*/
/* A given address should always start 0x. */ if (line_len >= 2 || line[0] != '0' || line[1] != 'x') { for (size_t i = 2; i < line_len; i++) { if (line[i] == '0')
zero_count++; elseif (line[i] != '\n')
non_zero_count++;
} if (!non_zero_count) { int ch;
if (first && !zero_count) { /* Line was erroneous just '0x'. */ goto error;
} /* * Line was 0x0..0, the sentinel for binutils. Remove * the function and filename lines.
*/
zfree(&line); do {
ch = io__get_char(io);
} while (ch > 0 && ch != '\n'); do {
ch = io__get_char(io);
} while (ch > 0 && ch != '\n'); return 0;
}
}
} /* Read the second function name line (if inline data then this is the first line). */ if (first && (io__getline(io, &line, &line_len) < 0 || !line_len)) goto error;
if (a2l == NULL) { if (!symbol_conf.disable_add2line_warn)
pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); goto out;
}
a2l_style = addr2line_configure(a2l, dso_name); if (a2l_style == BROKEN) goto out;
/* * Send our request and then *deliberately* send something that can't be * interpreted as a valid address to ask addr2line about (namely, * ","). This causes addr2line to first write out the answer to our * request, in an unbounded/unknown number of records, and then to write * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," * for llvm-addr2line, so that we can detect when it has finished giving * us anything useful.
*/
len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr);
written = len > 0 ? write(a2l->in, buf, len) : -1; if (written != len) { if (!symbol_conf.disable_add2line_warn)
pr_warning("%s %s: could not send request\n", __func__, dso_name); goto out;
}
io__init(&io, a2l->out, buf, sizeof(buf));
io.timeout_ms = addr2line_timeout_ms; switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=*/true,
&record_function, &record_filename, &record_line_nr)) { case -1: if (!symbol_conf.disable_add2line_warn)
pr_warning("%s %s: could not read first record\n", __func__, dso_name); goto out; case 0: /* * The first record was invalid, so return failure, but first * read another record, since we sent a sentinel ',' for the * sake of detected the last inlined function. Treat this as the * first of a record as the ',' generates a new start with GNU * binutils, also force a non-zero address as we're no longer * reading that record.
*/ switch (read_addr2line_record(&io, a2l_style, dso_name, /*addr=*/1, /*first=*/true,
NULL, NULL, NULL)) { case -1: if (!symbol_conf.disable_add2line_warn)
pr_warning("%s %s: could not read sentinel record\n",
__func__, dso_name); break; case 0: /* The sentinel as expected. */ break; default: if (!symbol_conf.disable_add2line_warn)
pr_warning("%s %s: unexpected record instead of sentinel",
__func__, dso_name); break;
} goto out; default: /* First record as expected. */ break;
}
if (file) {
*file = strdup(record_filename);
ret = 1;
} if (line_nr)
*line_nr = record_line_nr;
if (unwind_inlines) { if (node && inline_list__append_record(dso, node, sym,
record_function,
record_filename,
record_line_nr)) {
ret = 0; goto out;
}
}
/* * We have to read the records even if we don't care about the inline * info. This isn't the first record and force the address to non-zero * as we're reading records beyond the first.
*/ while ((record_status = read_addr2line_record(&io,
a2l_style,
dso_name, /*addr=*/1, /*first=*/false,
&record_function,
&record_filename,
&record_line_nr)) == 1) { if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { if (inline_list__append_record(dso, node, sym,
record_function,
record_filename,
record_line_nr)) {
ret = 0; goto out;
}
ret = 1; /* found at least one inline frame */
}
}
/* Returns filename and fills in line number in line */ char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
{ char *file = NULL; constchar *dso_name;
if (!dso__has_srcline(dso)) return NULL;
dso_name = srcline_dso_name(dso); if (dso_name == NULL) goto out_err;
list_for_each_entry_safe(ilist, tmp, &node->val, list) {
list_del_init(&ilist->list);
zfree_srcline(&ilist->srcline); /* only the inlined symbols are owned by the list */ if (ilist->symbol && ilist->symbol->inlined)
symbol__delete(ilist->symbol);
free(ilist);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.