static int __report_module(struct addr_location *al, u64 ip, struct unwind_info *ui) { Dwfl_Module *mod; struct dso *dso = NULL; /* * Some callers will use al->sym, so we can't just use the * cheaper thread__find_map() here. */ thread__find_symbol(ui->thread, PERF_RECORD_MISC_USER, ip, al); if (al->map) dso = al->map->dso; if (!dso) return 0; mod = dwfl_addrmodule(ui->dwfl, ip); if (mod) { Dwarf_Addr s; dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); if (s != al->map->start) mod = 0; } if (!mod) mod = dwfl_report_elf(ui->dwfl, dso->short_name, (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start, false); return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1; }
/* * The callchain saved by the kernel always includes the link register (LR). * * 0: PERF_CONTEXT_USER * 1: Program counter (Next instruction pointer) * 2: LR value * 3: Caller's caller * 4: ... * * The value in LR is only needed when it holds a return address. If the * return address is on the stack, we should ignore the LR value. * * Further, when the return address is in the LR, if a new frame was just * allocated but the LR was not saved into it, then the LR contains the * caller, slot 4: contains the caller's caller and the contents of slot 3: * (chain->ips[3]) is undefined and must be ignored. * * Use DWARF debug information to determine if any entries need to be skipped. * * Return: * index: of callchain entry that needs to be ignored (if any) * -1 if no entry needs to be ignored or in case of errors */ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) { struct addr_location al; struct dso *dso = NULL; int rc; u64 ip; u64 skip_slot = -1; if (!chain || chain->nr < 3) return skip_slot; ip = chain->ips[1]; thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); if (al.map) dso = al.map->dso; if (!dso) { pr_debug("%" PRIx64 " dso is NULL\n", ip); return skip_slot; } rc = check_return_addr(dso, al.map->start, ip); pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n", dso->long_name, al.sym->name, ip, rc); if (rc == 0) { /* * Return address on stack. Ignore LR value in callchain */ skip_slot = 2; } else if (rc == 2) { /* * New frame allocated but return address still in LR. * Ignore the caller's caller entry in callchain. */ skip_slot = 3; } return skip_slot; }