diff --git a/source/ucli_py/libunwind/Makefile b/source/ucli_py/libunwind/Makefile new file mode 100644 index 0000000..2c7ba94 --- /dev/null +++ b/source/ucli_py/libunwind/Makefile @@ -0,0 +1,18 @@ +TARGET_SO=libunwind.so +SOURCES=unwind.cc symbol.cc +OBJECTS=$(SOURCES:.cc=.o) + +INCLUDES=-I. + +CFLAGS=-g -O0 -fPIC + +LFLAGS=-shared + +%.o: %.cc + $(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +$(TARGET_SO): $(OBJECTS) + $(CXX) $(LFLAGS) $^ -o $@ + +clean: + rm -f $(TARGET_SO) $(OBJECTS) \ No newline at end of file diff --git a/source/ucli_py/libunwind/accessors.cc b/source/ucli_py/libunwind/accessors.cc new file mode 100644 index 0000000..5c39a98 --- /dev/null +++ b/source/ucli_py/libunwind/accessors.cc @@ -0,0 +1,483 @@ +#include +#include // for GElf_Ehdr | Elf +#include +#include + +#include "unwind.h" + +extern "C" { +int UNW_OBJ(dwarf_search_unwind_table)(unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +} + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ +#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ + +/* Pointer-encoding formats: */ +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ +#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ +#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ +#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ +#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ + +/* Pointer-encoding application: */ +#define DW_EH_PE_absptr 0x00 /* absolute value */ +#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ + +unw_accessors_t accessors = { + .find_proc_info = find_proc_info, + .put_unwind_info = put_unwind_info, + .get_dyn_info_list_addr = get_dyn_info_list_addr, + .access_mem = access_mem, + .access_reg = access_reg, + .access_fpreg = access_fpreg, + .resume = resume, + .get_proc_name = get_proc_name, +}; + +static vma *find_map(unw_word_t ip, struct unwind_info *ui) { + return ui->sp->find_vma(ui->pid, ip); +} + +static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, GElf_Shdr *shp, + const char *name) { + Elf_Scn *sec = NULL; + + while ((sec = elf_nextscn(elf, sec)) != NULL) { + char *str; + + gelf_getshdr(sec, shp); + str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); + if (!strcmp(name, str)) break; + } + + return sec; +} + +static u64 elf_section_offset(int fd, const char *name) { + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + u64 offset = 0; + + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) return 0; + + do { + if (gelf_getehdr(elf, &ehdr) == NULL) break; + + if (!elf_section_by_name(elf, &ehdr, &shdr, name)) break; + + offset = shdr.sh_offset; + } while (0); + + elf_end(elf); + return offset; +} + +struct eh_frame_hdr { + unsigned char version; + unsigned char eh_frame_ptr_enc; + unsigned char fde_count_enc; + unsigned char table_enc; + + /* + * The rest of the header is variable-length and consists of the + * following members: + * + * encoded_t eh_frame_ptr; + * encoded_t fde_count; + */ + + /* A single encoded pointer should not be more than 8 bytes. */ + u64 enc[2]; + + /* + * struct { + * encoded_t start_ip; + * encoded_t fde_addr; + * } binary_search_table[fde_count]; + */ + char data[0]; +} __attribute__((__packed__)); + +ssize_t dso_read(vma *dso, u64 offset, u8 *data, ssize_t size) { + ssize_t ret = -1; + int fd; + + fd = dso_data_fd(dso); + if (fd < 0) return -1; + + do { + if (-1 == lseek(fd, offset, SEEK_SET)) break; + + ret = read(fd, data, size); + if (ret <= 0) break; + } while (0); + + close(fd); + return ret; +} + +ssize_t dso__data_read_offset(vma *dso, u64 offset, u8 *data, ssize_t size) { + ssize_t r = 0; + u8 *p = data; + + do { + ssize_t ret; + ret = dso_read(dso, offset, p, size); + if (ret <= 0) { + return -1; + } + if (ret > size) { + return -1; + } + r += ret; + p += ret; + offset += ret; + size -= ret; + } while (size); + return r; +} + +#define dw_read(ptr, type, end) \ + ({ \ + type *__p = (type *)ptr; \ + type __v; \ + if ((__p + 1) > (type *)end) return -EINVAL; \ + __v = *__p++; \ + ptr = (typeof(ptr))__p; \ + __v; \ + }) + +static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, u8 encoding) { + u8 *cur = *p; + *val = 0; + + switch (encoding) { + case DW_EH_PE_omit: + *val = 0; + goto out; + case DW_EH_PE_ptr: + *val = dw_read(cur, unsigned long, end); + goto out; + default: + break; + } + + switch (encoding & DW_EH_PE_APPL_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *val = (unsigned long)cur; + break; + default: + return -EINVAL; + } + + if ((encoding & 0x07) == 0x00) encoding |= DW_EH_PE_udata4; + + switch (encoding & DW_EH_PE_FORMAT_MASK) { + case DW_EH_PE_sdata4: + *val += dw_read(cur, s32, end); + break; + case DW_EH_PE_udata4: + *val += dw_read(cur, u32, end); + break; + case DW_EH_PE_sdata8: + *val += dw_read(cur, s64, end); + break; + case DW_EH_PE_udata8: + *val += dw_read(cur, u64, end); + break; + default: + return -EINVAL; + } + +out: + *p = cur; + return 0; +} + +#define dw_read_encoded_value(ptr, end, enc) \ + ({ \ + u64 __v; \ + if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ + return -EINVAL; \ + } \ + __v; \ + }) + +static int unwind_spec_ehframe(vma *dso, u64 offset, u64 *table_data, + u64 *segbase, u64 *fde_count) { + struct eh_frame_hdr hdr; + u8 *enc = (u8 *)&hdr.enc; + u8 *end = (u8 *)&hdr.data; + ssize_t r; + + r = dso__data_read_offset(dso, offset, (u8 *)&hdr, sizeof(hdr)); + if (r != sizeof(hdr)) { + return -EINVAL; + } + + /* We dont need eh_frame_ptr, just skip it. */ + dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); + + *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); + *segbase = offset; + *table_data = (enc - (u8 *)&hdr) + offset; + + return 0; +} + +int dso_data_fd(vma *dso) { return open(dso->name.c_str(), O_RDONLY); } + +static int read_unwind_spec(vma *dso, u64 *table_data, u64 *segbase, + u64 *fde_count) { + int ret = -EINVAL, fd; + + if (dso->eh_frame_hdr_offset == 0 && dso->elf_read_error == 0) { + fd = dso_data_fd(dso); + if (fd < 0) return -EINVAL; + + dso->eh_frame_hdr_offset = elf_section_offset(fd, ".eh_frame_hdr"); + close(fd); + ret = unwind_spec_ehframe(dso, dso->eh_frame_hdr_offset, &dso->table_data, + &dso->eh_frame_hdr_offset, &dso->fde_count); + if (ret != 0) { + dso->eh_frame_hdr_offset = 0; + dso->elf_read_error = 1; + return -EINVAL; + } + } + + *table_data = dso->table_data; + *segbase = dso->eh_frame_hdr_offset; + *fde_count = dso->fde_count; + + /* TODO .debug_frame check if eh_frame_hdr fails */ + return 0; +} + +struct table_entry { + u32 start_ip_offset; + u32 fde_offset; +}; + +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, + void *arg) { + struct unwind_info *ui = (struct unwind_info *)arg; + unw_dyn_info_t di; + u64 table_data, segbase, fde_count; + + vma *map; + map = find_map(ip, ui); + if (!map) { + return -EINVAL; + } + + if (!read_unwind_spec(map, &table_data, &segbase, &fde_count)) { + memset(&di, 0, sizeof(di)); + di.format = UNW_INFO_FORMAT_REMOTE_TABLE; + di.start_ip = map->start; + di.end_ip = map->end; + di.u.rti.segbase = map->start + segbase; + di.u.rti.table_data = map->start + table_data; + di.u.rti.table_len = + fde_count * sizeof(struct table_entry) / sizeof(unw_word_t); + return dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg); + } + // return -EINVAL; + return -UNW_ENOINFO; +} + +static void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pi, + void *arg) { + // pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dil_addr, + void *arg) { + return -UNW_ENOINFO; +} + +ssize_t dso__data_read_addr(vma *map, u64 addr, u8 *data, ssize_t size) { + u64 offset; + + if (map->name.size() > 0 && map->name[0] != '/') return 0; + + offset = addr - map->start + map->offset; + return dso__data_read_offset(map, offset, data, size); +} + +struct map *last_map = NULL; +static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, + unw_word_t *data) { + ssize_t size; + + // ip in the first page is invalid + if (addr == 0 || addr == (unsigned long)(-1) || (long)addr < 4096) { + return -UNW_ENOINFO; + } + + vma *map; + map = find_map(addr, ui); + if (!map) { + return -UNW_ENOINFO; + } + + if (map->type != NATIVE_TYPE) { + return -UNW_ENOINFO; + } + + size = dso__data_read_addr(map, addr, (u8 *)data, sizeof(*data)); + + return !(size == sizeof(*data)); +} + +/* + * Optimization point. + */ +static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) { + /* we only support 3 registers. RIP, RSP and RBP */ + if (id < 0 || id > 2) return -EINVAL; + + *valp = regs->regs[id]; + return 0; +} + +unw_word_t last_addr = 0; +unw_word_t last_val = 0; +int stack_offset = 0; + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, + int __write, void *arg) { + struct unwind_info *ui = (struct unwind_info *)arg; + struct stack_dump *stack = &ui->sample->user_stack; + unw_word_t start, end; + int offset; + int ret; + + if (addr == last_addr) { + (*valp) = last_val; + return 0; + } + + last_addr = addr; + + /* Don't support write, probably not needed. */ + if (__write || !stack || !ui->sample->user_regs.regs) { + *valp = 0; + // fprintf(stderr, "access_mem: __write memory\n"); + last_val = *valp; + return 0; + } + + /* start is the SP */ + ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); + if (ret) { + // fprintf(stderr, "access_mem: reg_value error (ret: %d)\n", ret); + return ret; + } + + end = start + stack->size; + + /* Check overflow. */ + if (addr + sizeof(unw_word_t) < addr) { + // fprintf(stderr, "access_mem: Check overflow.\n"); + return -EINVAL; + } + + if (addr < start || addr + sizeof(unw_word_t) >= end) { + ret = access_dso_mem(ui, addr, valp); + if (ret) { + // pr_debug("unwind: access_mem %p not inside range %p-%p\n", + // (void *)addr, (void *)start, (void *)end); + *valp = 0; + last_val = 0; + return ret; + } + last_val = *valp; + return 0; + } + + offset = addr - start; + *valp = *(unw_word_t *)&stack->data[offset]; + last_val = *valp; + stack_offset = offset; + + // pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n", + // (void *)addr, (unsigned long)*valp, offset); + return 0; +} + +int unwind__arch_reg_id(int regnum) { + int id; + + switch (regnum) { + case UNW_X86_64_RBP: + id = PERF_REG_BP; + break; + case UNW_X86_64_RSP: + id = PERF_REG_SP; + break; + case UNW_X86_64_RIP: + id = PERF_REG_IP; + break; + default: + return -EINVAL; + } + + return id; +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, + unw_word_t *valp, int __write, void *arg) { + struct unwind_info *ui = (struct unwind_info *)arg; + int id, ret; + + /* Don't support write, I suspect we don't need it. */ + if (__write) { + // pr_err("unwind: access_reg w %d\n", regnum); + return 0; + } + + if (!ui->sample->user_regs.regs) { + *valp = 0; + return 0; + } + + id = unwind__arch_reg_id(regnum); + if (id < 0) { + // fprintf(stderr, "Cannot get reg: %d\n", regnum); + return -EINVAL; + } + + ret = reg_value(valp, &ui->sample->user_regs, id); + if (ret) { + // pr_err("unwind: can't read reg %d\n", regnum); + return ret; + } + + // pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); + return 0; +} + +static int access_fpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val, + int __write, void *arg) { + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg) { + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp, + size_t buf_len, unw_word_t *offp, void *arg) { + return -UNW_EINVAL; +} \ No newline at end of file diff --git a/source/ucli_py/libunwind/symbol.cc b/source/ucli_py/libunwind/symbol.cc new file mode 100644 index 0000000..e3e03a5 --- /dev/null +++ b/source/ucli_py/libunwind/symbol.cc @@ -0,0 +1,32 @@ +#include "symbol.h" + +symbol_parser g_symbol_parser; + +bool symbol_parser::find_vma(pid_t pid, vma &vm) +{ + std::map::iterator proc_vma_map; + + proc_vma_map = machine_vma.find(pid); + if (proc_vma_map == machine_vma.end()) { + return false; + } + + proc_vma::const_iterator vma_iter = proc_vma_map->second.upper_bound(vm.pc); + if (vma_iter == proc_vma_map->second.end()) { + return false; + } + if (vma_iter->second.end < vm.pc) { + return false; + } + + if (vma_iter != proc_vma_map->second.begin()) { + --vma_iter; + } + + vm.start = vma_iter->second.start; + vm.end = vma_iter->second.end; + vm.name = vma_iter->second.name; + vm.offset = vma_iter->second.offset; + + return true; +} \ No newline at end of file diff --git a/source/ucli_py/unwind/symbol.h b/source/ucli_py/libunwind/symbol.h similarity index 88% rename from source/ucli_py/unwind/symbol.h rename to source/ucli_py/libunwind/symbol.h index 52a3855..b32180c 100644 --- a/source/ucli_py/unwind/symbol.h +++ b/source/ucli_py/libunwind/symbol.h @@ -1,21 +1,7 @@ -/* - * Linux内核诊断工具--用户态符号表解析 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#ifndef __PERF_SYMBOL_H__ -#define __PERF_SYMBOL_H__ - #include #include #include -//#include - #define INVALID_ADDR ((size_t)(-1)) enum { NATIVE_TYPE = 0, @@ -55,25 +41,6 @@ struct elf_file { } }; -struct symbol { - size_t start; - size_t end; - size_t ip; - std::string name; - - symbol() :start(0), end(0), ip(0) {} - symbol(size_t pc) :start(0), end(0), ip(pc) {} - - void reset(size_t va) { start = end = 0; ip = va; } - bool operator< (const symbol &sym) const { - return sym.ip < start; - } - - bool operator> (const symbol &sym) const { - return sym.ip > end; - } -}; - struct vma { size_t start; size_t end; @@ -117,9 +84,24 @@ struct vma { } }; -static inline bool operator==(const vma &lhs, const vma &rhs) { - return lhs.start == rhs.start && lhs.end == rhs.end && lhs.name == rhs.name; -} +struct symbol { + size_t start; + size_t end; + size_t ip; + std::string name; + + symbol() :start(0), end(0), ip(0) {} + symbol(size_t pc) :start(0), end(0), ip(pc) {} + + void reset(size_t va) { start = end = 0; ip = va; } + bool operator< (const symbol &sym) const { + return sym.ip < start; + } + + bool operator> (const symbol &sym) const { + return sym.ip > end; + } +}; class symbol_parser { private: @@ -159,6 +141,4 @@ public: int user_symbol; }; -extern symbol_parser g_symbol_parser; - -#endif +extern symbol_parser g_symbol_parser; \ No newline at end of file diff --git a/source/ucli_py/libunwind/unwind.cc b/source/ucli_py/libunwind/unwind.cc new file mode 100644 index 0000000..fa2a972 --- /dev/null +++ b/source/ucli_py/libunwind/unwind.cc @@ -0,0 +1,131 @@ +#include "unwind.h" + +#include +#include + +#include + +static std::string unknow_symbol("UNKNOWN"); + +static int unwind_frame_callback(struct unwind_entry *entry, void *arg) { + //! todo: 未实现 + symbol sym; + std::string symbol; // Use std::string instead of string + elf_file file; + + sym.reset(entry->ip); + + if (g_symbol_parser.find_symbol_in_cache(entry->pid, entry->ip, symbol)) { + printf("#~ 0x%lx %s ([symbol])\n", entry->ip, symbol.c_str()); + return 0; + } + + if (g_symbol_parser.get_symbol_info(entry->pid, sym, file)) { + if (g_symbol_parser.find_elf_symbol(sym, file, entry->pid, entry->pid_ns)) { + printf("#~ 0x%lx %s ([symbol])\n", entry->ip, sym.name.c_str()); + g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, sym.name); + } else { + printf("#~ 0x%lx %s ([symbol])\n", entry->ip, "(unknown)[symbol]"); + g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, unknow_symbol); + } + } else { + printf("#~ 0x%lx %s ([symbol])\n", entry->ip, "(unknown)[vma,elf]"); + g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, unknow_symbol); + } + + return 0; +} +/* + * Optimization point. + */ +static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) { + /* we only support 3 registers. RIP, RSP and RBP */ + if (id < 0 || id > 2) return -EINVAL; + + *valp = regs->regs[id]; + return 0; +} + +static int entry(u64 ip, int pid, int pid_ns, unwind_entry_cb_t cb, void *arg) { + struct unwind_entry e; + + e.ip = ip; + e.pid = pid; + e.pid_ns = pid_ns; + + return cb(&e, arg); +} + +static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, + void *arg) { + unw_addr_space_t addr_space; + unw_cursor_t c; + entry_cb_arg_t *cb_arg = (entry_cb_arg_t *)arg; + int ret; + int loops = 0; + + addr_space = unw_create_addr_space(&accessors, 0); + if (!addr_space) { + // pr_err("unwind: Can't create unwind address space.\n"); + return -ENOMEM; + } + + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + + ret = unw_init_remote(&c, addr_space, ui); /* @ui is args */ + + while (!ret && (unw_step(&c) > 0)) { + unw_word_t ip; + + unw_get_reg(&c, UNW_REG_IP, &ip); // get IP from current step; + cb_arg->arg = &c; + ret = entry(ip, ui->pid, ui->pid_ns, cb, cb_arg); + + loops++; + if (loops >= 50) break; + } + + unw_destroy_addr_space(addr_space); + return ret; +} + +int unwind__get_entries(unwind_entry_cb_t cb, void *arg, symbol_parser *sp, + int pid, int pid_ns, struct perf_sample *data) { + unw_word_t ip; + struct unwind_info ui = { + .sample = data, + .pid = pid, + .pid_ns = pid_ns, + .sp = sp, + }; + int ret; + + if (!data->user_regs.regs) return -EINVAL; + + ret = reg_value(&ip, &data->user_regs, PERF_REG_IP); + if (ret) return ret; + + ret = entry(ip, pid, pid_ns, cb, arg); + if (ret) return -ENOMEM; + + return get_entries(&ui, cb, arg); +} + +void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, + raw_stack_detail *raw_stack, int attach) { + struct perf_sample stack_sample; + entry_cb_arg_t unwind_arg; + static u64 regs_buf[3]; + + printf(" 用户态堆栈SP:%lx, BP:%lx, IP:%lx\n", raw_stack->sp, + raw_stack->bp, raw_stack->ip); + stack_sample.user_stack.offset = 0; + stack_sample.user_stack.size = raw_stack->stack_size; + stack_sample.user_stack.data = (char *)&raw_stack->stack[0]; + stack_sample.user_regs.regs = regs_buf; + stack_sample.user_regs.regs[PERF_REG_IP] = raw_stack->ip; + stack_sample.user_regs.regs[PERF_REG_SP] = raw_stack->sp; + stack_sample.user_regs.regs[PERF_REG_BP] = raw_stack->bp; + unwind__get_entries(unwind_frame_callback, &unwind_arg, &g_symbol_parser, pid, + ns_pid, &stack_sample); +} \ No newline at end of file diff --git a/source/ucli_py/libunwind/unwind.h b/source/ucli_py/libunwind/unwind.h new file mode 100644 index 0000000..7c5623a --- /dev/null +++ b/source/ucli_py/libunwind/unwind.h @@ -0,0 +1,103 @@ +#include +#include +#include + +#include "symbol.h" + +#define DIAG_USER_STACK_SIZE (16 * 1024) + +typedef unsigned long u64; +typedef unsigned char u8; +typedef unsigned int u32; +typedef long s64; +typedef char s8; +typedef int s32; + +typedef struct { + struct pt_regs regs; + unsigned long ip; + unsigned long bp; + unsigned long sp; + unsigned long stack_size; + unsigned long stack[DIAG_USER_STACK_SIZE / sizeof(unsigned long)]; +} raw_stack_detail; + +struct regs_dump { + u64 *regs; +}; + +struct ip_callchain { + u64 nr; + u64 ips[0]; +}; + +struct branch_flags { + u64 mispred : 1; + u64 predicted : 1; + u64 reserved : 62; +}; + +struct branch_entry { + u64 from; + u64 to; + struct branch_flags flags; +}; + +struct branch_stack { + u64 nr; + struct branch_entry entries[0]; +}; + +struct stack_dump { + unsigned short offset; + u64 size; + char *data; +}; + +struct perf_sample { + u64 ip; + u32 pid, tid; + u64 time; + u64 addr; + u64 id; + u64 stream_id; + u64 period; + u32 cpu; + u32 raw_size; + void *raw_data; + struct ip_callchain *callchain; + struct branch_stack *branch_stack; + struct regs_dump user_regs; + struct stack_dump user_stack; +}; + +#define PERF_REG_IP 0 +#define PERF_REG_SP 1 +#define PERF_REG_BP 2 + +struct unwind_entry { + int pid; + int pid_ns; + u64 ip; + struct vma *map; +}; + +typedef struct { + struct perf_sample *stack_sample; + void *arg; +} entry_cb_arg_t; + +typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); + +// unw_create_addr_space need +extern unw_accessors_t accessors; + +struct unwind_info { + struct perf_sample *sample; + int pid; + int pid_ns; + symbol_parser *sp; +}; + +void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, + raw_stack_detail *raw_stack, int attach); \ No newline at end of file diff --git a/source/ucli_py/unwind/Makefile b/source/ucli_py/unwind/Makefile deleted file mode 100644 index 56df97f..0000000 --- a/source/ucli_py/unwind/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# Specify the compiler -CXX=g++ - -# Specify the target -TARGET=libunwind.so - -# List of source files -SRCS=symbol.cc unwind.cc - -# List of object files -OBJS=$(SRCS:.cc=.o) - -# Compilation flags -CXXFLAGS=-fPIC -c -Wall - -# Default target -all: $(TARGET) - -# Rule to link the target -$(TARGET): $(OBJS) - $(CXX) -shared -o $@ $^ - -# Rule to compile source files -%.o: %.cc - $(CXX) $(CXXFLAGS) $< -o $@ - -# Rule to clean intermediate files -clean: - rm -f $(OBJS) $(TARGET) \ No newline at end of file diff --git a/source/ucli_py/unwind/elf.cc b/source/ucli_py/unwind/elf.cc deleted file mode 100644 index b4901e2..0000000 --- a/source/ucli_py/unwind/elf.cc +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Linux内核诊断工具--elf相关公共函数 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "elf.h" -#include "attach.h" -#include "internal.h" - -#define NOTE_ALIGN(n) (((n) + 3) & -4U) - -struct sym_section_ctx { - Elf_Data *syms; - Elf_Data *symstrs; - Elf_Data *rel_data; - int is_reloc; - int is_plt; - int sym_count; - int plt_rel_type; - unsigned long plt_offset; - unsigned long plt_entsize; -}; - -struct symbol_sections_ctx { - sym_section_ctx symtab; - sym_section_ctx symtab_in_dynsym; - sym_section_ctx dynsymtab; -}; - -struct section_info { - Elf_Scn *sec; - GElf_Shdr *hdr; -}; - -struct plt_ctx { - section_info dynsym; - section_info plt_rel; - section_info plt; -}; - -__attribute__((unused)) static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, - GElf_Shdr *shp, const char *name, - size_t *idx) { - Elf_Scn *sec = NULL; - size_t cnt = 1; - - /* Elf is corrupted/truncated, avoid calling elf_strptr. */ - if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) - return NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) { - char *str; - - gelf_getshdr(sec, shp); - str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); - - if (!strcmp(name, str)) { - if (idx) - *idx = cnt; - - break; - } - - ++cnt; - } - - return sec; -} - -__attribute__((unused)) static int elf_read_build_id(Elf *elf, char *bf, size_t size) { - int err = -1; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - Elf_Data *data; - Elf_Scn *sec; - Elf_Kind ek; - char *ptr; - - if (size < BUILD_ID_SIZE) - goto out; - - ek = elf_kind(elf); - - if (ek != ELF_K_ELF) - goto out; - - if (gelf_getehdr(elf, &ehdr) == NULL) { - fprintf(stderr, "%s: cannot get elf header.\n", __func__); - goto out; - } - - /* - * Check following sections for notes: - * '.note.gnu.build-id' - * '.notes' - * '.note' (VDSO specific) - */ - do { - sec = elf_section_by_name(elf, &ehdr, &shdr, - ".note.gnu.build-id", NULL); - - if (sec) - break; - - sec = elf_section_by_name(elf, &ehdr, &shdr, - ".notes", NULL); - - if (sec) - break; - - sec = elf_section_by_name(elf, &ehdr, &shdr, - ".note", NULL); - - if (sec) - break; - - return err; - - } while (0); - - data = elf_getdata(sec, NULL); - - if (data == NULL) - goto out; - - ptr = (char *)data->d_buf; - - while ((intptr_t)ptr < (intptr_t)((char *)data->d_buf + data->d_size)) { - GElf_Nhdr *nhdr = (GElf_Nhdr *)ptr; - size_t namesz = NOTE_ALIGN(nhdr->n_namesz), - descsz = NOTE_ALIGN(nhdr->n_descsz); - const char *name; - - ptr += sizeof(*nhdr); - name = (const char *)ptr; - ptr += namesz; - - if (nhdr->n_type == NT_GNU_BUILD_ID && - nhdr->n_namesz == sizeof("GNU")) { - if (memcmp(name, "GNU", sizeof("GNU")) == 0) { - size_t sz = size < descsz ? size : descsz; - memcpy(bf, ptr, sz); - memset(bf + sz, 0, size - sz); - err = descsz; - break; - } - } - - ptr += descsz; - } - -out: - return err; -} - -extern int calc_sha1_1M(const char *filename, unsigned char *buf); - -int filename__read_build_id(int pid, const char *mnt_ns_name, const char *filename, char *bf, size_t size) { - int fd, err = -1; - struct stat sb; - - if (size < BUILD_ID_SIZE) - goto out; - - fd = open(filename, O_RDONLY); - - if (fd < 0) - goto out; - - if (fstat(fd, &sb) == 0) { - snprintf(bf, size, "%s[%lu]", filename, sb.st_size); - err = 0; - } - - close(fd); -out: - return err; -} - -static int is_function(const GElf_Sym *sym) -{ - return GELF_ST_TYPE(sym->st_info) == STT_FUNC && - sym->st_name != 0 && - sym->st_shndx != SHN_UNDEF; -} - -static int get_symbols_in_section(sym_section_ctx *sym, Elf *elf, Elf_Scn *sec, GElf_Shdr *shdr, int is_reloc) -{ - sym->syms = elf_getdata(sec, NULL); - if (!sym->syms) { - return -1; - } - - Elf_Scn *symstrs_sec = elf_getscn(elf, shdr->sh_link); - if (!sec) { - return -1; - } - - sym->symstrs = elf_getdata(symstrs_sec, NULL); - if (!sym->symstrs) { - return -1; - } - - sym->sym_count = shdr->sh_size / shdr->sh_entsize; - sym->is_plt = 0; - sym->is_reloc = is_reloc; - - return 0; -} - -static int get_plt_symbols_in_section(sym_section_ctx *sym, Elf *elf, plt_ctx *plt) -{ - sym->syms = elf_getdata(plt->dynsym.sec, NULL); - if (!sym->syms) { - return -1; - } - - sym->rel_data = elf_getdata(plt->plt_rel.sec, NULL); - if (!sym->rel_data) { - return -1; - } - - Elf_Scn *symstrs_sec = elf_getscn(elf, plt->dynsym.hdr->sh_link); - if (!symstrs_sec) { - return -1; - } - - sym->symstrs = elf_getdata(symstrs_sec, NULL); - if (!sym->symstrs) { - return -1; - } - - sym->is_plt = 1; - sym->plt_entsize = plt->plt.hdr->sh_type; - sym->plt_offset = plt->plt.hdr->sh_offset; - sym->sym_count = plt->plt_rel.hdr->sh_size / plt->plt_rel.hdr->sh_entsize; - sym->plt_rel_type = plt->plt_rel.hdr->sh_type; - - return 0; -} - -static void __get_plt_symbol(std::set &ss, symbol_sections_ctx *si, Elf *elf) -{ - symbol s; - GElf_Sym sym; - int symidx; - int index = 0; - const char *sym_name = NULL; - - s.end = 0; - s.start = 0; - - if (!si->dynsymtab.syms) { - return; - } - - while (index < si->dynsymtab.sym_count) { - if (si->dynsymtab.plt_rel_type == SHT_RELA) { - GElf_Rela pos_mem, *pos; - pos = gelf_getrela(si->dynsymtab.rel_data, index, &pos_mem); - symidx = GELF_R_SYM(pos->r_info); - } - else if (si->dynsymtab.plt_rel_type == SHT_REL) { - GElf_Rel pos_mem, *pos; - pos = gelf_getrel(si->dynsymtab.rel_data, index, &pos_mem); - symidx = GELF_R_SYM(pos->r_info); - } - else { - return; - } - index++; - si->dynsymtab.plt_offset += si->dynsymtab.plt_entsize; - gelf_getsym(si->dynsymtab.syms, symidx, &sym); - - sym_name = (const char *)si->dynsymtab.symstrs->d_buf + sym.st_name; - s.start = si->dynsymtab.plt_offset; - s.end = s.start + si->dynsymtab.plt_entsize; - s.ip = s.start; - s.name = sym_name; - ss.insert(s); - } -} - -static void __get_symbol_without_plt(std::set &ss, sym_section_ctx *tab, Elf *elf) -{ - GElf_Sym sym; - int index = 0; - const char *sym_name; - symbol s; - s.end = 0; - s.start = 0; - - while (index < tab->sym_count) { - gelf_getsym(tab->syms, index, &sym); - index++; - if (sym.st_shndx == SHN_ABS) { - continue; - } - if (!is_function(&sym)) { - continue; - } - sym_name = (const char *)tab->symstrs->d_buf + sym.st_name; - if (tab->is_reloc) { - Elf_Scn *sec = elf_getscn(elf, sym.st_shndx); - if (!sec) { - continue; - } - GElf_Shdr shdr; - gelf_getshdr(sec, &shdr); - sym.st_value -= shdr.sh_addr - shdr.sh_offset; - } - s.start = sym.st_value & 0xffffffff; - s.end = s.start + sym.st_size; - s.ip = s.start; - s.name = sym_name; - ss.insert(s); - } -} - -static void __get_symbol(std::set &ss, symbol_sections_ctx *si, Elf *elf) -{ - symbol s; - s.end = 0; - s.start = 0; - - if (!si->symtab.syms && !si->dynsymtab.syms) { - return; - } - - sym_section_ctx *tab = &si->symtab; - __get_symbol_without_plt(ss, tab, elf); - tab = &si->symtab_in_dynsym; - __get_symbol_without_plt(ss, tab, elf); -} - -static void get_all_symbols(std::set &ss, symbol_sections_ctx *si, Elf *elf) -{ - __get_symbol(ss, si, elf); - __get_plt_symbol(ss, si, elf); -} - -bool search_symbol(const std::set &ss, symbol &sym) -{ - std::set::const_iterator it = ss.find(sym); - - if (it != ss.end()) { - sym.end = it->end; - sym.start = it->start; - sym.name = it->name; - - return true; - } - - return false; -} - -bool get_symbol_from_elf(std::set &ss, const char *path) -{ - static int first_init = 0; - - if (!first_init) { - first_init = true; - init_global_env(); - } - - int is_reloc = 0; - elf_version(EV_CURRENT); - int fd = open(path, O_RDONLY); - - Elf *elf = elf_begin(fd, ELF_C_READ, NULL); - if (elf == NULL) { - close(fd); - return false; - } - - Elf_Kind ek = elf_kind(elf); - if (ek != ELF_K_ELF) { - elf_end(elf); - close(fd); - return false; - } - GElf_Ehdr hdr; - if (gelf_getehdr(elf, &hdr) == NULL) { - elf_end(elf); - close(fd); - return false; - } - - if (hdr.e_type == ET_EXEC) { - is_reloc = 1; - } - - if (!elf_rawdata(elf_getscn(elf, hdr.e_shstrndx), NULL)) { - elf_end(elf); - close(fd); - return false; - } - - GElf_Shdr shdr; - GElf_Shdr symtab_shdr; - GElf_Shdr dynsym_shdr; - GElf_Shdr plt_shdr; - GElf_Shdr plt_rel_shdr; - memset(&shdr, 0, sizeof(shdr)); - memset(&symtab_shdr, 0, sizeof(symtab_shdr)); - memset(&dynsym_shdr, 0, sizeof(dynsym_shdr)); - memset(&plt_shdr, 0, sizeof(plt_shdr)); - memset(&plt_rel_shdr, 0, sizeof(plt_rel_shdr)); - - Elf_Scn *sec = NULL; - Elf_Scn *dynsym_sec = NULL; - Elf_Scn *symtab_sec = NULL; - Elf_Scn *plt_sec = NULL; - Elf_Scn *plt_rel_sec = NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) { - char *str; - gelf_getshdr(sec, &shdr); - str = elf_strptr(elf, hdr.e_shstrndx, shdr.sh_name); - - if (str && strcmp(".symtab", str) == 0) { - symtab_sec = sec; - memcpy(&symtab_shdr, &shdr, sizeof(dynsym_shdr)); - } - if (str && strcmp(".dynsym", str) == 0) { - dynsym_sec = sec; - memcpy(&dynsym_shdr, &shdr, sizeof(dynsym_shdr)); - } - if (str && strcmp(".rela.plt", str) == 0) { - plt_rel_sec = sec; - memcpy(&plt_rel_shdr, &shdr, sizeof(plt_rel_shdr)); - } - if (str && strcmp(".plt", str) == 0) { - plt_sec = sec; - memcpy(&plt_shdr, &shdr, sizeof(plt_shdr)); - } - if (str && strcmp(".gnu.prelink_undo", str) == 0) { - is_reloc = 1; - } - } - - plt_ctx plt; - plt.dynsym.hdr = &dynsym_shdr; - plt.dynsym.sec = dynsym_sec; - plt.plt.hdr = &plt_shdr; - plt.plt.sec = plt_sec; - plt.plt_rel.hdr = &plt_rel_shdr; - plt.plt_rel.sec = plt_rel_sec; - - symbol_sections_ctx si; - memset(&si, 0, sizeof(si)); - if (symtab_sec) { - get_symbols_in_section(&si.symtab, elf, symtab_sec, &symtab_shdr, is_reloc); - } - if (dynsym_sec) { - get_symbols_in_section(&si.symtab_in_dynsym, elf, dynsym_sec, &dynsym_shdr, is_reloc); - } - if (dynsym_sec && plt_sec) { - get_plt_symbols_in_section(&si.dynsymtab, elf, &plt); - } - - get_all_symbols(ss, &si, elf); - elf_end(elf); - close(fd); - return true; -} - -struct symbol_cache_item { - int start; - int size; - char name[0]; -}; - -bool save_symbol_cache(std::set &ss, const char *path) -{ - char buf[2048]; - int len = 0; - bool status = true; - - int fd = open(path, O_RDONLY); - if (fd < 0) { - status = false; - return status; - } - int ret; - ret = read(fd, &len, 4); - if (ret <= 0) { - close(fd); - status = false; - return status; - } - ret = read(fd, buf, len); - if (ret <= 0) { - close(fd); - status = false; - return status; - } - - while (1) { - struct symbol_cache_item *sym; - symbol s; - ret = read(fd, &len, 4); - if (ret <= 0) { - status = false; - break; - } - ret = read(fd, buf, len); - if (ret < len) { - status = false; - break; - } - sym = (struct symbol_cache_item *)buf; - s.start = sym->start; - s.end = sym->start + sym->size; - s.ip = sym->start; - s.name = sym->name; - ss.insert(s); - } - close(fd); - return status; -} - -bool load_symbol_cache(std::set &ss, const char *path, const char *filename) -{ - int fd = open(path, O_RDWR | O_EXCL); - if (fd < 0) { - return false; - } - int len = strlen(filename); - int ret = write(fd, &len, 4); - if (ret < 0) { - close(fd); - return false; - } - ret = write(fd, filename, len); - if (ret < 0) { - close(fd); - return false; - } - - std::set::iterator it; - int v; - for (it = ss.begin(); it != ss.end(); ++it) { - v = it->start; - ret = write(fd, &v, 4); - v = it->end - it->start; - ret = write(fd, &v, 4); - ret = write(fd, it->name.c_str(), it->name.length()); - } - return true; -} diff --git a/source/ucli_py/unwind/elf.h b/source/ucli_py/unwind/elf.h deleted file mode 100644 index 7e02c0e..0000000 --- a/source/ucli_py/unwind/elf.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Linux内核诊断工具--elf相关函数头文件 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#ifndef _PERF_ELF_H__ -#define _PERF_ELF_H__ - -#include -#include - -#include "symbol.h" - -#define BUILD_ID_SIZE 40 -bool save_symbol_cache(std::set &ss, const char *path); -bool load_symbol_cache(std::set &ss, const char *path, const char *filename); - -bool get_symbol_from_elf(std::set &ss, const char *path); -bool search_symbol(const std::set &ss, symbol &sym); -int filename__read_build_id(int pid, const char *mnt_ns_name, const char *filename, char *bf, size_t size); -#endif diff --git a/source/ucli_py/unwind/internal.h b/source/ucli_py/unwind/internal.h deleted file mode 100644 index 9139e1e..0000000 --- a/source/ucli_py/unwind/internal.h +++ /dev/null @@ -1,189 +0,0 @@ -// /* -// * Linux内核诊断工具--杂项定义头文件 -// * -// * Copyright (C) 2020 Alibaba Ltd. -// * -// * 作者: Baoyou Xie -// * -// * License terms: GNU General Public License (GPL) version 3 -// * -// */ - -// #include -// #include -// #include "uapi/ali_diagnose.h" -// #include "json/json.h" - -// #include -// #include -// #include - -// #include "debug.h" - -// extern std::set g_proc_map; - -// int run_trace_main(int argc, char **argv); -// int sys_delay_main(int argc, char **argv); -// int sched_delay_main(int argc, char **argv); -// int throttle_delay_main(int argc, char **argv); -// int load_monitor_main(int argc, char **argv); -// int exit_monitor_main(int argc, char **argv); -// int utilization_main(int argc, char **argv); -// int perf_main(int argc, char **argv); -// int tcp_retrans_main(int argc, char **argv); -// int tcp_connect_main(int argc, char **argv); -// int rw_top_main(int argc, char **argv); -// int irq_delay_main(int argc, char **argv); -// int mutex_monitor_main(int argc, char **argv); -// int alloc_top_main(int argc, char **argv); -// int alloc_load_main(int argc, char **argv); -// int drop_packet_main(int argc, char **argv); -// int fs_orphan_main(int argc, char **argv); -// int df_du_main(int argc, char **argv); -// int exec_monitor_main(int argc, char **argv); -// int fs_shm_main(int argc, char **argv); -// int irq_stats_main(int argc, char **argv); -// int irq_trace_main(int argc, char **argv); -// int kprobe_main(int argc, char **argv); -// int mm_leak_main(int argc, char **argv); -// int proc_monitor_main(int argc, char **argv); -// int runq_info_main(int argc, char **argv); -// int reboot_main(int argc, char **argv); -// int pi_main(int argc, char *argv[]); -// int memcpy_main(int argc, char* argv[]); -// int md5_main(int argc, char *argv[]); -// int net_bandwidth_main(int argc, char *argv[]); -// int sig_info_main(int argc, char *argv[]); -// int task_monitor_main(int argc, char **argv); -// int rw_sem_main(int argc, char **argv); -// int rss_monitor_main(int argc, char **argv); - -// void usage_run_trace(void); -// void usage_sys_delay(void); -// void usage_load_monitor(void); -// void usage_exit_monitor(void); -// void usage_utilization(void); -// void usage_perf(); -// void usage_tcp_retrans(); -// void usage_rw_top(); -// void usage_irq_delay(); -// void usage_mutex_monitor(); -// void usage_alloc_top(); -// void usage_drop_packet(); -// void usage_fs_orphan(); -// void usage_exec_monitor(); -// void usage_fs_shm(); -// void usage_irq_stats(); -// void usage_irq_trace(); -// void usage_kprobe(); -// void usage_mm_leak(); -// void usage_testcase(void); -// void usage_pupil(void); -// void usage_sched_delay(void); -// void usage_reboot(void); -// void usage_test_memcpy(void); -// void usage_test_pi(void); -// void usage_test_md5(void); -// void usage_net_bandwidth(void); -// void usage_sig_info(void); -// void usage_task_monitor(void); -// void usage_rw_sem(void); -// void usage_rss_monitor(void); -// void usage_throttle_delay(void); - -// int uprobe_main(int argc, char **argv); -// void usage_uprobe(); - -// int ping_delay_main(int argc, char *argv[]); -// void usage_ping_delay(void); -// int ping_delay6_main(int argc, char *argv[]); -// void usage_ping_delay6(void); - -// int test_run_trace_main(int argc, char *argv[]); -// void usage_test_run_trace(void); - -// int memcg_stats_main(int argc, char *argv[]); -// void usage_memcg_stats(void); - -// int diag_activate(const char func[]); -// int diag_deactivate(const char func[]); - -// void diag_printf_inode(struct diag_inode_detail *inode); -// void diag_printf_time(struct diag_timespec *tv); -// void diag_printf_task(struct diag_task_detail *task); -// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains); -// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse); -// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse, int detail); -// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack); -// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack, int reverse); -// void diag_printf_user_stack(int pid, int ns_pid, const char *comm, -// struct diag_user_stack_detail *user_stack); -// void diag_printf_user_stack(int pid, int ns_pid, const char *comm, -// struct diag_user_stack_detail *user_stack, int attach); -// void diag_printf_user_stack(int pid, int ns_pid, const char *comm, -// struct diag_user_stack_detail *user_stack, int attach, int reverse); -// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, -// struct diag_raw_stack_detail *raw_stack); -// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, -// struct diag_raw_stack_detail *raw_stack, int attach); -// void init_java_env(const char *agent, int pid, int ns_pid, const char *comm, std::set &); -// void diag_unwind_raw_stack(int pid, int ns_pid, -// struct diag_raw_stack_detail *raw_stack, unsigned long stack[BACKTRACE_DEPTH]); - -// void diag_sls_time(struct diag_timespec *tv, Json::Value &owner); -// void diag_sls_task(struct diag_task_detail *tsk_info, Json::Value &task); -// void diag_sls_proc_chains(struct diag_proc_chains_detail *proc_chains, Json::Value &task); -// void diag_sls_kern_stack(struct diag_kern_stack_detail *kern_stack, Json::Value &task); -// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm, -// struct diag_user_stack_detail *user_stack, Json::Value &task); -// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm, -// struct diag_user_stack_detail *user_stack, Json::Value &task, int attach); -// void diag_sls_inode(struct diag_inode_detail *inode, Json::Value &root); -// int log_config(char *arg, char *sls_file, int *p_syslog_enabled); -// void write_syslog(int enabled, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root); -// void write_file(char *sls_file, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root); -// void diag_ip_addr_to_str(unsigned char *ip_addr,const char type[], Json::Value &root); -// #define ULONG_MAX (~0UL) -// #define STACK_IS_END(v) ((v) == 0 || (v) == ULONG_MAX) - -// class pid_cmdline { -// private: -// std::map cmdlines; -// public: -// void clear(void); -// std::string & get_pid_cmdline(int pid); -// }; - -// int jmaps_main(int argc, char **argv); -// void restore_global_env(); -// int attach_ns_env(int pid); -// int java_attach_once(int flag_no_attach = 0); - -// extern class pid_cmdline pid_cmdline; - -// extern void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set &procs, int dist); -// extern unsigned int ipstr2int(const char *ipstr); -// extern char *int2ipstr(const unsigned int ip, char *ipstr, const unsigned int ip_str_len); - -// extern int is_linux_2_6_x(void); -// extern int linux_2_6_x; - -// int sys_cost_main(int argc, char **argv); -// void usage_sys_cost(); - -// int fs_cache_main(int argc, char *argv[]); -// void usage_fs_cache(void); - -// int high_order_main(int argc, char *argv[]); -// void usage_high_order(void); - -// int pmu_main(int argc, char **argv); -// void usage_pmu(void); - -// int testcase_main(int argc, char *argv[]); - -// struct timeval; -// struct timezone; -// extern "C" { -// void diag_gettimeofday(struct diag_timespec *tv, struct timezone *tz); -// } diff --git a/source/ucli_py/unwind/symbol.cc b/source/ucli_py/unwind/symbol.cc deleted file mode 100644 index dac1680..0000000 --- a/source/ucli_py/unwind/symbol.cc +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Linux内核诊断工具--用户态符号表解析 - * - * Copyright (C) 2020 Alibaba Ltd. - * - * License terms: GNU General Public License (GPL) version 3 - * - */ - -#include -#include -#include - -#include "symbol.h" -#include "elf.h" -#include "internal.h" - -void restore_global_env(); -int attach_ns_env(int pid); - -symbol_parser g_symbol_parser; - -bool symbol_parser::add_pid_maps(int pid, size_t start, size_t end, size_t offset, const char *name) -{ - std::map::iterator it; - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - proc_vma proc; - machine_vma.insert(make_pair(pid, proc)); - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - return false; - } - } - - vma vm(start, end, offset, name); - it->second.insert(std::make_pair(vm.start, std::move(vm))); - - return true; -} - -bool symbol_parser::load_pid_maps(int pid) -{ - std::map::iterator it; - it = machine_vma.find(pid); - if (it != machine_vma.end()) { - return true; - } - - proc_vma proc; - char fn[256]; - sprintf(fn, "/proc/%d/maps", pid); - FILE *fp = fopen(fn, "r"); - if (!fp) { - return false; - } - - char buf[4096]; - char exename[4096]; - size_t start, end, offset; - while (fgets(buf, sizeof(buf), fp) != NULL) { - start = end = offset = 0; - exename[0] = '\0'; - sscanf(buf, "%lx-%lx %*s %lx %*x:%*x %*u %s %*s\n", &start, &end, &offset, exename); - if (exename[0] == '\0') { - strcpy(exename, "[anon]"); - } - vma vm(start, end, offset, exename); - proc.insert(std::make_pair(vm.start, std::move(vm))); - } - - fclose(fp); - - machine_vma.insert(std::make_pair(pid, std::move(proc))); - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - return false; - } - - return true; -} - -bool symbol_parser::load_perf_map(int pid, int pid_ns) -{ -#if 0 - if (pid != pid_ns) { - if (attach_ns_env(pid) < 0) { - return false; - } - } -#endif - char perfmapfile[64]; - snprintf(perfmapfile, sizeof(perfmapfile), "/tmp/perf-%d.map", pid); - FILE *fp = fopen(perfmapfile, "r"); - if (fp == NULL) { - return false; - } - char line[256]; - char *buf; - long start; - int size; - char name[256]; - std::set syms; - symbol sym; - while ((buf = fgets(line, sizeof(line), fp)) != NULL) { - sscanf(buf, "%lx %x %s\n", &start, &size, name); - sym.start = start; - sym.end = sym.start + size; - sym.ip = sym.start; - sym.name = name; - syms.insert(sym); - } - java_symbols.insert(make_pair(pid, std::move(syms))); -#if 0 - if (pid != pid_ns) { - restore_global_env(); - } -#endif - return true; -} - -bool symbol_parser::find_java_symbol(symbol &sym, int pid, int pid_ns) -{ - std::set ss; - std::map >::iterator it; - //bool load_now = false; - it = java_symbols.find(pid); - if (it == java_symbols.end()) { - if (!load_perf_map(pid, pid_ns)) { - return false; - } - //load_now = true; - it = java_symbols.find(pid); - return search_symbol(it->second, sym); - } else { - return search_symbol(it->second, sym); - } - return true; - - //bool ret = search_symbol(syms, sym); -#if 0 - if (!ret && !load_now) { - java_symbols.erase(pid); - if (!load_perf_map(pid)) { - return false; - } - syms = java_symbols.find(pid)->second; - return search_symbol(syms, sym); - } -#endif - //return ret; -} - -static bool load_kernel_symbol_list(std::vector &sym_list) -{ - FILE *fp = fopen("/proc/kallsyms", "r"); - if (!fp) { - return -1; - } - - char buf[256]; - char type; - int len; - while (fgets(buf, sizeof(buf), fp) != NULL) { - sscanf(buf, "%*p %c %*s\n", &type); - if ((type | 0x20) != 't') { - continue; - } - len = strlen(buf); - if (buf[len-1] == '\n') { - buf[len-1] = ' '; - } - sym_list.push_back(buf); - } - fclose(fp); - - std::sort(sym_list.begin(), sym_list.end()); - return true; -} - -bool is_space(int ch) { - return std::isspace(ch); -} - -static inline void rtrim(std::string &s) -{ - s.erase(std::find_if(s.rbegin(), s.rend(), is_space).base(), s.end()); -} - -static bool get_next_kernel_symbol( - std::set &syms, - std::vector &sym_list, - std::vector::iterator cursor) -{ - if (cursor == sym_list.end()) { - return false; - } - symbol sym; - size_t start, end; - sscanf(cursor->c_str(), "%p %*c %*s\n", (void **)&start); - sym.name = cursor->c_str() + 19; - rtrim(sym.name); -#if 0 - if (sym.name[sym.name.size()-1] == '\n') { - sym.name[sym.name.size()-1] = '\0'; - } -#endif - cursor++; - if (cursor != sym_list.end()) { - sscanf(cursor->c_str(), "%p %*c %*s\n", (void **)&end); - } - else { - end = INVALID_ADDR; - } - sym.start = start; - sym.end = end; - sym.ip = start; - - syms.insert(sym); - return true; -} - -bool symbol_parser::load_kernel() -{ - if (kernel_symbols.size() != 0) { - return true; - } - - std::vector sym_list; - if (!load_kernel_symbol_list(sym_list)) { - exit(0); - return false; - } - - std::vector::iterator cursor = sym_list.begin(); - while (get_next_kernel_symbol(kernel_symbols, sym_list, cursor)) { - cursor++; - } - return true; -} - -bool symbol_parser::load_elf(pid_t pid, const elf_file &file) -{ - std::map >::iterator it; - it = file_symbols.find(file); - std::set tmp; - std::set &syms = tmp; - if (it != file_symbols.end()) { - return true; - } - if (get_symbol_from_elf(syms, file.filename.c_str())) { - file_symbols.insert(make_pair(file, std::move(syms))); - return true; - } - return false; -} - -bool symbol_parser::find_kernel_symbol(symbol &sym) -{ - load_kernel(); - sym.end = sym.start = 0; - std::set::iterator it = kernel_symbols.find(sym); - if (it != kernel_symbols.end()) { - sym.end = it->end; - sym.start = it->start; - sym.name = it->name; - return true; - } - return false; -} - -bool symbol_parser::find_symbol_in_cache(int tgid, unsigned long addr, std::string &symbol) -{ - std::map >::const_iterator it_pid = - symbols_cache.find(tgid); - - if (it_pid != symbols_cache.end()) { - std::map map = symbols_cache[tgid]; - std::map::const_iterator it_symbol = - map.find(addr); - - if (it_symbol != map.end()) { - symbol = map[addr]; - - return true; - } - } - - return false; -} - -bool symbol_parser::putin_symbol_cache(int tgid, unsigned long addr, std::string &symbol) -{ - std::map >::const_iterator it_pid = - symbols_cache.find(tgid); - - if (it_pid == symbols_cache.end()) { - std::map map; - symbols_cache.insert(std::make_pair(tgid, map)); - } - - std::map &map = symbols_cache[tgid]; - std::map::const_iterator it_symbol = - map.find(addr); - - if (it_symbol == map.end()) { - map[addr] = symbol; - return true; - } - - return false; -} - -bool symbol_parser::get_symbol_info(int pid, symbol &sym, elf_file &file) -{ - std::map::iterator proc_vma_info; - - if (java_only) { - file.type = UNKNOWN; - return true; - } - - proc_vma_info = machine_vma.find(pid); - if (proc_vma_info == machine_vma.end()) { - if (!load_pid_maps(pid)) { - return false; - } - } - - vma area(sym.ip); - if (!find_vma(pid, area)) { - return false; - } - if (area.name == "[anon]") { - file.type = JIT_TYPE; - } - - file.reset(area.name); - if (file.type != JIT_TYPE) { - sym.reset(area.map(sym.ip)); - } - - return true; -} - -bool symbol_parser::find_elf_symbol(symbol &sym, const elf_file &file, int pid, int pid_ns) -{ - if (java_only) { - return find_java_symbol(sym, pid, pid_ns); - } - - if (file.type == JIT_TYPE) { - return find_java_symbol(sym, pid, pid_ns); - } - - std::map >::iterator it; - it = file_symbols.find(file); - std::set ss; - if (it == file_symbols.end()) { - if (!load_elf(pid, file)) { - return false; - } - it = file_symbols.find(file); - return search_symbol(it->second, sym); - } else { - return search_symbol(it->second, sym); - } - return true; -} - -vma* symbol_parser::find_vma(pid_t pid, size_t pc) -{ - std::map::iterator it; - - it = machine_vma.find(pid); - if (it == machine_vma.end()) { - return NULL; - } - - proc_vma::iterator vma_iter = it->second.upper_bound(pc); - if (vma_iter == it->second.end() || vma_iter->second.end < pc) { - return NULL; - } - - if (vma_iter != it->second.begin()) { - --vma_iter; - } - - return &vma_iter->second; -} - -bool symbol_parser::find_vma(pid_t pid, vma &vm) -{ - std::map::iterator proc_vma_map; - - proc_vma_map = machine_vma.find(pid); - if (proc_vma_map == machine_vma.end()) { - return false; - } - - proc_vma::const_iterator vma_iter = proc_vma_map->second.upper_bound(vm.pc); - if (vma_iter == proc_vma_map->second.end()) { - return false; - } - if (vma_iter->second.end < vm.pc) { - return false; - } - - if (vma_iter != proc_vma_map->second.begin()) { - --vma_iter; - } - - vm.start = vma_iter->second.start; - vm.end = vma_iter->second.end; - vm.name = vma_iter->second.name; - vm.offset = vma_iter->second.offset; - - return true; -} - -void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set &procs, int dist) -{ - pid_cmdline.clear(); - procs.clear(); - g_symbol_parser.clear_symbol_info(dist); -} - -void symbol_parser::clear_symbol_info(int dist) -{ - machine_vma.clear(); - java_symbols.clear(); - if (dist) { - kernel_symbols.clear(); - file_symbols.clear(); - } -} - -void symbol_parser::dump(void) -{ - int count1, count2, count3; - { - count1 = 0; - count2 = 0; - count3 = 0; - std::map >::iterator iter = file_symbols.begin(); - for(; iter != file_symbols.end(); ++iter) { - std::set& map = iter->second; - const elf_file& file = iter->first; - - count1++; - printf("xby-debug, file_symbols: %s, %lu\n", - file.filename.c_str(), - map.size()); - - count2 += map.size(); - std::set::iterator it = map.begin(); - for(; it != map.end(); ++it) { - count3 += it->name.length(); - } - } - printf("xby-debug, file_symbols: %d, %d, %d\n", count1, count2, count3); - printf("xby-debug, sizeof(symbol): %ld\n", sizeof(symbol)); - } - - { - count1 = 0; - count2 = 0; - std::map >::iterator iter = java_symbols.begin(); - for(; iter != java_symbols.end(); ++iter) { - count1++; - std::set& map = iter->second; - count2 += map.size(); - } - printf("xby-debug, java_symbols: %d, %d\n", count1, count2); - } - - { - printf("xby-debug, kernel_symbols: %lu\n", kernel_symbols.size()); - } - - { - count1 = 0; - count2 = 0; - std::map::iterator iter = machine_vma.begin(); - for(; iter != machine_vma.end(); ++iter) { - count1++; - proc_vma map = iter->second; - count2 += map.size(); - } - printf("xby-debug, machine_vma: %d, %d\n", count1, count2); - } - - { - count1 = 0; - count2 = 0; - std::map >::iterator iter = symbols_cache.begin(); - for(; iter != symbols_cache.end(); ++iter) { - count1++; - std::map& map = iter->second; - count2 += map.size(); - } - printf("xby-debug, symbols_cache: %d, %d\n", count1, count2); - } -} diff --git a/source/ucli_py/unwind/unwind.cc b/source/ucli_py/unwind/unwind.cc deleted file mode 100644 index 85aa4b5..0000000 --- a/source/ucli_py/unwind/unwind.cc +++ /dev/null @@ -1,684 +0,0 @@ -/* - * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. - * - * Lots of this code have been borrowed or heavily inspired from parts of - * the libunwind 0.99 code which are (amongst other contributors I may have - * forgotten): - * - * Copyright (C) 2002-2007 Hewlett-Packard Co - * Contributed by David Mosberger-Tang - * - * And the bugs have been added by: - * - * Copyright (C) 2010, Frederic Weisbecker - * Copyright (C) 2012, Jiri Olsa - * - */ - -#include -#include -#include - -#include -#include -#include -#include - -//#include -#include -#include -#include -#include - - -#include "unwind.h" -#include "symbol.h" - - -extern "C" { -int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); -} - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ -#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ - -/* Pointer-encoding formats: */ -#define DW_EH_PE_omit 0xff -#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ -#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ -#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ -#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ -#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ - -/* Pointer-encoding application: */ -#define DW_EH_PE_absptr 0x00 /* absolute value */ -#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ - -/* - * The following are not documented by LSB v1.3, yet they are used by - * GCC, presumably they aren't documented by LSB since they aren't - * used on Linux: - */ -#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ -#define DW_EH_PE_aligned 0x50 /* aligned pointer */ - -/* Flags intentionaly not handled, since they're not needed: - * #define DW_EH_PE_indirect 0x80 - * #define DW_EH_PE_uleb128 0x01 - * #define DW_EH_PE_udata2 0x02 - * #define DW_EH_PE_sleb128 0x09 - * #define DW_EH_PE_sdata2 0x0a - * #define DW_EH_PE_textrel 0x20 - * #define DW_EH_PE_datarel 0x30 - */ - - -struct unwind_info { - struct perf_sample *sample; - int pid; - int pid_ns; - symbol_parser *sp; -}; - -#define dw_read(ptr, type, end) ({ \ - type *__p = (type *) ptr; \ - type __v; \ - if ((__p + 1) > (type *) end) \ - return -EINVAL; \ - __v = *__p++; \ - ptr = (typeof(ptr)) __p; \ - __v; \ - }) - -#ifdef __x86_64__ -int unwind__arch_reg_id(int regnum) -{ - int id; - - switch (regnum) { - case UNW_X86_64_RBP: - id = PERF_REG_BP; - break; - case UNW_X86_64_RSP: - id = PERF_REG_SP; - break; - case UNW_X86_64_RIP: - id = PERF_REG_IP; - break; - default: - return -EINVAL; - } - - return id; -} -#else -int unwind__arch_reg_id(int regnum) -{ - int id; - switch (regnum) { - case UNW_AARCH64_SP: - id = PERF_REG_SP; - break; - case UNW_AARCH64_PC: - id = PERF_REG_IP; - break; - default: - return -EINVAL; - } - - return id; -} -#endif - -static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, - u8 encoding) -{ - u8 *cur = *p; - *val = 0; - - switch (encoding) { - case DW_EH_PE_omit: - *val = 0; - goto out; - case DW_EH_PE_ptr: - *val = dw_read(cur, unsigned long, end); - goto out; - default: - break; - } - - switch (encoding & DW_EH_PE_APPL_MASK) { - case DW_EH_PE_absptr: - break; - case DW_EH_PE_pcrel: - *val = (unsigned long) cur; - break; - default: - return -EINVAL; - } - - if ((encoding & 0x07) == 0x00) - encoding |= DW_EH_PE_udata4; - - switch (encoding & DW_EH_PE_FORMAT_MASK) { - case DW_EH_PE_sdata4: - *val += dw_read(cur, s32, end); - break; - case DW_EH_PE_udata4: - *val += dw_read(cur, u32, end); - break; - case DW_EH_PE_sdata8: - *val += dw_read(cur, s64, end); - break; - case DW_EH_PE_udata8: - *val += dw_read(cur, u64, end); - break; - default: - return -EINVAL; - } - - out: - *p = cur; - return 0; -} - -#define dw_read_encoded_value(ptr, end, enc) ({ \ - u64 __v; \ - if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ - return -EINVAL; \ - } \ - __v; \ - }) - -static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, - GElf_Shdr *shp, const char *name) -{ - Elf_Scn *sec = NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) { - char *str; - - gelf_getshdr(sec, shp); - str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); - if (!strcmp(name, str)) - break; - } - - return sec; -} - -static u64 elf_section_offset(int fd, const char *name) -{ - Elf *elf; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - u64 offset = 0; - - elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); - if (elf == NULL) - return 0; - - do { - if (gelf_getehdr(elf, &ehdr) == NULL) - break; - - if (!elf_section_by_name(elf, &ehdr, &shdr, name)) - break; - - offset = shdr.sh_offset; - } while (0); - - elf_end(elf); - return offset; -} - -struct table_entry { - u32 start_ip_offset; - u32 fde_offset; -}; - -struct eh_frame_hdr { - unsigned char version; - unsigned char eh_frame_ptr_enc; - unsigned char fde_count_enc; - unsigned char table_enc; - - /* - * The rest of the header is variable-length and consists of the - * following members: - * - * encoded_t eh_frame_ptr; - * encoded_t fde_count; - */ - - /* A single encoded pointer should not be more than 8 bytes. */ - u64 enc[2]; - - /* - * struct { - * encoded_t start_ip; - * encoded_t fde_addr; - * } binary_search_table[fde_count]; - */ - char data[0]; -} __attribute__((__packed__)); - -int dso_data_fd(vma* dso) -{ - return open(dso->name.c_str(), O_RDONLY); -} - -ssize_t dso_read(vma *dso, u64 offset, u8 *data, ssize_t size) -{ - ssize_t ret = -1; - int fd; - - fd = dso_data_fd(dso); - if (fd < 0) - return -1; - - do { - if (-1 == lseek(fd, offset, SEEK_SET)) - break; - - ret = read(fd, data, size); - if (ret <= 0) - break; - } while (0); - - close(fd); - return ret; -} - -ssize_t dso__data_read_offset(vma *dso, u64 offset, u8 *data, ssize_t size) -{ - ssize_t r = 0; - u8 *p = data; - - do { - ssize_t ret; - ret = dso_read(dso, offset, p, size); - if (ret <= 0) { - return -1; - } - if (ret > size) { - return -1; - } - r += ret; - p += ret; - offset += ret; - size -= ret; - } while (size); - return r; -} - -ssize_t dso__data_read_addr(vma *map, - u64 addr, u8 *data, ssize_t size) -{ - u64 offset; - - if (map->name.size() > 0 && map->name[0] != '/') - return 0; - - offset = addr - map->start + map->offset; - return dso__data_read_offset(map, offset, data, size); -} - - -static int unwind_spec_ehframe(vma *dso, - u64 offset, u64 *table_data, u64 *segbase, - u64 *fde_count) -{ - struct eh_frame_hdr hdr; - u8 *enc = (u8 *) &hdr.enc; - u8 *end = (u8 *) &hdr.data; - ssize_t r; - - r = dso__data_read_offset(dso, offset, (u8 *) &hdr, sizeof(hdr)); - if (r != sizeof(hdr)) { - return -EINVAL; - } - - /* We dont need eh_frame_ptr, just skip it. */ - dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); - - *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); - *segbase = offset; - *table_data = (enc - (u8 *) &hdr) + offset; - - return 0; -} - -static int read_unwind_spec(vma* dso, u64 *table_data, u64 *segbase, u64 *fde_count) -{ - int ret = -EINVAL, fd; - - if (dso->eh_frame_hdr_offset == 0 && dso->elf_read_error == 0) { - fd = dso_data_fd(dso); - if (fd < 0) - return -EINVAL; - - dso->eh_frame_hdr_offset = elf_section_offset(fd, ".eh_frame_hdr"); - close(fd); - ret = unwind_spec_ehframe(dso, dso->eh_frame_hdr_offset, - &dso->table_data, &dso->eh_frame_hdr_offset, - &dso->fde_count); - if (ret != 0) { - dso->eh_frame_hdr_offset = 0; - dso->elf_read_error = 1; - return -EINVAL; - } - } - - *table_data = dso->table_data; - *segbase = dso->eh_frame_hdr_offset; - *fde_count = dso->fde_count; - - /* TODO .debug_frame check if eh_frame_hdr fails */ - return 0; -} - -static vma* find_map(unw_word_t ip, struct unwind_info *ui) -{ - return ui->sp->find_vma(ui->pid, ip); -} - -static int -find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, - int need_unwind_info, void *arg) -{ - struct unwind_info *ui = (struct unwind_info *)arg; - unw_dyn_info_t di; - u64 table_data, segbase, fde_count; - - vma* map; - map = find_map(ip, ui); - if (!map) { - return -EINVAL; - } - - if (!read_unwind_spec(map, &table_data, &segbase, &fde_count)) { - memset(&di, 0, sizeof(di)); - di.format = UNW_INFO_FORMAT_REMOTE_TABLE; - di.start_ip = map->start; - di.end_ip = map->end; - di.u.rti.segbase = map->start + segbase; - di.u.rti.table_data = map->start + table_data; - di.u.rti.table_len = fde_count * sizeof(struct table_entry) - / sizeof(unw_word_t); - return dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } - //return -EINVAL; - return -UNW_ENOINFO; -} - -static int access_fpreg(unw_addr_space_t as, - unw_regnum_t num, - unw_fpreg_t *val, - int __write, - void *arg) -{ - return -UNW_EINVAL; -} - -static int get_dyn_info_list_addr(unw_addr_space_t as, - unw_word_t *dil_addr, - void *arg) -{ - return -UNW_ENOINFO; -} - -static int resume(unw_addr_space_t as, - unw_cursor_t *cu, - void *arg) -{ - return -UNW_EINVAL; -} - -static int -get_proc_name(unw_addr_space_t as, - unw_word_t addr, - char *bufp, size_t buf_len, - unw_word_t *offp, void *arg) -{ - return -UNW_EINVAL; -} - -struct map *last_map = NULL; -static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, - unw_word_t *data) -{ - ssize_t size; - - // ip in the first page is invalid - if ( addr == 0 || addr == (unsigned long)(-1) || (long)addr < 4096 ) { - return -UNW_ENOINFO; - } - - vma *map; - map = find_map(addr, ui); - if (!map) { - return -UNW_ENOINFO; - } - - if (map->type != NATIVE_TYPE) { - return -UNW_ENOINFO; - } - - size = dso__data_read_addr(map, - addr, (u8 *) data, sizeof(*data)); - - return !(size == sizeof(*data)); -} - -/* - * Optimization point. - */ -static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) -{ - /* we only support 3 registers. RIP, RSP and RBP */ - if (id < 0 || id > 2) - return -EINVAL; - - *valp = regs->regs[id]; - return 0; -} - -unw_word_t last_addr = 0; -unw_word_t last_val = 0; -int stack_offset = 0; - -static int access_mem(unw_addr_space_t as, - unw_word_t addr, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui = (struct unwind_info *)arg; - struct stack_dump *stack = &ui->sample->user_stack; - unw_word_t start, end; - int offset; - int ret; - - if (addr == last_addr) { - (*valp) = last_val; - return 0; - } - - last_addr = addr; - - /* Don't support write, probably not needed. */ - if (__write || !stack || !ui->sample->user_regs.regs) { - *valp = 0; - // fprintf(stderr, "access_mem: __write memory\n"); - last_val = *valp; - return 0; - } - - /* start is the SP */ - ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); - if (ret) { - // fprintf(stderr, "access_mem: reg_value error (ret: %d)\n", ret); - return ret; - } - - end = start + stack->size; - - /* Check overflow. */ - if (addr + sizeof(unw_word_t) < addr) { - // fprintf(stderr, "access_mem: Check overflow.\n"); - return -EINVAL; - } - - if (addr < start || addr + sizeof(unw_word_t) >= end) { - ret = access_dso_mem(ui, addr, valp); - if (ret) { - // pr_debug("unwind: access_mem %p not inside range %p-%p\n", - // (void *)addr, (void *)start, (void *)end); - *valp = 0; - last_val = 0; - return ret; - } - last_val = *valp; - return 0; - } - - offset = addr - start; - *valp = *(unw_word_t *)&stack->data[offset]; - last_val = *valp; - stack_offset = offset; - - //pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n", - // (void *)addr, (unsigned long)*valp, offset); - return 0; -} - -static int access_reg(unw_addr_space_t as, - unw_regnum_t regnum, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui = (struct unwind_info *)arg; - int id, ret; - - /* Don't support write, I suspect we don't need it. */ - if (__write) { - //pr_err("unwind: access_reg w %d\n", regnum); - return 0; - } - - if (!ui->sample->user_regs.regs) { - *valp = 0; - return 0; - } - - id = unwind__arch_reg_id(regnum); - if (id < 0) { - //fprintf(stderr, "Cannot get reg: %d\n", regnum); - return -EINVAL; - } - - ret = reg_value(valp, &ui->sample->user_regs, id); - if (ret) { - //pr_err("unwind: can't read reg %d\n", regnum); - return ret; - } - - //pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); - return 0; -} - -static void put_unwind_info(unw_addr_space_t as, - unw_proc_info_t *pi, - void *arg) -{ - //pr_debug("unwind: put_unwind_info called\n"); -} - -static int entry(u64 ip, int pid, int pid_ns, unwind_entry_cb_t cb, void *arg) -{ - struct unwind_entry e; - - e.ip = ip; - e.pid = pid; - e.pid_ns = pid_ns; - - return cb(&e, arg); -} - -static unw_accessors_t accessors = { - .find_proc_info = find_proc_info, - .put_unwind_info = put_unwind_info, - .get_dyn_info_list_addr = get_dyn_info_list_addr, - .access_mem = access_mem, - .access_reg = access_reg, - .access_fpreg = access_fpreg, - .resume = resume, - .get_proc_name = get_proc_name, -}; - -static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, - void *arg) -{ - unw_addr_space_t addr_space; - unw_cursor_t c; - entry_cb_arg_t *cb_arg = (entry_cb_arg_t *)arg; - int ret; - int loops = 0; - - addr_space = unw_create_addr_space(&accessors, 0); - if (!addr_space) { - //pr_err("unwind: Can't create unwind address space.\n"); - return -ENOMEM; - } - - unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); - - ret = unw_init_remote(&c, addr_space, ui); /* @ui is args */ - - while (!ret && (unw_step(&c) > 0)) { - unw_word_t ip; - - unw_get_reg(&c, UNW_REG_IP, &ip); //get IP from current step; - cb_arg->arg = &c; - ret = entry(ip, ui->pid, ui->pid_ns, cb, cb_arg); - - loops++; - if (loops >= 50) - break; - } - - unw_destroy_addr_space(addr_space); - return ret; -} - -int unwind__get_entries(unwind_entry_cb_t cb, void *arg, - symbol_parser *sp, int pid, int pid_ns, - struct perf_sample *data) -{ - unw_word_t ip; - struct unwind_info ui = { - .sample = data, - .pid = pid, - .pid_ns = pid_ns, - .sp = sp, - }; - int ret; - - if (!data->user_regs.regs) - return -EINVAL; - - ret = reg_value(&ip, &data->user_regs, PERF_REG_IP); - if (ret) - return ret; - - ret = entry(ip, pid, pid_ns, cb, arg); - if (ret) - return -ENOMEM; - - return get_entries(&ui, cb, arg); -} diff --git a/source/ucli_py/unwind/unwind.h b/source/ucli_py/unwind/unwind.h deleted file mode 100644 index a18cea2..0000000 --- a/source/ucli_py/unwind/unwind.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef __UNWIND_H -#define __UNWIND_H - -#include -#include "symbol.h" - -typedef unsigned long u64; -typedef unsigned char u8; -typedef unsigned int u32; -typedef long s64; -typedef char s8; -typedef int s32; - - -struct regs_dump { - u64 *regs; -}; - -struct ip_callchain { - u64 nr; - u64 ips[0]; -}; - -struct branch_flags { - u64 mispred:1; - u64 predicted:1; - u64 reserved:62; -}; - -struct branch_entry { - u64 from; - u64 to; - struct branch_flags flags; -}; - -struct branch_stack { - u64 nr; - struct branch_entry entries[0]; -}; - -struct stack_dump { - unsigned short offset; - u64 size; - char *data; -}; - -struct perf_sample { - u64 ip; - u32 pid, tid; - u64 time; - u64 addr; - u64 id; - u64 stream_id; - u64 period; - u32 cpu; - u32 raw_size; - void *raw_data; - struct ip_callchain *callchain; - struct branch_stack *branch_stack; - struct regs_dump user_regs; - struct stack_dump user_stack; -}; - -#define PERF_REG_IP 0 -#define PERF_REG_SP 1 -#define PERF_REG_BP 2 - -struct unwind_entry { - int pid; - int pid_ns; - u64 ip; - struct vma *map; -}; - -typedef struct { - struct perf_sample *stack_sample; - void *arg; -} entry_cb_arg_t; - -typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); - -int unwind__get_entries(unwind_entry_cb_t cb, void *arg, - symbol_parser *sp, - int pid, int pid_ns, - struct perf_sample *data); -int unwind__arch_reg_id(int regnum); - -extern int stack_offset; -static inline void clear_stack_offset(void) -{ - stack_offset = 0; -} - -static inline int get_stack_offset(void) -{ - return stack_offset; -} - -extern void unwind__get_rbp(void *arg); - -#endif /* __UNWIND_H */