/* Get 2 hex digits */
c1 = *(*line)++; if (!isxdigit(c1)) break;
c2 = *(*line)++; if (!isxdigit(c2)) break;
/* Store byte and advance buf */
**buf = (hex(c1) << 4) | hex(c2);
(*buf)++;
(*buf_len)--;
bytes_read++;
/* End of chunk? */ if (isspace(**line)) break;
}
/* * objdump will display raw insn as LE if code endian * is LE and bytes_per_chunk > 1. In that case reverse * the chunk we just read. * * see disassemble_bytes() at binutils/objdump.c for details * how objdump chooses display endian)
*/ if (bytes_read > 1 && !host_is_bigendian()) { unsignedchar *chunk_end = chunk_start + bytes_read - 1; unsignedchar tmp;
/* copy it from temporary buffer to 'buf' according
* to address on current objdump line */
off = addr - start_addr; if (off >= *len) break;
written_bytes = MIN(read_bytes, *len - off);
memcpy(buf + off, tmp, written_bytes);
off_last = off + written_bytes;
}
/* len returns number of bytes that could not be read */
*len -= off_last;
free(line);
return err;
}
/* * Only gets GNU objdump version. Returns 0 for llvm-objdump.
*/ staticint objdump_version(void)
{
size_t line_len; char cmd[PATH_MAX * 2]; char *line = NULL; constchar *fmt;
FILE *f; int ret;
int version_tmp, version_num = 0; char *version = 0, *token;
fmt = "%s --version";
ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path); if (ret <= 0 || (size_t)ret >= sizeof(cmd)) return -1; /* Ignore objdump errors */
strcat(cmd, " 2>/dev/null");
f = popen(cmd, "r"); if (!f) {
pr_debug("popen failed\n"); return -1;
} /* Get first line of objdump --version output */
ret = getline(&line, &line_len, f);
pclose(f); if (ret < 0) {
pr_debug("getline failed\n"); return -1;
}
token = strsep(&line, " "); if (token != NULL && !strcmp(token, "GNU")) { // version is last part of first line of objdump --version output. while ((token = strsep(&line, " ")))
version = token;
// Convert version into a format we can compare with
token = strsep(&version, ".");
version_num = atoi(token); if (version_num)
version_num *= 10000;
ret = uname(&uname_buf); if (ret) {
pr_debug("uname failed\n"); return -1;
}
if (!strncmp(uname_buf.machine, "riscv", 5)) { int version = objdump_version();
/* Default to this workaround if version parsing fails */ if (version < 0 || version > 24100) { /* * Starting at riscv objdump version 2.41, dumping in * the middle of an instruction is not supported. riscv * instructions are aligned along 2-byte intervals and * can be either 2-bytes or 4-bytes. This makes it * possible that the stop-address lands in the middle of * a 4-byte instruction. Increase the stop_address by * two to ensure an instruction is not cut in half, but * leave the len as-is so only the expected number of * bytes are collected.
*/
stop_address += 2;
}
}
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
addr_location__init(&al); if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) { if (cpumode == PERF_RECORD_MISC_HYPERVISOR) {
pr_debug("Hypervisor address can not be resolved - skipping\n"); goto out;
}
pr_debug("On file address is: %#"PRIx64"\n", al.addr);
if (len > BUFSZ)
len = BUFSZ;
/* Do not go off the map */ if (addr + len > map__end(al.map))
len = map__end(al.map) - addr;
/* * Some architectures (ex: powerpc) have stubs (trampolines) in kernel * modules to manage long jumps. Check if the ip offset falls in stubs * sections for kernel modules. And skip module address after text end
*/ if (dso__is_kmod(dso) && al.addr > dso__text_end(dso)) {
pr_debug("skipping the module address %#"PRIx64" after text end\n", al.addr); goto out;
}
/* Read the object code using perf */
ret_len = dso__data_read_offset(dso, maps__machine(thread__maps(thread)),
al.addr, buf1, len); if (ret_len != len) {
pr_debug("dso__data_read_offset failed\n");
err = -1; goto out;
}
/* * Converting addresses for use by objdump requires more information. * map__load() does that. See map__rip_2objdump() for details.
*/ if (map__load(al.map)) {
err = -1; goto out;
}
/* objdump struggles with kcore - try each map only once */ if (dso__is_kcore(dso)) {
size_t d;
for (d = 0; d < state->done_cnt; d++) { if (state->done[d] == map__start(al.map)) {
pr_debug("kcore map tested already");
pr_debug(" - skipping\n"); goto out;
}
} if (state->done_cnt >= ARRAY_SIZE(state->done)) {
pr_debug("Too many kcore maps - skipping\n"); goto out;
}
state->done[state->done_cnt++] = map__start(al.map);
}
/* Read the object code using objdump */
objdump_addr = map__rip_2objdump(al.map, al.addr);
ret = read_via_objdump(objdump_name, objdump_addr, buf2, len);
if (decomp)
unlink(objdump_name);
if (ret > 0) { /* * The kernel maps are inaccurate - assume objdump is right in * that case.
*/ if (cpumode == PERF_RECORD_MISC_KERNEL ||
cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
len -= ret; if (len) {
pr_debug("Reducing len to %zu\n", len);
} elseif (dso__is_kcore(dso)) { /* * objdump cannot handle very large segments * that may be found in kcore.
*/
pr_debug("objdump failed for kcore");
pr_debug(" - skipping\n");
} else {
err = -1;
} goto out;
}
} if (ret < 0) {
pr_debug("read_via_objdump failed\n");
err = -1; goto out;
}
/* The results should be identical */ if (memcmp(buf1, buf2, len)) {
pr_debug("Bytes read differ from those read by objdump\n");
pr_debug("buf1 (dso):\n");
dump_buf(buf1, len);
pr_debug("buf2 (objdump):\n");
dump_buf(buf2, len);
err = -1; goto out;
}
pr_debug("Bytes read match those read by objdump\n");
out:
addr_location__exit(&al); return err;
}
staticint process_sample_event(struct machine *machine, struct evlist *evlist, union perf_event *event, struct state *state)
{ struct perf_sample sample; struct thread *thread; int ret;
perf_sample__init(&sample, /*all=*/false);
ret = evlist__parse_sample(evlist, event, &sample); if (ret) {
pr_debug("evlist__parse_sample failed\n");
ret = -1; goto out;
}
thread = machine__findnew_thread(machine, sample.pid, sample.tid); if (!thread) {
pr_debug("machine__findnew_thread failed\n");
ret = -1; goto out;
}
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.