162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Lots of this code have been borrowed or heavily inspired from parts of 662306a36Sopenharmony_ci * the libunwind 0.99 code which are (amongst other contributors I may have 762306a36Sopenharmony_ci * forgotten): 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2002-2007 Hewlett-Packard Co 1062306a36Sopenharmony_ci * Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * And the bugs have been added by: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com> 1562306a36Sopenharmony_ci * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com> 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <elf.h> 2062306a36Sopenharmony_ci#include <errno.h> 2162306a36Sopenharmony_ci#include <gelf.h> 2262306a36Sopenharmony_ci#include <fcntl.h> 2362306a36Sopenharmony_ci#include <inttypes.h> 2462306a36Sopenharmony_ci#include <string.h> 2562306a36Sopenharmony_ci#include <unistd.h> 2662306a36Sopenharmony_ci#include <sys/mman.h> 2762306a36Sopenharmony_ci#include <linux/list.h> 2862306a36Sopenharmony_ci#include <linux/zalloc.h> 2962306a36Sopenharmony_ci#ifndef REMOTE_UNWIND_LIBUNWIND 3062306a36Sopenharmony_ci#include <libunwind.h> 3162306a36Sopenharmony_ci#include <libunwind-ptrace.h> 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci#include "callchain.h" 3462306a36Sopenharmony_ci#include "thread.h" 3562306a36Sopenharmony_ci#include "session.h" 3662306a36Sopenharmony_ci#include "perf_regs.h" 3762306a36Sopenharmony_ci#include "unwind.h" 3862306a36Sopenharmony_ci#include "map.h" 3962306a36Sopenharmony_ci#include "symbol.h" 4062306a36Sopenharmony_ci#include "debug.h" 4162306a36Sopenharmony_ci#include "asm/bug.h" 4262306a36Sopenharmony_ci#include "dso.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciextern int 4562306a36Sopenharmony_ciUNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 4662306a36Sopenharmony_ci unw_word_t ip, 4762306a36Sopenharmony_ci unw_dyn_info_t *di, 4862306a36Sopenharmony_ci unw_proc_info_t *pi, 4962306a36Sopenharmony_ci int need_unwind_info, void *arg); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciextern int 5462306a36Sopenharmony_ciUNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, 5562306a36Sopenharmony_ci unw_word_t ip, 5662306a36Sopenharmony_ci unw_word_t segbase, 5762306a36Sopenharmony_ci const char *obj_name, unw_word_t start, 5862306a36Sopenharmony_ci unw_word_t end); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ 6362306a36Sopenharmony_ci#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Pointer-encoding formats: */ 6662306a36Sopenharmony_ci#define DW_EH_PE_omit 0xff 6762306a36Sopenharmony_ci#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ 6862306a36Sopenharmony_ci#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ 6962306a36Sopenharmony_ci#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ 7062306a36Sopenharmony_ci#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ 7162306a36Sopenharmony_ci#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Pointer-encoding application: */ 7462306a36Sopenharmony_ci#define DW_EH_PE_absptr 0x00 /* absolute value */ 7562306a36Sopenharmony_ci#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * The following are not documented by LSB v1.3, yet they are used by 7962306a36Sopenharmony_ci * GCC, presumably they aren't documented by LSB since they aren't 8062306a36Sopenharmony_ci * used on Linux: 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ 8362306a36Sopenharmony_ci#define DW_EH_PE_aligned 0x50 /* aligned pointer */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Flags intentionally not handled, since they're not needed: 8662306a36Sopenharmony_ci * #define DW_EH_PE_indirect 0x80 8762306a36Sopenharmony_ci * #define DW_EH_PE_uleb128 0x01 8862306a36Sopenharmony_ci * #define DW_EH_PE_udata2 0x02 8962306a36Sopenharmony_ci * #define DW_EH_PE_sleb128 0x09 9062306a36Sopenharmony_ci * #define DW_EH_PE_sdata2 0x0a 9162306a36Sopenharmony_ci * #define DW_EH_PE_textrel 0x20 9262306a36Sopenharmony_ci * #define DW_EH_PE_datarel 0x30 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct unwind_info { 9662306a36Sopenharmony_ci struct perf_sample *sample; 9762306a36Sopenharmony_ci struct machine *machine; 9862306a36Sopenharmony_ci struct thread *thread; 9962306a36Sopenharmony_ci bool best_effort; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#define dw_read(ptr, type, end) ({ \ 10362306a36Sopenharmony_ci type *__p = (type *) ptr; \ 10462306a36Sopenharmony_ci type __v; \ 10562306a36Sopenharmony_ci if ((__p + 1) > (type *) end) \ 10662306a36Sopenharmony_ci return -EINVAL; \ 10762306a36Sopenharmony_ci __v = *__p++; \ 10862306a36Sopenharmony_ci ptr = (typeof(ptr)) __p; \ 10962306a36Sopenharmony_ci __v; \ 11062306a36Sopenharmony_ci }) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, 11362306a36Sopenharmony_ci u8 encoding) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u8 *cur = *p; 11662306a36Sopenharmony_ci *val = 0; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci switch (encoding) { 11962306a36Sopenharmony_ci case DW_EH_PE_omit: 12062306a36Sopenharmony_ci *val = 0; 12162306a36Sopenharmony_ci goto out; 12262306a36Sopenharmony_ci case DW_EH_PE_ptr: 12362306a36Sopenharmony_ci *val = dw_read(cur, unsigned long, end); 12462306a36Sopenharmony_ci goto out; 12562306a36Sopenharmony_ci default: 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci switch (encoding & DW_EH_PE_APPL_MASK) { 13062306a36Sopenharmony_ci case DW_EH_PE_absptr: 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case DW_EH_PE_pcrel: 13362306a36Sopenharmony_ci *val = (unsigned long) cur; 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci default: 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if ((encoding & 0x07) == 0x00) 14062306a36Sopenharmony_ci encoding |= DW_EH_PE_udata4; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci switch (encoding & DW_EH_PE_FORMAT_MASK) { 14362306a36Sopenharmony_ci case DW_EH_PE_sdata4: 14462306a36Sopenharmony_ci *val += dw_read(cur, s32, end); 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case DW_EH_PE_udata4: 14762306a36Sopenharmony_ci *val += dw_read(cur, u32, end); 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci case DW_EH_PE_sdata8: 15062306a36Sopenharmony_ci *val += dw_read(cur, s64, end); 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case DW_EH_PE_udata8: 15362306a36Sopenharmony_ci *val += dw_read(cur, u64, end); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci out: 16062306a36Sopenharmony_ci *p = cur; 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define dw_read_encoded_value(ptr, end, enc) ({ \ 16562306a36Sopenharmony_ci u64 __v; \ 16662306a36Sopenharmony_ci if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ 16762306a36Sopenharmony_ci return -EINVAL; \ 16862306a36Sopenharmony_ci } \ 16962306a36Sopenharmony_ci __v; \ 17062306a36Sopenharmony_ci }) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int elf_section_address_and_offset(int fd, const char *name, u64 *address, u64 *offset) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci Elf *elf; 17562306a36Sopenharmony_ci GElf_Ehdr ehdr; 17662306a36Sopenharmony_ci GElf_Shdr shdr; 17762306a36Sopenharmony_ci int ret = -1; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 18062306a36Sopenharmony_ci if (elf == NULL) 18162306a36Sopenharmony_ci return -1; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) 18462306a36Sopenharmony_ci goto out_err; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) 18762306a36Sopenharmony_ci goto out_err; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci *address = shdr.sh_addr; 19062306a36Sopenharmony_ci *offset = shdr.sh_offset; 19162306a36Sopenharmony_ci ret = 0; 19262306a36Sopenharmony_ciout_err: 19362306a36Sopenharmony_ci elf_end(elf); 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 19862306a36Sopenharmony_cistatic u64 elf_section_offset(int fd, const char *name) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci u64 address, offset = 0; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (elf_section_address_and_offset(fd, name, &address, &offset)) 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return offset; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci#endif 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic u64 elf_base_address(int fd) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci Elf *elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 21262306a36Sopenharmony_ci GElf_Phdr phdr; 21362306a36Sopenharmony_ci u64 retval = 0; 21462306a36Sopenharmony_ci size_t i, phdrnum = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (elf == NULL) 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci (void)elf_getphdrnum(elf, &phdrnum); 21962306a36Sopenharmony_ci /* PT_LOAD segments are sorted by p_vaddr, so the first has the minimum p_vaddr. */ 22062306a36Sopenharmony_ci for (i = 0; i < phdrnum; i++) { 22162306a36Sopenharmony_ci if (gelf_getphdr(elf, i, &phdr) && phdr.p_type == PT_LOAD) { 22262306a36Sopenharmony_ci retval = phdr.p_vaddr & -getpagesize(); 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci elf_end(elf); 22862306a36Sopenharmony_ci return retval; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 23262306a36Sopenharmony_cistatic int elf_is_exec(int fd, const char *name) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci Elf *elf; 23562306a36Sopenharmony_ci GElf_Ehdr ehdr; 23662306a36Sopenharmony_ci int retval = 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 23962306a36Sopenharmony_ci if (elf == NULL) 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) 24262306a36Sopenharmony_ci goto out; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci retval = (ehdr.e_type == ET_EXEC); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciout: 24762306a36Sopenharmony_ci elf_end(elf); 24862306a36Sopenharmony_ci pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); 24962306a36Sopenharmony_ci return retval; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci#endif 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistruct table_entry { 25462306a36Sopenharmony_ci u32 start_ip_offset; 25562306a36Sopenharmony_ci u32 fde_offset; 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistruct eh_frame_hdr { 25962306a36Sopenharmony_ci unsigned char version; 26062306a36Sopenharmony_ci unsigned char eh_frame_ptr_enc; 26162306a36Sopenharmony_ci unsigned char fde_count_enc; 26262306a36Sopenharmony_ci unsigned char table_enc; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* 26562306a36Sopenharmony_ci * The rest of the header is variable-length and consists of the 26662306a36Sopenharmony_ci * following members: 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * encoded_t eh_frame_ptr; 26962306a36Sopenharmony_ci * encoded_t fde_count; 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* A single encoded pointer should not be more than 8 bytes. */ 27362306a36Sopenharmony_ci u64 enc[2]; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * struct { 27762306a36Sopenharmony_ci * encoded_t start_ip; 27862306a36Sopenharmony_ci * encoded_t fde_addr; 27962306a36Sopenharmony_ci * } binary_search_table[fde_count]; 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci char data[]; 28262306a36Sopenharmony_ci} __packed; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int unwind_spec_ehframe(struct dso *dso, struct machine *machine, 28562306a36Sopenharmony_ci u64 offset, u64 *table_data_offset, u64 *fde_count) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct eh_frame_hdr hdr; 28862306a36Sopenharmony_ci u8 *enc = (u8 *) &hdr.enc; 28962306a36Sopenharmony_ci u8 *end = (u8 *) &hdr.data; 29062306a36Sopenharmony_ci ssize_t r; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci r = dso__data_read_offset(dso, machine, offset, 29362306a36Sopenharmony_ci (u8 *) &hdr, sizeof(hdr)); 29462306a36Sopenharmony_ci if (r != sizeof(hdr)) 29562306a36Sopenharmony_ci return -EINVAL; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* We dont need eh_frame_ptr, just skip it. */ 29862306a36Sopenharmony_ci dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); 30162306a36Sopenharmony_ci *table_data_offset = enc - (u8 *) &hdr; 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, 30662306a36Sopenharmony_ci u64 *table_data, u64 *segbase, 30762306a36Sopenharmony_ci u64 *fde_count) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct map_rb_node *map_node; 31062306a36Sopenharmony_ci u64 base_addr = UINT64_MAX; 31162306a36Sopenharmony_ci int ret, fd; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (dso->data.eh_frame_hdr_offset == 0) { 31462306a36Sopenharmony_ci fd = dso__data_get_fd(dso, ui->machine); 31562306a36Sopenharmony_ci if (fd < 0) 31662306a36Sopenharmony_ci return -EINVAL; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Check the .eh_frame section for unwinding info */ 31962306a36Sopenharmony_ci ret = elf_section_address_and_offset(fd, ".eh_frame_hdr", 32062306a36Sopenharmony_ci &dso->data.eh_frame_hdr_addr, 32162306a36Sopenharmony_ci &dso->data.eh_frame_hdr_offset); 32262306a36Sopenharmony_ci dso->data.elf_base_addr = elf_base_address(fd); 32362306a36Sopenharmony_ci dso__data_put_fd(dso); 32462306a36Sopenharmony_ci if (ret || dso->data.eh_frame_hdr_offset == 0) 32562306a36Sopenharmony_ci return -EINVAL; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci maps__for_each_entry(thread__maps(ui->thread), map_node) { 32962306a36Sopenharmony_ci struct map *map = map_node->map; 33062306a36Sopenharmony_ci u64 start = map__start(map) - map__pgoff(map); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (map__dso(map) == dso && start < base_addr) 33362306a36Sopenharmony_ci base_addr = start; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci base_addr -= dso->data.elf_base_addr; 33662306a36Sopenharmony_ci /* Address of .eh_frame_hdr */ 33762306a36Sopenharmony_ci *segbase = base_addr + dso->data.eh_frame_hdr_addr; 33862306a36Sopenharmony_ci ret = unwind_spec_ehframe(dso, ui->machine, dso->data.eh_frame_hdr_offset, 33962306a36Sopenharmony_ci table_data, fde_count); 34062306a36Sopenharmony_ci if (ret) 34162306a36Sopenharmony_ci return ret; 34262306a36Sopenharmony_ci /* binary_search_table offset plus .eh_frame_hdr address */ 34362306a36Sopenharmony_ci *table_data += *segbase; 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 34862306a36Sopenharmony_cistatic int read_unwind_spec_debug_frame(struct dso *dso, 34962306a36Sopenharmony_ci struct machine *machine, u64 *offset) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci int fd; 35262306a36Sopenharmony_ci u64 ofs = dso->data.debug_frame_offset; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* debug_frame can reside in: 35562306a36Sopenharmony_ci * - dso 35662306a36Sopenharmony_ci * - debug pointed by symsrc_filename 35762306a36Sopenharmony_ci * - gnu_debuglink, which doesn't necessary 35862306a36Sopenharmony_ci * has to be pointed by symsrc_filename 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci if (ofs == 0) { 36162306a36Sopenharmony_ci fd = dso__data_get_fd(dso, machine); 36262306a36Sopenharmony_ci if (fd >= 0) { 36362306a36Sopenharmony_ci ofs = elf_section_offset(fd, ".debug_frame"); 36462306a36Sopenharmony_ci dso__data_put_fd(dso); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (ofs <= 0) { 36862306a36Sopenharmony_ci fd = open(dso->symsrc_filename, O_RDONLY); 36962306a36Sopenharmony_ci if (fd >= 0) { 37062306a36Sopenharmony_ci ofs = elf_section_offset(fd, ".debug_frame"); 37162306a36Sopenharmony_ci close(fd); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (ofs <= 0) { 37662306a36Sopenharmony_ci char *debuglink = malloc(PATH_MAX); 37762306a36Sopenharmony_ci int ret = 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = dso__read_binary_type_filename( 38062306a36Sopenharmony_ci dso, DSO_BINARY_TYPE__DEBUGLINK, 38162306a36Sopenharmony_ci machine->root_dir, debuglink, PATH_MAX); 38262306a36Sopenharmony_ci if (!ret) { 38362306a36Sopenharmony_ci fd = open(debuglink, O_RDONLY); 38462306a36Sopenharmony_ci if (fd >= 0) { 38562306a36Sopenharmony_ci ofs = elf_section_offset(fd, 38662306a36Sopenharmony_ci ".debug_frame"); 38762306a36Sopenharmony_ci close(fd); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci if (ofs > 0) { 39162306a36Sopenharmony_ci if (dso->symsrc_filename != NULL) { 39262306a36Sopenharmony_ci pr_warning( 39362306a36Sopenharmony_ci "%s: overwrite symsrc(%s,%s)\n", 39462306a36Sopenharmony_ci __func__, 39562306a36Sopenharmony_ci dso->symsrc_filename, 39662306a36Sopenharmony_ci debuglink); 39762306a36Sopenharmony_ci zfree(&dso->symsrc_filename); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci dso->symsrc_filename = debuglink; 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci free(debuglink); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci dso->data.debug_frame_offset = ofs; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci *offset = ofs; 40962306a36Sopenharmony_ci if (*offset) 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return -EINVAL; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci#endif 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic struct map *find_map(unw_word_t ip, struct unwind_info *ui) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct addr_location al; 41962306a36Sopenharmony_ci struct map *ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci addr_location__init(&al); 42262306a36Sopenharmony_ci thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al); 42362306a36Sopenharmony_ci ret = map__get(al.map); 42462306a36Sopenharmony_ci addr_location__exit(&al); 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int 42962306a36Sopenharmony_cifind_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 43062306a36Sopenharmony_ci int need_unwind_info, void *arg) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct unwind_info *ui = arg; 43362306a36Sopenharmony_ci struct map *map; 43462306a36Sopenharmony_ci struct dso *dso; 43562306a36Sopenharmony_ci unw_dyn_info_t di; 43662306a36Sopenharmony_ci u64 table_data, segbase, fde_count; 43762306a36Sopenharmony_ci int ret = -EINVAL; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci map = find_map(ip, ui); 44062306a36Sopenharmony_ci if (!map) 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci dso = map__dso(map); 44462306a36Sopenharmony_ci if (!dso) { 44562306a36Sopenharmony_ci map__put(map); 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci pr_debug("unwind: find_proc_info dso %s\n", dso->name); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* Check the .eh_frame section for unwinding info */ 45262306a36Sopenharmony_ci if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count)) { 45362306a36Sopenharmony_ci memset(&di, 0, sizeof(di)); 45462306a36Sopenharmony_ci di.format = UNW_INFO_FORMAT_REMOTE_TABLE; 45562306a36Sopenharmony_ci di.start_ip = map__start(map); 45662306a36Sopenharmony_ci di.end_ip = map__end(map); 45762306a36Sopenharmony_ci di.u.rti.segbase = segbase; 45862306a36Sopenharmony_ci di.u.rti.table_data = table_data; 45962306a36Sopenharmony_ci di.u.rti.table_len = fde_count * sizeof(struct table_entry) 46062306a36Sopenharmony_ci / sizeof(unw_word_t); 46162306a36Sopenharmony_ci ret = dwarf_search_unwind_table(as, ip, &di, pi, 46262306a36Sopenharmony_ci need_unwind_info, arg); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 46662306a36Sopenharmony_ci /* Check the .debug_frame section for unwinding info */ 46762306a36Sopenharmony_ci if (ret < 0 && 46862306a36Sopenharmony_ci !read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) { 46962306a36Sopenharmony_ci int fd = dso__data_get_fd(dso, ui->machine); 47062306a36Sopenharmony_ci int is_exec = elf_is_exec(fd, dso->name); 47162306a36Sopenharmony_ci u64 start = map__start(map); 47262306a36Sopenharmony_ci unw_word_t base = is_exec ? 0 : start; 47362306a36Sopenharmony_ci const char *symfile; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (fd >= 0) 47662306a36Sopenharmony_ci dso__data_put_fd(dso); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci symfile = dso->symsrc_filename ?: dso->name; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci memset(&di, 0, sizeof(di)); 48162306a36Sopenharmony_ci if (dwarf_find_debug_frame(0, &di, ip, base, symfile, start, map__end(map))) 48262306a36Sopenharmony_ci ret = dwarf_search_unwind_table(as, ip, &di, pi, 48362306a36Sopenharmony_ci need_unwind_info, arg); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci#endif 48662306a36Sopenharmony_ci map__put(map); 48762306a36Sopenharmony_ci return ret; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int access_fpreg(unw_addr_space_t __maybe_unused as, 49162306a36Sopenharmony_ci unw_regnum_t __maybe_unused num, 49262306a36Sopenharmony_ci unw_fpreg_t __maybe_unused *val, 49362306a36Sopenharmony_ci int __maybe_unused __write, 49462306a36Sopenharmony_ci void __maybe_unused *arg) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci pr_err("unwind: access_fpreg unsupported\n"); 49762306a36Sopenharmony_ci return -UNW_EINVAL; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, 50162306a36Sopenharmony_ci unw_word_t __maybe_unused *dil_addr, 50262306a36Sopenharmony_ci void __maybe_unused *arg) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci return -UNW_ENOINFO; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int resume(unw_addr_space_t __maybe_unused as, 50862306a36Sopenharmony_ci unw_cursor_t __maybe_unused *cu, 50962306a36Sopenharmony_ci void __maybe_unused *arg) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci pr_err("unwind: resume unsupported\n"); 51262306a36Sopenharmony_ci return -UNW_EINVAL; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic int 51662306a36Sopenharmony_ciget_proc_name(unw_addr_space_t __maybe_unused as, 51762306a36Sopenharmony_ci unw_word_t __maybe_unused addr, 51862306a36Sopenharmony_ci char __maybe_unused *bufp, size_t __maybe_unused buf_len, 51962306a36Sopenharmony_ci unw_word_t __maybe_unused *offp, void __maybe_unused *arg) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci pr_err("unwind: get_proc_name unsupported\n"); 52262306a36Sopenharmony_ci return -UNW_EINVAL; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int access_dso_mem(struct unwind_info *ui, unw_word_t addr, 52662306a36Sopenharmony_ci unw_word_t *data) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct map *map; 52962306a36Sopenharmony_ci struct dso *dso; 53062306a36Sopenharmony_ci ssize_t size; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci map = find_map(addr, ui); 53362306a36Sopenharmony_ci if (!map) { 53462306a36Sopenharmony_ci pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 53562306a36Sopenharmony_ci return -1; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci dso = map__dso(map); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (!dso) { 54162306a36Sopenharmony_ci map__put(map); 54262306a36Sopenharmony_ci return -1; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci size = dso__data_read_addr(dso, map, ui->machine, 54662306a36Sopenharmony_ci addr, (u8 *) data, sizeof(*data)); 54762306a36Sopenharmony_ci map__put(map); 54862306a36Sopenharmony_ci return !(size == sizeof(*data)); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int access_mem(unw_addr_space_t __maybe_unused as, 55262306a36Sopenharmony_ci unw_word_t addr, unw_word_t *valp, 55362306a36Sopenharmony_ci int __write, void *arg) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct unwind_info *ui = arg; 55662306a36Sopenharmony_ci const char *arch = perf_env__arch(ui->machine->env); 55762306a36Sopenharmony_ci struct stack_dump *stack = &ui->sample->user_stack; 55862306a36Sopenharmony_ci u64 start, end; 55962306a36Sopenharmony_ci int offset; 56062306a36Sopenharmony_ci int ret; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Don't support write, probably not needed. */ 56362306a36Sopenharmony_ci if (__write || !stack || !ui->sample->user_regs.regs) { 56462306a36Sopenharmony_ci *valp = 0; 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ret = perf_reg_value(&start, &ui->sample->user_regs, 56962306a36Sopenharmony_ci perf_arch_reg_sp(arch)); 57062306a36Sopenharmony_ci if (ret) 57162306a36Sopenharmony_ci return ret; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci end = start + stack->size; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Check overflow. */ 57662306a36Sopenharmony_ci if (addr + sizeof(unw_word_t) < addr) 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (addr < start || addr + sizeof(unw_word_t) >= end) { 58062306a36Sopenharmony_ci ret = access_dso_mem(ui, addr, valp); 58162306a36Sopenharmony_ci if (ret) { 58262306a36Sopenharmony_ci pr_debug("unwind: access_mem %p not inside range" 58362306a36Sopenharmony_ci " 0x%" PRIx64 "-0x%" PRIx64 "\n", 58462306a36Sopenharmony_ci (void *) (uintptr_t) addr, start, end); 58562306a36Sopenharmony_ci *valp = 0; 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci offset = addr - start; 59262306a36Sopenharmony_ci *valp = *(unw_word_t *)&stack->data[offset]; 59362306a36Sopenharmony_ci pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", 59462306a36Sopenharmony_ci (void *) (uintptr_t) addr, (unsigned long)*valp, offset); 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int access_reg(unw_addr_space_t __maybe_unused as, 59962306a36Sopenharmony_ci unw_regnum_t regnum, unw_word_t *valp, 60062306a36Sopenharmony_ci int __write, void *arg) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct unwind_info *ui = arg; 60362306a36Sopenharmony_ci int id, ret; 60462306a36Sopenharmony_ci u64 val; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* Don't support write, I suspect we don't need it. */ 60762306a36Sopenharmony_ci if (__write) { 60862306a36Sopenharmony_ci pr_err("unwind: access_reg w %d\n", regnum); 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (!ui->sample->user_regs.regs) { 61362306a36Sopenharmony_ci *valp = 0; 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci id = LIBUNWIND__ARCH_REG_ID(regnum); 61862306a36Sopenharmony_ci if (id < 0) 61962306a36Sopenharmony_ci return -EINVAL; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ret = perf_reg_value(&val, &ui->sample->user_regs, id); 62262306a36Sopenharmony_ci if (ret) { 62362306a36Sopenharmony_ci if (!ui->best_effort) 62462306a36Sopenharmony_ci pr_err("unwind: can't read reg %d\n", regnum); 62562306a36Sopenharmony_ci return ret; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci *valp = (unw_word_t) val; 62962306a36Sopenharmony_ci pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void put_unwind_info(unw_addr_space_t __maybe_unused as, 63462306a36Sopenharmony_ci unw_proc_info_t *pi __maybe_unused, 63562306a36Sopenharmony_ci void *arg __maybe_unused) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci pr_debug("unwind: put_unwind_info called\n"); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int entry(u64 ip, struct thread *thread, 64162306a36Sopenharmony_ci unwind_entry_cb_t cb, void *arg) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct unwind_entry e; 64462306a36Sopenharmony_ci struct addr_location al; 64562306a36Sopenharmony_ci int ret; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci addr_location__init(&al); 64862306a36Sopenharmony_ci e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); 64962306a36Sopenharmony_ci e.ip = ip; 65062306a36Sopenharmony_ci e.ms.map = al.map; 65162306a36Sopenharmony_ci e.ms.maps = al.maps; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", 65462306a36Sopenharmony_ci al.sym ? al.sym->name : "''", 65562306a36Sopenharmony_ci ip, 65662306a36Sopenharmony_ci al.map ? map__map_ip(al.map, ip) : (u64) 0); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ret = cb(&e, arg); 65962306a36Sopenharmony_ci addr_location__exit(&al); 66062306a36Sopenharmony_ci return ret; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic void display_error(int err) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci switch (err) { 66662306a36Sopenharmony_ci case UNW_EINVAL: 66762306a36Sopenharmony_ci pr_err("unwind: Only supports local.\n"); 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci case UNW_EUNSPEC: 67062306a36Sopenharmony_ci pr_err("unwind: Unspecified error.\n"); 67162306a36Sopenharmony_ci break; 67262306a36Sopenharmony_ci case UNW_EBADREG: 67362306a36Sopenharmony_ci pr_err("unwind: Register unavailable.\n"); 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci default: 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic unw_accessors_t accessors = { 68162306a36Sopenharmony_ci .find_proc_info = find_proc_info, 68262306a36Sopenharmony_ci .put_unwind_info = put_unwind_info, 68362306a36Sopenharmony_ci .get_dyn_info_list_addr = get_dyn_info_list_addr, 68462306a36Sopenharmony_ci .access_mem = access_mem, 68562306a36Sopenharmony_ci .access_reg = access_reg, 68662306a36Sopenharmony_ci .access_fpreg = access_fpreg, 68762306a36Sopenharmony_ci .resume = resume, 68862306a36Sopenharmony_ci .get_proc_name = get_proc_name, 68962306a36Sopenharmony_ci}; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int _unwind__prepare_access(struct maps *maps) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci void *addr_space = unw_create_addr_space(&accessors, 0); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci RC_CHK_ACCESS(maps)->addr_space = addr_space; 69662306a36Sopenharmony_ci if (!addr_space) { 69762306a36Sopenharmony_ci pr_err("unwind: Can't create unwind address space.\n"); 69862306a36Sopenharmony_ci return -ENOMEM; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); 70262306a36Sopenharmony_ci return 0; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic void _unwind__flush_access(struct maps *maps) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci unw_flush_cache(maps__addr_space(maps), 0, 0); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic void _unwind__finish_access(struct maps *maps) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci unw_destroy_addr_space(maps__addr_space(maps)); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 71662306a36Sopenharmony_ci void *arg, int max_stack) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci const char *arch = perf_env__arch(ui->machine->env); 71962306a36Sopenharmony_ci u64 val; 72062306a36Sopenharmony_ci unw_word_t ips[max_stack]; 72162306a36Sopenharmony_ci unw_addr_space_t addr_space; 72262306a36Sopenharmony_ci unw_cursor_t c; 72362306a36Sopenharmony_ci int ret, i = 0; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ret = perf_reg_value(&val, &ui->sample->user_regs, 72662306a36Sopenharmony_ci perf_arch_reg_ip(arch)); 72762306a36Sopenharmony_ci if (ret) 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ips[i++] = (unw_word_t) val; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * If we need more than one entry, do the DWARF 73462306a36Sopenharmony_ci * unwind itself. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci if (max_stack - 1 > 0) { 73762306a36Sopenharmony_ci WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); 73862306a36Sopenharmony_ci addr_space = maps__addr_space(thread__maps(ui->thread)); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (addr_space == NULL) 74162306a36Sopenharmony_ci return -1; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci ret = unw_init_remote(&c, addr_space, ui); 74462306a36Sopenharmony_ci if (ret && !ui->best_effort) 74562306a36Sopenharmony_ci display_error(ret); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci while (!ret && (unw_step(&c) > 0) && i < max_stack) { 74862306a36Sopenharmony_ci unw_get_reg(&c, UNW_REG_IP, &ips[i]); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* 75162306a36Sopenharmony_ci * Decrement the IP for any non-activation frames. 75262306a36Sopenharmony_ci * this is required to properly find the srcline 75362306a36Sopenharmony_ci * for caller frames. 75462306a36Sopenharmony_ci * See also the documentation for dwfl_frame_pc(), 75562306a36Sopenharmony_ci * which this code tries to replicate. 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci if (unw_is_signal_frame(&c) <= 0) 75862306a36Sopenharmony_ci --ips[i]; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci ++i; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci max_stack = i; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* 76762306a36Sopenharmony_ci * Display what we got based on the order setup. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci for (i = 0; i < max_stack && !ret; i++) { 77062306a36Sopenharmony_ci int j = i; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (callchain_param.order == ORDER_CALLER) 77362306a36Sopenharmony_ci j = max_stack - i - 1; 77462306a36Sopenharmony_ci ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return ret; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, 78162306a36Sopenharmony_ci struct thread *thread, 78262306a36Sopenharmony_ci struct perf_sample *data, int max_stack, 78362306a36Sopenharmony_ci bool best_effort) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct unwind_info ui = { 78662306a36Sopenharmony_ci .sample = data, 78762306a36Sopenharmony_ci .thread = thread, 78862306a36Sopenharmony_ci .machine = maps__machine(thread__maps(thread)), 78962306a36Sopenharmony_ci .best_effort = best_effort 79062306a36Sopenharmony_ci }; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!data->user_regs.regs) 79362306a36Sopenharmony_ci return -EINVAL; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (max_stack <= 0) 79662306a36Sopenharmony_ci return -EINVAL; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return get_entries(&ui, cb, arg, max_stack); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic struct unwind_libunwind_ops 80262306a36Sopenharmony_ci_unwind_libunwind_ops = { 80362306a36Sopenharmony_ci .prepare_access = _unwind__prepare_access, 80462306a36Sopenharmony_ci .flush_access = _unwind__flush_access, 80562306a36Sopenharmony_ci .finish_access = _unwind__finish_access, 80662306a36Sopenharmony_ci .get_entries = _unwind__get_entries, 80762306a36Sopenharmony_ci}; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci#ifndef REMOTE_UNWIND_LIBUNWIND 81062306a36Sopenharmony_cistruct unwind_libunwind_ops * 81162306a36Sopenharmony_cilocal_unwind_libunwind_ops = &_unwind_libunwind_ops; 81262306a36Sopenharmony_ci#endif 813