From a6614067673a5e61444fcfcb6c9826bdcf60c28e Mon Sep 17 00:00:00 2001 From: Igor Nabirushkin Date: Thu, 8 Nov 2018 13:49:42 +0300 Subject: tegra-profiler: dwarf: support multiple processes - Support DWARF/ARM-EHABI unwinding for multiple processes. - Add cpu_id for MMAP samples. Bug 2438564 Jira DTSP-824 Jira DTSP-1599 Change-Id: I998906011cff240b9a554cd40679cd9ec9c0f7b7 Signed-off-by: Igor Nabirushkin Reviewed-on: https://git-master.nvidia.com/r/1945653 (cherry picked from commit 20e2cf7d2509dfc4708f4a3720aee26852998f13) Reviewed-on: https://git-master.nvidia.com/r/1992080 Reviewed-by: Dmitry Antipov Reviewed-by: Bibek Basu GVS: Gerrit_Virtual_Submit Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/misc/tegra-profiler/comm.c | 127 +++-- drivers/misc/tegra-profiler/comm.h | 3 + drivers/misc/tegra-profiler/dwarf_unwind.c | 136 ++++-- drivers/misc/tegra-profiler/eh_unwind.c | 732 +++++++++++++++++------------ drivers/misc/tegra-profiler/eh_unwind.h | 66 +-- drivers/misc/tegra-profiler/hrt.c | 8 - drivers/misc/tegra-profiler/main.c | 4 +- drivers/misc/tegra-profiler/mmap.c | 48 +- drivers/misc/tegra-profiler/quadd.h | 6 + drivers/misc/tegra-profiler/version.h | 2 +- include/linux/tegra_profiler.h | 64 +-- 11 files changed, 715 insertions(+), 481 deletions(-) diff --git a/drivers/misc/tegra-profiler/comm.c b/drivers/misc/tegra-profiler/comm.c index df632a272..9625851a3 100644 --- a/drivers/misc/tegra-profiler/comm.c +++ b/drivers/misc/tegra-profiler/comm.c @@ -58,9 +58,6 @@ struct quadd_comm_ctx { int params_ok; struct miscdevice *misc_dev; - - struct list_head mmap_areas; - raw_spinlock_t mmaps_lock; }; struct comm_cpu_context { @@ -230,12 +227,11 @@ static struct quadd_comm_data_interface comm_data = { .is_active = is_active, }; -static struct quadd_mmap_area * -find_mmap(unsigned long vm_start) +static struct quadd_mmap_area *find_mmap_by_vma(unsigned long vm_start) { struct quadd_mmap_area *entry; - list_for_each_entry(entry, &comm_ctx.mmap_areas, list) { + list_for_each_entry(entry, &comm_ctx.ctx->mmap_areas, list) { struct vm_area_struct *mmap_vma = entry->mmap_vma; if (vm_start == mmap_vma->vm_start) @@ -245,6 +241,18 @@ find_mmap(unsigned long vm_start) return NULL; } +static struct quadd_mmap_area *find_mmap_by_hash(unsigned int hash) +{ + struct quadd_mmap_area *entry; + + list_for_each_entry(entry, &comm_ctx.ctx->mmap_areas, list) { + if (hash == entry->fi.file_hash) + return entry; + } + + return NULL; +} + static int device_open(struct inode *inode, struct file *file) { int err; @@ -432,7 +440,8 @@ device_ioctl(struct file *file, unsigned long ioctl_param) { int err = 0; - unsigned int cpuid; + unsigned int cpuid, file_hash; + unsigned long mmap_start; struct quadd_mmap_area *mmap; struct quadd_parameters *user_params; struct quadd_pmu_setup_for_cpu *cpu_pmu_params; @@ -673,26 +682,43 @@ device_ioctl(struct file *file, goto error_out; } - pr_debug("%s: user_mmap_start: %#llx, sections vma: %#llx - %#llx\n", - __func__, - (unsigned long long)extabs.user_mmap_start, - (unsigned long long)extabs.vm_start, - (unsigned long long)extabs.vm_end); + mmap_start = (unsigned long)extabs.user_mmap_start; + file_hash = extabs.file_hash; - raw_spin_lock(&comm_ctx.mmaps_lock); - mmap = find_mmap(extabs.user_mmap_start); + pr_debug("%s: mmap_start: %#lx, hash: %#x, sec: %#lx - %#lx\n", + __func__, mmap_start, file_hash, + (unsigned long)extabs.vm_start, + (unsigned long)extabs.vm_end); + + raw_spin_lock(&comm_ctx.ctx->mmaps_lock); + + mmap = mmap_start ? find_mmap_by_vma(mmap_start) : + find_mmap_by_hash(file_hash); if (!mmap) { - pr_err("%s: error: mmap is not found\n", __func__); + pr_err("%s: error: !mmap, start/hash: %#lx/%#x\n", + __func__, mmap_start, file_hash); err = -ENXIO; - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); + goto error_out; + } + + if ((mmap_start && mmap->type != QUADD_MMAP_TYPE_NONE) || + (!mmap_start && mmap->type != QUADD_MMAP_TYPE_EXTABS)) { + pr_err("%s: wrong mmap: %d, start/hash: %#lx/%#x\n", + __func__, mmap->type, mmap_start, file_hash); + err = -ENXIO; + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); goto error_out; } mmap->type = QUADD_MMAP_TYPE_EXTABS; mmap->rb = NULL; + if (mmap_start) + mmap->fi.file_hash = extabs.file_hash; + err = comm_ctx.control->set_extab(&extabs, mmap); - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); if (err) { pr_err("error: set_sections_info\n"); goto error_out; @@ -702,24 +728,35 @@ device_ioctl(struct file *file, case IOCTL_SET_MMAP_RB: if (copy_from_user(&mmap_rb, (void __user *)ioctl_param, sizeof(mmap_rb))) { - pr_err("%s: error: mmap_rb failed\n", __func__); err = -EFAULT; goto error_out; } - raw_spin_lock(&comm_ctx.mmaps_lock); - mmap = find_mmap((unsigned long)mmap_rb.vm_start); - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_lock(&comm_ctx.ctx->mmaps_lock); + + mmap = find_mmap_by_vma((unsigned long)mmap_rb.vm_start); if (!mmap) { - pr_err("%s: error: mmap is not found\n", __func__); + pr_err("set_mmap_rb: mmap is not found, start: %#lx\n", + (unsigned long)mmap_rb.vm_start); + err = -ENXIO; + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); + goto error_out; + } + + if (mmap->type != QUADD_MMAP_TYPE_NONE) { + pr_err("set_mmap_rb: wrong mmap: %d, start: %#lx\n", + mmap->type, mmap->mmap_vma->vm_start); err = -ENXIO; + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); goto error_out; } + mmap->type = QUADD_MMAP_TYPE_RB; err = init_mmap_hdr(&mmap_rb, mmap); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); if (err) { - pr_err("%s: error: init_mmap_hdr\n", __func__); + pr_err("set_mmap_rb: error: init_mmap_hdr\n"); goto error_out; } @@ -742,7 +779,7 @@ remove_mmap_entry(struct quadd_mmap_area *mmap) { struct quadd_mmap_area *entry, *next; - list_for_each_entry_safe(entry, next, &comm_ctx.mmap_areas, list) { + list_for_each_entry_safe(entry, next, &comm_ctx.ctx->mmap_areas, list) { if (entry == mmap) { list_del(&entry->list); break; @@ -760,18 +797,18 @@ static void mmap_close(struct vm_area_struct *vma) { struct quadd_mmap_area *mmap; - pr_debug("%s: mmap_close: vma: %#lx - %#lx\n", - __func__, vma->vm_start, vma->vm_end); - - raw_spin_lock(&comm_ctx.mmaps_lock); + raw_spin_lock(&comm_ctx.ctx->mmaps_lock); - mmap = find_mmap(vma->vm_start); + mmap = find_mmap_by_vma(vma->vm_start); if (!mmap) { - pr_err("%s: error: mmap is not found\n", __func__); + pr_err("%s: error: mmap is not found: vma: %#lx - %#lx\n", + __func__, vma->vm_start, vma->vm_end); goto out; } - pr_debug("mmap_close: type: %d\n", mmap->type); + pr_debug("%s: mmap: %p: type: %d, %#lx - %#lx, data: %p\n", + __func__, mmap, mmap->type, mmap->mmap_vma->vm_start, + mmap->mmap_vma->vm_end, mmap->data); if (mmap->type == QUADD_MMAP_TYPE_EXTABS) comm_ctx.control->delete_mmap(mmap); @@ -783,7 +820,7 @@ static void mmap_close(struct vm_area_struct *vma) remove_mmap_entry(mmap); out: - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); if (mmap) { vfree(mmap->data); @@ -812,11 +849,11 @@ static int mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vma->vm_start, vma->vm_end, vmf->pgoff, vmf->virtual_address); #endif - raw_spin_lock(&comm_ctx.mmaps_lock); + raw_spin_lock(&comm_ctx.ctx->mmaps_lock); - mmap = find_mmap(vma->vm_start); + mmap = find_mmap_by_vma(vma->vm_start); if (!mmap) { - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); return VM_FAULT_SIGBUS; } @@ -825,7 +862,7 @@ static int mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vmf->page = vmalloc_to_page(data + offset); get_page(vmf->page); - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); return 0; } @@ -841,9 +878,6 @@ device_mmap(struct file *filp, struct vm_area_struct *vma) unsigned long vma_size, nr_pages; struct quadd_mmap_area *entry; - pr_debug("mmap: vma: %#lx - %#lx, pgoff: %#lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); - if (vma->vm_pgoff != 0) return -EINVAL; @@ -874,13 +908,12 @@ device_mmap(struct file *filp, struct vm_area_struct *vma) entry->type = QUADD_MMAP_TYPE_NONE; - pr_debug("%s: data: %p - %p (%#lx)\n", - __func__, entry->data, entry->data + nr_pages * PAGE_SIZE, - nr_pages * PAGE_SIZE); + pr_debug("%s: mmap: %p, vma: %#lx - %#lx, data: %p\n", + __func__, entry, vma->vm_start, vma->vm_end, entry->data); - raw_spin_lock(&comm_ctx.mmaps_lock); - list_add_tail(&entry->list, &comm_ctx.mmap_areas); - raw_spin_unlock(&comm_ctx.mmaps_lock); + raw_spin_lock(&comm_ctx.ctx->mmaps_lock); + list_add_tail(&entry->list, &comm_ctx.ctx->mmap_areas); + raw_spin_unlock(&comm_ctx.ctx->mmaps_lock); vma->vm_ops = &mmap_vm_ops; vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP; @@ -930,8 +963,8 @@ static int comm_init(void) comm_ctx.nr_users = 0; - INIT_LIST_HEAD(&comm_ctx.mmap_areas); - raw_spin_lock_init(&comm_ctx.mmaps_lock); + INIT_LIST_HEAD(&comm_ctx.ctx->mmap_areas); + raw_spin_lock_init(&comm_ctx.ctx->mmaps_lock); for_each_possible_cpu(cpu_id) { struct comm_cpu_context *cc = &per_cpu(cpu_ctx, cpu_id); diff --git a/drivers/misc/tegra-profiler/comm.h b/drivers/misc/tegra-profiler/comm.h index 4ad06e404..e2be1b024 100644 --- a/drivers/misc/tegra-profiler/comm.h +++ b/drivers/misc/tegra-profiler/comm.h @@ -18,6 +18,7 @@ #define __QUADD_COMM_H__ #include +#include "eh_unwind.h" struct quadd_ctx; struct quadd_record_data; @@ -60,6 +61,8 @@ struct quadd_mmap_area { atomic_t state; atomic_t ref_count; raw_spinlock_t state_lock; + + struct file_ex_region_info fi; }; struct quadd_comm_control_interface { diff --git a/drivers/misc/tegra-profiler/dwarf_unwind.c b/drivers/misc/tegra-profiler/dwarf_unwind.c index cb7cbee35..7ff33ad6c 100644 --- a/drivers/misc/tegra-profiler/dwarf_unwind.c +++ b/drivers/misc/tegra-profiler/dwarf_unwind.c @@ -229,8 +229,8 @@ is_frame_present(struct ex_region_info *ri, int is_eh) { struct extab_info *ti, *ti_hdr; - ti = &ri->ex_sec[get_secid_frame(is_eh)]; - ti_hdr = &ri->ex_sec[get_secid_frame_hdr(is_eh)]; + ti = &ri->mmap->fi.ex_sec[get_secid_frame(is_eh)]; + ti_hdr = &ri->mmap->fi.ex_sec[get_secid_frame_hdr(is_eh)]; return (ti->length && ti_hdr->length) ? 1 : 0; } @@ -246,11 +246,15 @@ validate_addr(struct ex_region_info *ri, unsigned long start, end; mmap = ri->mmap; + if (unlikely(!mmap)) { + pr_warn_once("%s: !mmap\n", __func__); + return 0; + } if (atomic_read(&mmap->state) != QUADD_MMAP_STATE_ACTIVE) return 0; - ti = &ri->ex_sec[st]; + ti = &mmap->fi.ex_sec[st]; start = (unsigned long)mmap->data + ti->mmap_offset; end = start + ti->length; @@ -381,11 +385,24 @@ ex_addr_to_mmap_addr(unsigned long addr, { unsigned long offset; struct extab_info *ti; + struct quadd_mmap_area *mmap; + + mmap = ri->mmap; + if (unlikely(!mmap)) { + pr_warn_once("%s: !mmap\n", __func__); + return 0; + } + + ti = &mmap->fi.ex_sec[st]; + offset = addr - get_ex_sec_address(ri, ti, st); - ti = &ri->ex_sec[st]; - offset = addr - ti->addr; + pr_debug("addr: %#lx, data: %p, st: %d, ri vma: %#lx-%#lx\n", + addr, mmap->data, st, ri->vm_start, ri->vm_end); + pr_debug("ti addr/len/mmap_of:%#lx/%#lx/%#lx, offset:%#lx, res:%#lx\n", + ti->addr, ti->length, ti->mmap_offset, + offset, ti->mmap_offset + offset + (unsigned long)mmap->data); - return ti->mmap_offset + offset + (unsigned long)ri->mmap->data; + return ti->mmap_offset + offset + (unsigned long)mmap->data; } static inline unsigned long @@ -394,11 +411,24 @@ mmap_addr_to_ex_addr(unsigned long addr, { unsigned long offset; struct extab_info *ti; + struct quadd_mmap_area *mmap; + + mmap = ri->mmap; + if (unlikely(!mmap)) { + pr_warn_once("%s: !mmap\n", __func__); + return 0; + } + + ti = &mmap->fi.ex_sec[st]; + offset = addr - ti->mmap_offset - (unsigned long)mmap->data; - ti = &ri->ex_sec[st]; - offset = addr - ti->mmap_offset - (unsigned long)ri->mmap->data; + pr_debug("addr: %#lx, data: %p, st: %d, ri vma: %#lx-%#lx\n", + addr, mmap->data, st, ri->vm_start, ri->vm_end); + pr_debug("ti addr/len/mmap_of:%#lx/%#lx/%#lx, offset:%#lx, res:%#lx\n", + ti->addr, ti->length, ti->mmap_offset, + offset, get_ex_sec_address(ri, ti, st) + offset); - return ti->addr + offset; + return get_ex_sec_address(ri, ti, st) + offset; } static int @@ -409,11 +439,11 @@ get_section_index_by_address(struct ex_region_info *ri, struct extab_info *ti; unsigned long start, end; - for (i = 0; i < ARRAY_SIZE(ri->ex_sec); i++) { - ti = &ri->ex_sec[i]; + for (i = 0; i < ARRAY_SIZE(ri->mmap->fi.ex_sec); i++) { + ti = &ri->mmap->fi.ex_sec[i]; if (ti->length > 0) { - start = ti->addr; + start = get_ex_sec_address(ri, ti, i); end = start + ti->length; if (addr >= start && addr < end) @@ -1470,7 +1500,8 @@ dwarf_get_bs_table(struct ex_region_info *ri, secid_hdr = get_secid_frame_hdr(is_eh); if (hdr->version != 1) { - pr_warn_once("warning: unknown eh hdr format\n"); + pr_warn_once("warning: unknown eh hdr format: %u\n", + (unsigned int)hdr->version); return NULL; } p = (unsigned char *)(hdr + 1); @@ -1504,7 +1535,8 @@ dwarf_get_bs_table(struct ex_region_info *ri, return NULL; if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { - pr_warn_once("warning: unknown eh hdr format\n"); + pr_warn_once("warning: unknown eh hdr format: %u\n", + (unsigned int)hdr->version); return NULL; } @@ -1533,9 +1565,9 @@ dwarf_decode_fde_cie(struct ex_region_info *ri, struct extab_info *ti; secid = get_secid_frame(is_eh); - ti = &ri->ex_sec[secid]; + ti = &ri->mmap->fi.ex_sec[secid]; - addr = ti->addr; + addr = get_ex_sec_address(ri, ti, secid); frame_start = (unsigned char *) ex_addr_to_mmap_addr(addr, ri, secid); @@ -1606,7 +1638,8 @@ dwarf_find_fde(struct ex_region_info *ri, void *data, unsigned long length, unsigned long pc, - int is_eh) + int is_eh, + struct task_struct *task) { long err; int secid, secid_hdr; @@ -1619,8 +1652,8 @@ dwarf_find_fde(struct ex_region_info *ri, secid = get_secid_frame(is_eh); secid_hdr = get_secid_frame_hdr(is_eh); - ti = &ri->ex_sec[secid_hdr]; - data_base = ti->addr; + ti = &ri->mmap->fi.ex_sec[secid_hdr]; + data_base = get_ex_sec_address(ri, ti, secid_hdr); bst = dwarf_get_bs_table(ri, data, length, data_base, &fde_count, is_eh); @@ -1636,7 +1669,7 @@ dwarf_find_fde(struct ex_region_info *ri, if (pc >= init_loc) { unsigned long start, end; - struct extab_info *ti = &ri->ex_sec[secid]; + struct extab_info *ti = &ri->mmap->fi.ex_sec[secid]; fde_addr = dw_bst_get_fde_addr(fi, data_base); fde_addr = ex_addr_to_mmap_addr(fde_addr, ri, @@ -1661,8 +1694,8 @@ dwarf_find_fde(struct ex_region_info *ri, end = start + fde.address_range; if (sf && !sf->is_sched) - quadd_unwind_set_tail_info(ri->vm_start, secid, - start, end); + quadd_unwind_set_tail_info(ri, secid, + start, end, task); } pr_debug("pc: %#lx, last bst entry: %#lx - %#lx", @@ -1683,7 +1716,8 @@ dwarf_find_fde(struct ex_region_info *ri, } static int -__is_fde_entry_exist(struct ex_region_info *ri, unsigned long addr, int is_eh) +__is_fde_entry_exist(struct ex_region_info *ri, unsigned long addr, + int is_eh, struct task_struct *task) { int secid_hdr; unsigned char *fde_p; @@ -1693,16 +1727,16 @@ __is_fde_entry_exist(struct ex_region_info *ri, unsigned long addr, int is_eh) secid_hdr = get_secid_frame_hdr(is_eh); - ti = &ri->ex_sec[secid_hdr]; + ti = &ri->mmap->fi.ex_sec[secid_hdr]; - a = ti->addr; + a = get_ex_sec_address(ri, ti, secid_hdr); hdr_start = (unsigned char *) ex_addr_to_mmap_addr(a, ri, secid_hdr); hdr_len = ti->length; - fde_p = dwarf_find_fde(ri, NULL, hdr_start, hdr_len, addr, is_eh); + fde_p = dwarf_find_fde(ri, NULL, hdr_start, hdr_len, addr, is_eh, task); return fde_p ? 1 : 0; } @@ -1711,18 +1745,19 @@ static int is_fde_entry_exist(struct ex_region_info *ri, unsigned long addr, int *is_eh, - int *is_debug) + int *is_debug, + struct task_struct *task) { *is_eh = 0; *is_debug = 0; if (is_frame_present(ri, 1)) { - if (__is_fde_entry_exist(ri, addr, 1)) + if (__is_fde_entry_exist(ri, addr, 1, task)) *is_eh = 1; } if (is_frame_present(ri, 0)) { - if (__is_fde_entry_exist(ri, addr, 0)) + if (__is_fde_entry_exist(ri, addr, 0, task)) *is_debug = 1; } @@ -1735,7 +1770,8 @@ dwarf_decode(struct ex_region_info *ri, struct dw_cie *cie, struct dw_fde *fde, unsigned long pc, - int is_eh) + int is_eh, + struct task_struct *task) { long err; int secid_hdr; @@ -1745,9 +1781,9 @@ dwarf_decode(struct ex_region_info *ri, struct extab_info *ti; secid_hdr = get_secid_frame_hdr(is_eh); - ti = &ri->ex_sec[secid_hdr]; + ti = &ri->mmap->fi.ex_sec[secid_hdr]; - addr = ti->addr; + addr = get_ex_sec_address(ri, ti, secid_hdr); hdr_start = (unsigned char *) ex_addr_to_mmap_addr(addr, ri, secid_hdr); @@ -1757,7 +1793,7 @@ dwarf_decode(struct ex_region_info *ri, pr_debug("eh frame hdr: %p - %p\n", hdr_start, hdr_start + hdr_len); - fde_p = dwarf_find_fde(ri, sf, hdr_start, hdr_len, pc, is_eh); + fde_p = dwarf_find_fde(ri, sf, hdr_start, hdr_len, pc, is_eh, task); if (!fde_p) return -QUADD_URC_IDX_NOT_FOUND; @@ -1798,7 +1834,8 @@ static long unwind_frame(struct ex_region_info *ri, struct stackframe *sf, struct vm_area_struct *vma_sp, - int is_eh) + int is_eh, + struct task_struct *task) { int i, num_regs; long err; @@ -1810,7 +1847,7 @@ unwind_frame(struct ex_region_info *ri, struct regs_state *rs, *rs_initial; int mode = sf->mode; - err = dwarf_decode(ri, sf, &cie, &fde, pc, is_eh); + err = dwarf_decode(ri, sf, &cie, &fde, pc, is_eh, task); if (err < 0) return err; @@ -1984,7 +2021,8 @@ unwind_backtrace(struct quadd_callchain *cc, prev_ri = NULL; } - err = quadd_get_dw_frames(vma_pc->vm_start, &ri_new); + err = quadd_get_dw_frames(vma_pc->vm_start, + &ri_new, task); if (err) { cc->urc_dwarf = QUADD_URC_TBL_NOT_EXIST; break; @@ -1996,7 +2034,8 @@ unwind_backtrace(struct quadd_callchain *cc, prev_ri = ri = &ri_new; } - if (!is_fde_entry_exist(ri, sf->pc, &__is_eh, &__is_debug)) { + if (!is_fde_entry_exist(ri, sf->pc, &__is_eh, + &__is_debug, task)) { pr_debug("eh/debug fde entries are not existed\n"); cc->urc_dwarf = QUADD_URC_IDX_NOT_FOUND; break; @@ -2011,12 +2050,12 @@ unwind_backtrace(struct quadd_callchain *cc, is_eh = 1; } - err = unwind_frame(ri, sf, vma_sp, is_eh); + err = unwind_frame(ri, sf, vma_sp, is_eh, task); if (err < 0) { if (__is_eh && __is_debug) { is_eh ^= 1; - err = unwind_frame(ri, sf, vma_sp, is_eh); + err = unwind_frame(ri, sf, vma_sp, is_eh, task); if (err < 0) { cc->urc_dwarf = -err; break; @@ -2068,7 +2107,8 @@ quadd_is_ex_entry_exist_dwarf(struct quadd_event_context *event_ctx, struct ex_region_info ri; struct vm_area_struct *vma; struct pt_regs *regs = event_ctx->regs; - struct mm_struct *mm = event_ctx->task->mm; + struct task_struct *task = event_ctx->task; + struct mm_struct *mm = task->mm; if (!regs || !mm) return 0; @@ -2077,11 +2117,11 @@ quadd_is_ex_entry_exist_dwarf(struct quadd_event_context *event_ctx, if (!vma) return 0; - err = quadd_get_dw_frames(vma->vm_start, &ri); + err = quadd_get_dw_frames(vma->vm_start, &ri, task); if (err) return 0; - res = is_fde_entry_exist(&ri, addr, &is_eh, &is_debug); + res = is_fde_entry_exist(&ri, addr, &is_eh, &is_debug, task); quadd_put_dw_frames(&ri); return res; @@ -2142,9 +2182,10 @@ quadd_get_user_cc_dwarf(struct quadd_event_context *event_ctx, mode = DW_MODE_ARM32; #endif - pr_debug("%s: pc: %#lx, lr: %#lx\n", __func__, ip, lr); - pr_debug("%s: sp: %#lx, fp: %#lx, fp_thumb: %#lx\n", - __func__, sp, fp, fp_thumb); + pr_debug("%s: pid: %u, pc: %#lx, lr: %#lx\n", + __func__, task_tgid_nr(task), ip, lr); + pr_debug("%s: pid: %u, sp: %#lx, fp: %#lx, fp_thumb: %#lx\n", + __func__, task_tgid_nr(task), sp, fp, fp_thumb); sf = &cpu_ctx->sf; @@ -2172,7 +2213,7 @@ quadd_get_user_cc_dwarf(struct quadd_event_context *event_ctx, if (!vma_sp) return 0; - err = quadd_get_dw_frames(vma->vm_start, &ri); + err = quadd_get_dw_frames(vma->vm_start, &ri, task); if (err) { cc->urc_dwarf = QUADD_URC_TBL_NOT_EXIST; return 0; @@ -2181,7 +2222,8 @@ quadd_get_user_cc_dwarf(struct quadd_event_context *event_ctx, unwind_backtrace(cc, &ri, sf, vma_sp, task); quadd_put_dw_frames(&ri); - pr_debug("%s: mode: %s, cc->nr: %d --> %d\n", __func__, + pr_debug("%s: pid: %u: mode: %s, cc->nr: %d --> %d\n", + __func__, task_tgid_nr(task), (mode == DW_MODE_ARM32) ? "arm32" : "arm64", nr_prev, cc->nr); diff --git a/drivers/misc/tegra-profiler/eh_unwind.c b/drivers/misc/tegra-profiler/eh_unwind.c index acf71799f..20ec16338 100644 --- a/drivers/misc/tegra-profiler/eh_unwind.c +++ b/drivers/misc/tegra-profiler/eh_unwind.c @@ -25,6 +25,7 @@ #include +#include "quadd.h" #include "hrt.h" #include "tegra.h" #include "eh_unwind.h" @@ -33,7 +34,7 @@ #include "dwarf_unwind.h" #include "disassembler.h" -#define QUADD_EXTABS_SIZE 0x100 +#define QUADD_EXTABS_SIZE 32 #define GET_NR_PAGES(a, l) \ ((PAGE_ALIGN((a) + (l)) - ((a) & PAGE_MASK)) / PAGE_SIZE) @@ -50,18 +51,23 @@ enum regs { struct regions_data { struct ex_region_info *entries; - unsigned long curr_nr; + unsigned long nr_entries; unsigned long size; + pid_t pid; + struct rcu_head rcu; + + struct list_head list; }; struct quadd_unwind_ctx { - struct regions_data __rcu *rd; + struct quadd_ctx *quadd_ctx; - pid_t pid; unsigned long ex_tables_size; - raw_spinlock_t lock; + + struct list_head mm_ex_list; + raw_spinlock_t mm_ex_list_lock; }; struct unwind_idx { @@ -90,8 +96,39 @@ struct pin_pages_work { unsigned long vm_start; }; +struct ex_entry_node { + struct list_head list; + pid_t pid; + unsigned long vm_start; + unsigned long vm_end; +}; + static struct quadd_unwind_ctx ctx; +static inline int is_debug_frame(int secid) +{ + return (secid == QUADD_SEC_TYPE_DEBUG_FRAME || + secid == QUADD_SEC_TYPE_DEBUG_FRAME_HDR) ? 1 : 0; +} + +unsigned long +get_ex_sec_address(struct ex_region_info *ri, struct extab_info *ti, int secid) +{ + struct quadd_mmap_area *mmap; + unsigned long res = ti->addr; + + mmap = ri->mmap; + if (unlikely(!mmap)) { + pr_warn_once("%s: !mmap\n", __func__); + return 0; + } + + if (!(is_debug_frame(secid) && !mmap->fi.is_shared)) + res += ri->vm_start; + + return res; +} + static inline int validate_mmap_addr(struct quadd_mmap_area *mmap, unsigned long addr, unsigned long nbytes) @@ -142,13 +179,20 @@ ex_addr_to_mmap_addr(unsigned long addr, { unsigned long offset; struct extab_info *ti; + struct quadd_mmap_area *mmap; - ti = &ri->ex_sec[sec_type]; + mmap = ri->mmap; + if (unlikely(!mmap)) { + pr_warn_once("%s: !mmap\n", __func__); + return 0; + } + + ti = &mmap->fi.ex_sec[sec_type]; if (unlikely(!ti->length)) return 0; - offset = addr - ti->addr; - return ti->mmap_offset + offset + (unsigned long)ri->mmap->data; + offset = addr - get_ex_sec_address(ri, ti, sec_type); + return ti->mmap_offset + offset + (unsigned long)mmap->data; } static inline unsigned long @@ -158,13 +202,20 @@ mmap_addr_to_ex_addr(unsigned long addr, { unsigned long offset; struct extab_info *ti; + struct quadd_mmap_area *mmap; - ti = &ri->ex_sec[sec_type]; + mmap = ri->mmap; + if (unlikely(!mmap)) { + pr_warn_once("%s: !mmap\n", __func__); + return 0; + } + + ti = &mmap->fi.ex_sec[sec_type]; if (unlikely(!ti->length)) return 0; - offset = addr - ti->mmap_offset - (unsigned long)ri->mmap->data; - return ti->addr + offset; + offset = addr - ti->mmap_offset - (unsigned long)mmap->data; + return get_ex_sec_address(ri, ti, sec_type) + offset; } static inline u32 __maybe_unused @@ -207,22 +258,58 @@ mmap_prel31_to_addr(const u32 *ptr, struct ex_region_info *ri, return addr_res; } +static struct regions_data *rd_alloc(unsigned long size) +{ + struct regions_data *rd; + + rd = kzalloc(sizeof(*rd), GFP_ATOMIC); + if (!rd) + return ERR_PTR(-ENOMEM); + + rd->entries = kcalloc(size, sizeof(*rd->entries), GFP_ATOMIC); + if (!rd->entries) { + kfree(rd); + return ERR_PTR(-ENOMEM); + } + + rd->size = size; + rd->nr_entries = 0; + + return rd; +} + +static void rd_free(struct regions_data *rd) +{ + if (rd) + kfree(rd->entries); + + kfree(rd); +} + +static void mm_ex_list_free_rcu(struct rcu_head *head) +{ + struct regions_data *entry = + container_of(head, struct regions_data, rcu); + + rd_free(entry); +} + static int add_ex_region(struct regions_data *rd, struct ex_region_info *new_entry) { unsigned int i_min, i_max, mid; struct ex_region_info *array = rd->entries; - unsigned long size = rd->curr_nr; + unsigned long size = rd->nr_entries; if (!array) - return 0; + return -ENOMEM; if (size == 0) { memcpy(&array[0], new_entry, sizeof(*new_entry)); - return 1; - } else if (size == 1 && array[0].vm_start == new_entry->vm_start) { return 0; + } else if (size == 1 && array[0].vm_start == new_entry->vm_start) { + return -EEXIST; } i_min = 0; @@ -232,10 +319,10 @@ add_ex_region(struct regions_data *rd, memmove(array + 1, array, size * sizeof(*array)); memcpy(&array[0], new_entry, sizeof(*new_entry)); - return 1; + return 0; } else if (array[size - 1].vm_start < new_entry->vm_start) { memcpy(&array[size], new_entry, sizeof(*new_entry)); - return 1; + return 0; } while (i_min < i_max) { @@ -248,13 +335,14 @@ add_ex_region(struct regions_data *rd, } if (array[i_max].vm_start == new_entry->vm_start) - return 0; + return -EEXIST; memmove(array + i_max + 1, array + i_max, (size - i_max) * sizeof(*array)); memcpy(&array[i_max], new_entry, sizeof(*new_entry)); - return 1; + + return 0; } static int @@ -263,7 +351,7 @@ remove_ex_region(struct regions_data *rd, { unsigned int i_min, i_max, mid; struct ex_region_info *array = rd->entries; - unsigned long size = rd->curr_nr; + unsigned long size = rd->nr_entries; if (!array) return 0; @@ -334,34 +422,242 @@ __search_ex_region(struct ex_region_info *array, } static long -search_ex_region(unsigned long key, struct ex_region_info *ri) +search_ex_region(pid_t pid, unsigned long key, struct ex_region_info *ri) { - struct regions_data *rd; + struct regions_data *entry; struct ex_region_info *ri_p = NULL; rcu_read_lock(); + list_for_each_entry_rcu(entry, &ctx.mm_ex_list, list) { + if (entry->pid == pid) { + ri_p = __search_ex_region(entry->entries, + entry->nr_entries, key); + if (ri_p) + memcpy(ri, ri_p, sizeof(*ri)); + break; + } + } + rcu_read_unlock(); - rd = rcu_dereference(ctx.rd); - if (!rd) - goto out; + return ri_p ? 0 : -ENOENT; +} - ri_p = __search_ex_region(rd->entries, rd->curr_nr, key); - if (ri_p) - memcpy(ri, ri_p, sizeof(*ri)); +static inline int +validate_sections(struct quadd_sections *et) +{ + int i; + unsigned long size = 0; -out: - rcu_read_unlock(); - return ri_p ? 0 : -ENOENT; + if (et->vm_start >= et->vm_end) + return -EINVAL; + + for (i = 0; i < QUADD_SEC_TYPE_MAX; i++) + size += et->sec[i].length; + + return size < et->vm_end - et->vm_start; +} + +static void +mmap_ex_entry_del(struct quadd_mmap_area *mmap, + pid_t pid, unsigned long vm_start) +{ + struct ex_entry_node *e, *n; + + list_for_each_entry_safe(e, n, &mmap->ex_entries, list) { + if (e->pid == pid && e->vm_start == vm_start) { + list_del(&e->list); + kfree(e); + break; + } + } +} + +static int +is_overlapped(unsigned long a_start, unsigned long a_end, + unsigned long b_start, unsigned long b_end) +{ + return ((a_start >= b_start && a_start < b_end) || + (b_start >= a_start && b_start < a_end)); +} + +static int +remove_overlapped_regions(struct regions_data *rd, struct ex_region_info *ri) +{ + long idx_from = -1, idx_to = -1; + unsigned long i, start, end, nr, nr_removed = 0; + struct ex_region_info *array = rd->entries; + + nr = rd->nr_entries; + if (nr == 0) + return 0; + + for (i = 0; i < nr; i++) { + start = array[i].vm_start; + end = array[i].vm_end; + + if (is_overlapped(start, end, ri->vm_start, ri->vm_end)) { + idx_from = idx_to = i; + for (idx_to = i + 1; idx_to < nr; idx_to++) { + start = array[idx_to].vm_start; + end = array[idx_to].vm_end; + if (!is_overlapped(start, end, ri->vm_start, + ri->vm_end)) + break; + } + break; + } + } + + if (idx_from >= 0) { + struct ex_region_info *ri_del; + unsigned long nr_copied = nr - idx_to; + + nr_removed = idx_to - idx_from; + + pr_debug("%s: [%u] new: %#lx-%#lx, rm:%#lx-%#lx...%#lx-%#lx\n", + __func__, rd->pid, ri->vm_start, ri->vm_end, + array[idx_from].vm_start, array[idx_from].vm_end, + array[idx_to - 1].vm_start, array[idx_to - 1].vm_end); + + if (nr_copied > 0) + memmove(array + idx_from, array + idx_to, + nr_copied * sizeof(*array)); + + for (i = idx_from; i < idx_to; i++) { + ri_del = &array[i]; + mmap_ex_entry_del(ri_del->mmap, rd->pid, + ri_del->vm_start); + } + + rd->nr_entries -= nr_removed; + } + + return nr_removed; +} + +static int +mm_ex_list_add(struct ex_region_info *ri, pid_t pid) +{ + int err = 0; + struct regions_data *entry, *rd, *rd_old = NULL; + unsigned long nr_entries_new; + + raw_spin_lock(&ctx.mm_ex_list_lock); + + list_for_each_entry(entry, &ctx.mm_ex_list, list) { + if (entry->pid == pid) { + rd_old = entry; + break; + } + } + + nr_entries_new = rd_old ? rd_old->nr_entries + 1 : 1; + + rd = rd_alloc(nr_entries_new); + if (IS_ERR(rd)) { + err = PTR_ERR(rd); + goto out_unlock; + } + + if (rd_old) { + memcpy(rd->entries, rd_old->entries, + rd_old->nr_entries * sizeof(*rd_old->entries)); + rd->nr_entries = rd_old->nr_entries; + rd->pid = pid; + remove_overlapped_regions(rd, ri); + } + + err = add_ex_region(rd, ri); + if (err < 0) + goto out_free; + + rd->nr_entries++; + + rd->pid = pid; + INIT_LIST_HEAD(&rd->list); + + if (rd_old) { + list_replace_rcu(&rd_old->list, &rd->list); + call_rcu(&rd_old->rcu, mm_ex_list_free_rcu); + } else { + list_add_tail_rcu(&rd->list, &ctx.mm_ex_list); + } + + raw_spin_unlock(&ctx.mm_ex_list_lock); + return 0; + +out_free: + rd_free(rd); +out_unlock: + raw_spin_unlock(&ctx.mm_ex_list_lock); + + return err; +} + +static int +mm_ex_list_del(unsigned long vm_start, pid_t pid) +{ + int err = 0, nr_removed; + unsigned long nr_entries; + struct regions_data *rd_entry, *rd_new; + struct ex_region_info ex_entry; + + ex_entry.vm_start = vm_start; + + raw_spin_lock(&ctx.mm_ex_list_lock); + + list_for_each_entry(rd_entry, &ctx.mm_ex_list, list) { + if (rd_entry->pid == pid) { + nr_entries = rd_entry->nr_entries; + + if (unlikely(nr_entries == 0)) { + pr_warn_once("%s: !nr_entries\n", __func__); + err = -ENOENT; + goto out_unlock; + } + + rd_new = rd_alloc(nr_entries); + if (IS_ERR(rd_new)) { + err = PTR_ERR(rd_new); + goto out_unlock; + } + + memcpy(rd_new->entries, rd_entry->entries, + nr_entries * sizeof(*rd_entry->entries)); + rd_new->nr_entries = nr_entries; + + rd_new->pid = pid; + INIT_LIST_HEAD(&rd_new->list); + + nr_removed = remove_ex_region(rd_new, &ex_entry); + rd_new->nr_entries -= nr_removed; + + if (rd_new->nr_entries > 0) { + list_replace_rcu(&rd_entry->list, + &rd_new->list); + call_rcu(&rd_entry->rcu, mm_ex_list_free_rcu); + } else { + rd_free(rd_new); + list_del_rcu(&rd_entry->list); + call_rcu(&rd_entry->rcu, mm_ex_list_free_rcu); + } + } + } + +out_unlock: + raw_spin_unlock(&ctx.mm_ex_list_lock); + + return err; } static long -get_extabs_ehabi(unsigned long key, struct ex_region_info *ri) +get_extabs_ehabi(pid_t pid, unsigned long key, struct ex_region_info *ri) { long err = 0; struct extab_info *ti_exidx; struct quadd_mmap_area *mmap; - err = search_ex_region(key, ri); + err = search_ex_region(pid, key, ri); if (err < 0) return err; @@ -374,7 +670,7 @@ get_extabs_ehabi(unsigned long key, struct ex_region_info *ri) goto out; } - ti_exidx = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX]; + ti_exidx = &mmap->fi.ex_sec[QUADD_SEC_TYPE_EXIDX]; if (ti_exidx->length) atomic_inc(&mmap->ref_count); @@ -403,13 +699,17 @@ static void put_extabs_ehabi(struct ex_region_info *ri) } long -quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri) +quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri, + struct task_struct *task) { + pid_t pid; long err = 0; struct extab_info *ti, *ti_hdr; struct quadd_mmap_area *mmap; - err = search_ex_region(key, ri); + pid = task_tgid_nr(task); + + err = search_ex_region(pid, key, ri); if (err < 0) return err; @@ -422,16 +722,16 @@ quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri) goto out; } - ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME]; - ti_hdr = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR]; + ti = &mmap->fi.ex_sec[QUADD_SEC_TYPE_EH_FRAME]; + ti_hdr = &mmap->fi.ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR]; if (ti->length && ti_hdr->length) { atomic_inc(&mmap->ref_count); goto out; } - ti = &ri->ex_sec[QUADD_SEC_TYPE_DEBUG_FRAME]; - ti_hdr = &ri->ex_sec[QUADD_SEC_TYPE_DEBUG_FRAME_HDR]; + ti = &mmap->fi.ex_sec[QUADD_SEC_TYPE_DEBUG_FRAME]; + ti_hdr = &mmap->fi.ex_sec[QUADD_SEC_TYPE_DEBUG_FRAME_HDR]; if (ti->length && ti_hdr->length) atomic_inc(&mmap->ref_count); @@ -459,252 +759,118 @@ void quadd_put_dw_frames(struct ex_region_info *ri) pr_err_once("%s: error: mmap ref_count\n", __func__); } -static struct regions_data *rd_alloc(unsigned long size) -{ - struct regions_data *rd; - - rd = kzalloc(sizeof(*rd), GFP_ATOMIC); - if (!rd) - return NULL; - - rd->entries = kcalloc(size, sizeof(*rd->entries), GFP_ATOMIC); - if (!rd->entries) { - kfree(rd); - return NULL; - } - - rd->size = size; - rd->curr_nr = 0; - - return rd; -} - -static void rd_free(struct regions_data *rd) -{ - if (rd) - kfree(rd->entries); - - kfree(rd); -} - -static void rd_free_rcu(struct rcu_head *rh) -{ - struct regions_data *rd = container_of(rh, struct regions_data, rcu); - - rd_free(rd); -} - int quadd_unwind_set_extab(struct quadd_sections *extabs, struct quadd_mmap_area *mmap) { - int i, err = 0; - unsigned long nr_entries, nr_added, new_size; + int i, err; struct ex_region_info ri_entry; - struct extab_info *ti; - struct regions_data *rd, *rd_new; - struct ex_region_info *ex_entry; + struct ex_entry_node *mmap_ex_entry; if (mmap->type != QUADD_MMAP_TYPE_EXTABS) return -EIO; - raw_spin_lock(&ctx.lock); - - rd = rcu_dereference(ctx.rd); - if (!rd) { - pr_warn("%s: warning: rd\n", __func__); - new_size = QUADD_EXTABS_SIZE; - nr_entries = 0; - } else { - new_size = rd->size; - nr_entries = rd->curr_nr; - } - - if (nr_entries >= new_size) - new_size += new_size >> 1; - - rd_new = rd_alloc(new_size); - if (IS_ERR_OR_NULL(rd_new)) { - pr_err("%s: error: rd_alloc\n", __func__); - err = -ENOMEM; - goto error_out; - } - - if (rd && nr_entries) - memcpy(rd_new->entries, rd->entries, - nr_entries * sizeof(*rd->entries)); - - rd_new->curr_nr = nr_entries; - - ri_entry.vm_start = extabs->vm_start; - ri_entry.vm_end = extabs->vm_end; + err = validate_sections(extabs); + if (err < 0) + return err; - ri_entry.mmap = mmap; + if (extabs->user_mmap_start) { + mmap->fi.is_shared = + (extabs->flags & QUADD_SECTIONS_FLAG_IS_SHARED) != 0; - for (i = 0; i < QUADD_SEC_TYPE_MAX; i++) { - struct quadd_sec_info *si = &extabs->sec[i]; + for (i = 0; i < QUADD_SEC_TYPE_MAX; i++) { + struct quadd_sec_info *si = &extabs->sec[i]; + struct extab_info *ti = &mmap->fi.ex_sec[i]; - ti = &ri_entry.ex_sec[i]; + ti->tf_start = 0; + ti->tf_end = 0; - ti->tf_start = 0; - ti->tf_end = 0; + if (!si->addr) { + ti->addr = 0; + ti->length = 0; + ti->mmap_offset = 0; - if (!si->addr) { - ti->addr = 0; - ti->length = 0; - ti->mmap_offset = 0; + continue; + } - continue; + ti->addr = si->addr; + ti->length = si->length; + ti->mmap_offset = si->mmap_offset; } - - ti->addr = si->addr; - ti->length = si->length; - ti->mmap_offset = si->mmap_offset; } - nr_added = add_ex_region(rd_new, &ri_entry); - if (nr_added == 0) - goto error_free; - - rd_new->curr_nr += nr_added; + ri_entry.vm_start = extabs->vm_start; + ri_entry.vm_end = extabs->vm_end; + ri_entry.file_hash = extabs->file_hash; + ri_entry.mmap = mmap; - ex_entry = kzalloc(sizeof(*ex_entry), GFP_ATOMIC); - if (!ex_entry) { + mmap_ex_entry = kzalloc(sizeof(*mmap_ex_entry), GFP_ATOMIC); + if (!mmap_ex_entry) { err = -ENOMEM; - goto error_free; + goto err_out; } - memcpy(ex_entry, &ri_entry, sizeof(*ex_entry)); - INIT_LIST_HEAD(&ex_entry->list); - list_add_tail(&ex_entry->list, &mmap->ex_entries); + mmap_ex_entry->vm_start = ri_entry.vm_start; + mmap_ex_entry->vm_end = ri_entry.vm_end; + mmap_ex_entry->pid = extabs->pid; - rcu_assign_pointer(ctx.rd, rd_new); + err = mm_ex_list_add(&ri_entry, extabs->pid); + if (err < 0) + goto out_ex_entry_free; - if (rd) - call_rcu(&rd->rcu, rd_free_rcu); + INIT_LIST_HEAD(&mmap_ex_entry->list); + list_add_tail(&mmap_ex_entry->list, &mmap->ex_entries); - raw_spin_unlock(&ctx.lock); + pr_debug("%s: pid: %u: vma: %#lx - %#lx, file_hash: %#x\n", + __func__, extabs->pid, (unsigned long)extabs->vm_start, + (unsigned long)extabs->vm_end, extabs->file_hash); return 0; -error_free: - rd_free(rd_new); -error_out: - raw_spin_unlock(&ctx.lock); +out_ex_entry_free: + kfree(mmap_ex_entry); +err_out: return err; } void -quadd_unwind_set_tail_info(unsigned long vm_start, +quadd_unwind_set_tail_info(struct ex_region_info *ri, int secid, unsigned long tf_start, - unsigned long tf_end) + unsigned long tf_end, + struct task_struct *task) { - struct ex_region_info *ri; - unsigned long nr_entries, size; - struct regions_data *rd, *rd_new; - struct extab_info *ti; - - raw_spin_lock(&ctx.lock); - - rd = rcu_dereference(ctx.rd); - - if (!rd || rd->curr_nr == 0) - goto error_out; - - size = rd->size; - nr_entries = rd->curr_nr; - - rd_new = rd_alloc(size); - if (IS_ERR_OR_NULL(rd_new)) { - pr_err_once("%s: error: rd_alloc\n", __func__); - goto error_out; - } - - memcpy(rd_new->entries, rd->entries, - nr_entries * sizeof(*rd->entries)); - - rd_new->curr_nr = nr_entries; - - ri = __search_ex_region(rd_new->entries, nr_entries, vm_start); - if (!ri) - goto error_free; - - ti = &ri->ex_sec[secid]; - - ti->tf_start = tf_start; - ti->tf_end = tf_end; - - rcu_assign_pointer(ctx.rd, rd_new); + struct quadd_mmap_area *mmap; - call_rcu(&rd->rcu, rd_free_rcu); - raw_spin_unlock(&ctx.lock); + raw_spin_lock(&ctx.quadd_ctx->mmaps_lock); - return; + mmap = ri->mmap; + mmap->fi.ex_sec[secid].tf_start = tf_start; + mmap->fi.ex_sec[secid].tf_end = tf_end; -error_free: - rd_free(rd_new); + pr_debug("%s: pid: %u, secid: %d, tf: %#lx - %#lx\n", + __func__, task_tgid_nr(task), secid, tf_start, tf_end); -error_out: - raw_spin_unlock(&ctx.lock); -} - -static int -clean_mmap(struct regions_data *rd, struct quadd_mmap_area *mmap, int rm_ext) -{ - int nr_removed = 0; - struct ex_region_info *entry, *next; - - if (!rd || !mmap) - return 0; - - list_for_each_entry_safe(entry, next, &mmap->ex_entries, list) { - if (rm_ext) - nr_removed += remove_ex_region(rd, entry); - - list_del(&entry->list); - kfree(entry); - } - - return nr_removed; + raw_spin_unlock(&ctx.quadd_ctx->mmaps_lock); } static void -__quadd_unwind_delete_mmap(struct quadd_mmap_area *mmap) +clean_mmap(struct quadd_mmap_area *mmap) { - unsigned long nr_entries, nr_removed, new_size; - struct regions_data *rd, *rd_new; + struct ex_entry_node *entry, *next; - if (!mmap) + if (atomic_read(&mmap->ref_count)) { + pr_warn_once("%s: ref_count != 0\n", __func__); return; - - raw_spin_lock(&ctx.lock); - - rd = rcu_dereference(ctx.rd); - if (!rd || !rd->curr_nr) - goto error_out; - - nr_entries = rd->curr_nr; - new_size = min_t(unsigned long, rd->size, nr_entries); - - rd_new = rd_alloc(new_size); - if (IS_ERR_OR_NULL(rd_new)) { - pr_err("%s: error: rd_alloc\n", __func__); - goto error_out; } - rd_new->size = new_size; - rd_new->curr_nr = nr_entries; - - memcpy(rd_new->entries, rd->entries, - nr_entries * sizeof(*rd->entries)); - nr_removed = clean_mmap(rd_new, mmap, 1); - rd_new->curr_nr -= nr_removed; - - rcu_assign_pointer(ctx.rd, rd_new); - call_rcu(&rd->rcu, rd_free_rcu); + if (!mmap || mmap->type != QUADD_MMAP_TYPE_EXTABS) + return; -error_out: - raw_spin_unlock(&ctx.lock); + list_for_each_entry_safe(entry, next, &mmap->ex_entries, list) { + mm_ex_list_del(entry->vm_start, entry->pid); + list_del(&entry->list); + kfree(entry); + } } static void mmap_wait_for_close(struct quadd_mmap_area *mmap) @@ -723,10 +889,10 @@ static void mmap_wait_for_close(struct quadd_mmap_area *mmap) cpu_relax(); } -void quadd_unwind_delete_mmap(struct quadd_mmap_area *mmap) +void quadd_unwind_clean_mmap(struct quadd_mmap_area *mmap) { mmap_wait_for_close(mmap); - __quadd_unwind_delete_mmap(mmap); + clean_mmap(mmap); } static const struct unwind_idx * @@ -739,8 +905,7 @@ unwind_find_idx(struct ex_region_info *ri, u32 addr, unsigned long *lowaddr) struct unwind_idx *stop; struct unwind_idx *mid = NULL; - ti = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX]; - + ti = &ri->mmap->fi.ex_sec[QUADD_SEC_TYPE_EXIDX]; length = ti->length / sizeof(*start); if (unlikely(!length)) @@ -1063,7 +1228,8 @@ unwind_frame(struct quadd_unw_methods um, struct ex_region_info *ri, struct stackframe *frame, struct vm_area_struct *vma_sp, - int thumbflag) + int thumbflag, + struct task_struct *task) { unsigned long high, low, min, max; const struct unwind_idx *idx; @@ -1208,7 +1374,7 @@ unwind_backtrace(struct quadd_callchain *cc, long err; int nr_added; struct extab_info *ti; - unsigned long where = frame->pc; + unsigned long addr, where = frame->pc; struct vm_area_struct *vma_pc; struct mm_struct *mm = task->mm; @@ -1224,15 +1390,17 @@ unwind_backtrace(struct quadd_callchain *cc, if (!vma_pc) break; - ti = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX]; + ti = &ri->mmap->fi.ex_sec[QUADD_SEC_TYPE_EXIDX]; + addr = get_ex_sec_address(ri, ti, QUADD_SEC_TYPE_EXIDX); - if (!is_vma_addr(ti->addr, vma_pc, sizeof(u32))) { + if (!is_vma_addr(addr, vma_pc, sizeof(u32))) { if (prev_ri) { put_extabs_ehabi(prev_ri); prev_ri = NULL; } - err = get_extabs_ehabi(vma_pc->vm_start, &ri_new); + err = get_extabs_ehabi(task_tgid_nr(task), + vma_pc->vm_start, &ri_new); if (err) { cc->urc_ut = QUADD_URC_TBL_NOT_EXIST; break; @@ -1241,7 +1409,7 @@ unwind_backtrace(struct quadd_callchain *cc, prev_ri = ri = &ri_new; } - err = unwind_frame(cc->um, ri, frame, vma_sp, thumbflag); + err = unwind_frame(cc->um, ri, frame, vma_sp, thumbflag, task); if (err < 0) { pr_debug("end unwind, urc: %ld\n", err); cc->urc_ut = -err; @@ -1336,7 +1504,7 @@ quadd_get_user_cc_arm32_ehabi(struct quadd_event_context *event_ctx, if (!vma_sp) return 0; - err = get_extabs_ehabi(vma->vm_start, &ri); + err = get_extabs_ehabi(task_tgid_nr(task), vma->vm_start, &ri); if (err) { cc->urc_ut = QUADD_URC_TBL_NOT_EXIST; return 0; @@ -1372,7 +1540,8 @@ quadd_is_ex_entry_exist_arm32_ehabi(struct quadd_event_context *event_ctx, if (!vma) return 0; - err = get_extabs_ehabi(vma->vm_start, &ri); + err = get_extabs_ehabi(task_tgid_nr(event_ctx->task), + vma->vm_start, &ri); if (err) return 0; @@ -1403,81 +1572,42 @@ out: int quadd_unwind_start(struct task_struct *task) { int err; - struct regions_data *rd, *rd_old; - - rd = rd_alloc(QUADD_EXTABS_SIZE); - if (IS_ERR_OR_NULL(rd)) { - pr_err("%s: error: rd_alloc\n", __func__); - return -ENOMEM; - } err = quadd_dwarf_unwind_start(); - if (err) { - rd_free(rd); + if (err < 0) return err; - } - - raw_spin_lock(&ctx.lock); - - rd_old = rcu_dereference(ctx.rd); - if (rd_old) - pr_warn("%s: warning: rd_old\n", __func__); - - rcu_assign_pointer(ctx.rd, rd); - - if (rd_old) - call_rcu(&rd_old->rcu, rd_free_rcu); - - ctx.pid = task->tgid; ctx.ex_tables_size = 0; - raw_spin_unlock(&ctx.lock); - return 0; } void quadd_unwind_stop(void) { - unsigned long i, nr_entries; - struct regions_data *rd; - struct quadd_mmap_area *mmap; + struct quadd_mmap_area *entry; - raw_spin_lock(&ctx.lock); + raw_spin_lock(&ctx.quadd_ctx->mmaps_lock); - ctx.pid = 0; + list_for_each_entry(entry, &ctx.quadd_ctx->mmap_areas, list) + quadd_unwind_clean_mmap(entry); - rd = rcu_dereference(ctx.rd); - if (!rd) - goto out; + raw_spin_unlock(&ctx.quadd_ctx->mmaps_lock); - nr_entries = rd->curr_nr; - - for (i = 0; i < nr_entries; i++) { - mmap = rd->entries[i].mmap; - mmap_wait_for_close(mmap); - clean_mmap(rd, mmap, 0); - } - - rcu_assign_pointer(ctx.rd, NULL); - call_rcu(&rd->rcu, rd_free_rcu); - -out: - raw_spin_unlock(&ctx.lock); quadd_dwarf_unwind_stop(); } -int quadd_unwind_init(void) +int quadd_unwind_init(struct quadd_ctx *quadd_ctx) { int err; + ctx.quadd_ctx = quadd_ctx; + err = quadd_dwarf_unwind_init(); if (err) return err; - raw_spin_lock_init(&ctx.lock); - rcu_assign_pointer(ctx.rd, NULL); - ctx.pid = 0; + INIT_LIST_HEAD(&ctx.mm_ex_list); + raw_spin_lock_init(&ctx.mm_ex_list_lock); return 0; } diff --git a/drivers/misc/tegra-profiler/eh_unwind.h b/drivers/misc/tegra-profiler/eh_unwind.h index dd0ba906c..33271535b 100644 --- a/drivers/misc/tegra-profiler/eh_unwind.h +++ b/drivers/misc/tegra-profiler/eh_unwind.h @@ -1,7 +1,7 @@ /* * drivers/misc/tegra-profiler/eh_unwind.h * - * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,16 +21,41 @@ struct quadd_callchain; struct quadd_ctx; -struct quadd_extables; struct task_struct; struct quadd_mmap_area; struct quadd_event_context; +struct extab_info { + unsigned long addr; + unsigned long length; + + unsigned long mmap_offset; + + unsigned long tf_start; + unsigned long tf_end; +}; + +struct file_ex_region_info { + struct extab_info ex_sec[QUADD_SEC_TYPE_MAX]; + u32 file_hash; + + unsigned int is_shared:1; +}; + +struct ex_region_info { + unsigned long vm_start; + unsigned long vm_end; + + struct quadd_mmap_area *mmap; + + u32 file_hash; +}; + unsigned int quadd_get_user_cc_arm32_ehabi(struct quadd_event_context *event_ctx, struct quadd_callchain *cc); -int quadd_unwind_init(void); +int quadd_unwind_init(struct quadd_ctx *quadd_ctx); void quadd_unwind_deinit(void); int quadd_unwind_start(struct task_struct *task); @@ -38,41 +63,26 @@ void quadd_unwind_stop(void); int quadd_unwind_set_extab(struct quadd_sections *extabs, struct quadd_mmap_area *mmap); -void quadd_unwind_delete_mmap(struct quadd_mmap_area *mmap); +void quadd_unwind_clean_mmap(struct quadd_mmap_area *mmap); int quadd_is_ex_entry_exist_arm32_ehabi(struct quadd_event_context *event_ctx, unsigned long addr); void -quadd_unwind_set_tail_info(unsigned long vm_start, +quadd_unwind_set_tail_info(struct ex_region_info *ri, int secid, unsigned long tf_start, - unsigned long tf_end); - - -struct extab_info { - unsigned long addr; - unsigned long length; - - unsigned long mmap_offset; - - unsigned long tf_start; - unsigned long tf_end; -}; - -struct ex_region_info { - unsigned long vm_start; - unsigned long vm_end; - - struct extab_info ex_sec[QUADD_SEC_TYPE_MAX]; - struct quadd_mmap_area *mmap; - - struct list_head list; -}; + unsigned long tf_end, + struct task_struct *task); long -quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri); +quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri, + struct task_struct *task); void quadd_put_dw_frames(struct ex_region_info *ri); +unsigned long +get_ex_sec_address(struct ex_region_info *ri, + struct extab_info *ti, int secid); + #endif /* __QUADD_EH_UNWIND_H__ */ diff --git a/drivers/misc/tegra-profiler/hrt.c b/drivers/misc/tegra-profiler/hrt.c index 37504a008..35c4f01bc 100644 --- a/drivers/misc/tegra-profiler/hrt.c +++ b/drivers/misc/tegra-profiler/hrt.c @@ -428,13 +428,6 @@ get_stack_offset(struct task_struct *task, return vma->vm_end - sp; } -static inline void -validate_um_for_task(struct task_struct *task, struct quadd_unw_methods *um) -{ - if (task_tgid_nr(task) != hrt.root_pid) - um->ut = um->dwarf = 0; -} - static void read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched) { @@ -498,7 +491,6 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched) if (ctx->param.backtrace) { cc->um = hrt.um; - validate_um_for_task(task, &cc->um); bt_size = quadd_get_user_callchain(&event_ctx, cc, ctx); if (bt_size > 0) { diff --git a/drivers/misc/tegra-profiler/main.c b/drivers/misc/tegra-profiler/main.c index bb7576b1d..39ede51d8 100644 --- a/drivers/misc/tegra-profiler/main.c +++ b/drivers/misc/tegra-profiler/main.c @@ -605,7 +605,7 @@ set_extab(struct quadd_sections *extabs, static void delete_mmap(struct quadd_mmap_area *mmap) { - quadd_unwind_delete_mmap(mmap); + quadd_unwind_clean_mmap(mmap); } static int @@ -731,7 +731,7 @@ int quadd_late_init(void) goto out_err_hrt; } - err = quadd_unwind_init(); + err = quadd_unwind_init(&ctx); if (err < 0) { pr_err("error: EH unwinding init failed\n"); goto out_err_power_clk; diff --git a/drivers/misc/tegra-profiler/mmap.c b/drivers/misc/tegra-profiler/mmap.c index 2c60456f1..b19934474 100644 --- a/drivers/misc/tegra-profiler/mmap.c +++ b/drivers/misc/tegra-profiler/mmap.c @@ -35,18 +35,18 @@ #include "mmap.h" #include "comm.h" #include "hrt.h" +#include "tegra.h" #define TMP_BUFFER_SIZE (PATH_MAX) #define QUADD_MMAP_TREE_MAX_LEVEL 32 static void put_mmap_sample(struct quadd_mmap_data *s, char *filename, - size_t length, unsigned long pgoff, - int is_file_exists, pid_t __tgid) + size_t length, unsigned long pgoff, pid_t __tgid) { - u64 mmap_ed = 0; + int vec_idx = 0; struct quadd_record_data r; - struct quadd_iovec vec[4]; + struct quadd_iovec vec[3]; u64 pgoff_val = (u64)pgoff << PAGE_SHIFT; u32 tgid = (u32)__tgid; @@ -57,26 +57,23 @@ put_mmap_sample(struct quadd_mmap_data *s, char *filename, r.mmap.time = quadd_get_time(); r.mmap.filename_length = length; - if (is_file_exists) - mmap_ed |= QUADD_MMAP_ED_IS_FILE_EXISTS; - - vec[0].base = &pgoff_val; - vec[0].len = sizeof(pgoff_val); + vec[vec_idx].base = &pgoff_val; + vec[vec_idx].len = sizeof(pgoff_val); + vec_idx++; - vec[1].base = &mmap_ed; - vec[1].len = sizeof(mmap_ed); + vec[vec_idx].base = filename; + vec[vec_idx].len = length; + vec_idx++; - vec[2].base = filename; - vec[2].len = length; - - vec[3].base = &tgid; - vec[3].len = sizeof(tgid); + vec[vec_idx].base = &tgid; + vec[vec_idx].len = sizeof(tgid); + vec_idx++; pr_debug("[%d] MMAP: tid: %u,pid: %u,'%s',%#llx-%#llx(%llx,%#llx)\n", - smp_processor_id(), s->pid, tgid, filename, + s->cpu_id, s->pid, tgid, filename, s->addr, s->addr + s->len, s->len, pgoff_val); - quadd_put_sample_this_cpu(&r, vec, ARRAY_SIZE(vec)); + quadd_put_sample_this_cpu(&r, vec, vec_idx); } static void @@ -84,6 +81,7 @@ process_mmap(struct vm_area_struct *vma, struct task_struct *task, char *buf, size_t buf_size) { pid_t tgid; + unsigned int cpu_flags; int is_file_exists; struct file *vm_file; char *file_name; @@ -136,13 +134,23 @@ process_mmap(struct vm_area_struct *vma, struct task_struct *task, sample.pid = task_pid_nr(task); tgid = task_tgid_nr(task); - sample.user_mode = 1; sample.addr = vma->vm_start; sample.len = vma->vm_end - vma->vm_start; + sample.flags = 0; + + sample.cpu_id = quadd_get_processor_id(NULL, &cpu_flags); + if (cpu_flags & QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP) + sample.flags |= QUADD_MMAP_FLAG_LP_MODE; + + if (is_file_exists) + sample.flags |= QUADD_MMAP_FLAG_IS_FILE_EXISTS; + + sample.flags |= QUADD_MMAP_FLAG_USER_MODE; + put_mmap_sample(&sample, file_name, length_aligned, - vma->vm_pgoff, is_file_exists, tgid); + vma->vm_pgoff, tgid); } void quadd_process_mmap(struct vm_area_struct *vma, struct task_struct *task) diff --git a/drivers/misc/tegra-profiler/quadd.h b/drivers/misc/tegra-profiler/quadd.h index 48e5e8821..ba166e085 100644 --- a/drivers/misc/tegra-profiler/quadd.h +++ b/drivers/misc/tegra-profiler/quadd.h @@ -17,6 +17,9 @@ #ifndef __QUADD_H #define __QUADD_H +#include +#include + #include /* #define QUADD_USE_EMULATE_COUNTERS 1 */ @@ -88,6 +91,9 @@ struct quadd_ctx { unsigned int mode_is_trace_all:1; unsigned int mode_is_sample_tree:1; unsigned int mode_is_trace_tree:1; + + struct list_head mmap_areas; + raw_spinlock_t mmaps_lock; }; static inline int quadd_mode_is_sampling(struct quadd_ctx *ctx) diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h index 8a44773c9..72f5f5de5 100644 --- a/drivers/misc/tegra-profiler/version.h +++ b/drivers/misc/tegra-profiler/version.h @@ -17,7 +17,7 @@ #ifndef __QUADD_VERSION_H #define __QUADD_VERSION_H -#define QUADD_MODULE_VERSION "1.129" +#define QUADD_MODULE_VERSION "1.130" #define QUADD_MODULE_BRANCH "Dev" #endif /* __QUADD_VERSION_H */ diff --git a/include/linux/tegra_profiler.h b/include/linux/tegra_profiler.h index 08f898abe..97495c60c 100644 --- a/include/linux/tegra_profiler.h +++ b/include/linux/tegra_profiler.h @@ -19,8 +19,8 @@ #include -#define QUADD_SAMPLES_VERSION 44 -#define QUADD_IO_VERSION 25 +#define QUADD_SAMPLES_VERSION 45 +#define QUADD_IO_VERSION 26 #define QUADD_IO_VERSION_DYNAMIC_RB 5 #define QUADD_IO_VERSION_RB_MAX_FILL_COUNT 6 @@ -43,6 +43,7 @@ #define QUADD_IO_VERSION_SAMPLING_MODE 23 #define QUADD_IO_VERSION_FORCE_ARCH_TIMER 24 #define QUADD_IO_VERSION_SAMPLE_ALL_TASKS 25 +#define QUADD_IO_VERSION_EXTABLES_PID 26 #define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG 17 #define QUADD_SAMPLE_VERSION_GROUP_SAMPLES 18 @@ -70,6 +71,7 @@ #define QUADD_SAMPLE_VERSION_SAMPLING_MODE 42 #define QUADD_SAMPLE_VERSION_SAMPLE_ALL_TASKS 43 #define QUADD_SAMPLE_VERSION_KTHREAD_TSK_FLAG 44 +#define QUADD_SAMPLE_VERSION_MMAP_CPUID 45 #define QUADD_MMAP_HEADER_VERSION 1 @@ -256,16 +258,20 @@ struct quadd_sample_data { u32 events_flags; }; -#define QUADD_MMAP_ED_IS_FILE_EXISTS (1 << 0) +#define QUADD_MMAP_FLAG_LP_MODE (1 << 0) +#define QUADD_MMAP_FLAG_USER_MODE (1 << 1) +#define QUADD_MMAP_FLAG_IS_FILE_EXISTS (1 << 2) struct quadd_mmap_data { u32 pid; u64 time; + u8 cpu_id; + u16 flags; + u64 addr; u64 len; - u8 user_mode:1; u16 filename_length; }; @@ -301,10 +307,10 @@ struct quadd_additional_sample { u16 extra_length; }; -#define QUADD_SCHED_FLAG_LP_MODE (1 << 0) -#define QUADD_SCHED_FLAG_SCHED_IN (1 << 1) -#define QUADD_SCHED_FLAG_IS_VPID (1 << 2) -#define QUADD_SCHED_FLAG_PF_KTHREAD (1 << 3) +#define QUADD_SCHED_FLAG_LP_MODE (1ULL << 0) +#define QUADD_SCHED_FLAG_SCHED_IN (1ULL << 1) +#define QUADD_SCHED_FLAG_IS_VPID (1ULL << 2) +#define QUADD_SCHED_FLAG_PF_KTHREAD (1ULL << 3) struct quadd_sched_data { u32 pid; @@ -349,24 +355,24 @@ struct quadd_debug_data { #define QUADD_HEADER_MAGIC 0x1122 -#define QUADD_HDR_FLAG_BACKTRACE (1 << 0) -#define QUADD_HDR_FLAG_USE_FREQ (1 << 1) -#define QUADD_HDR_FLAG_POWER_RATE (1 << 2) -#define QUADD_HDR_FLAG_DEBUG_SAMPLES (1 << 3) -#define QUADD_HDR_FLAG_GET_MMAP (1 << 4) -#define QUADD_HDR_FLAG_BT_FP (1 << 5) -#define QUADD_HDR_FLAG_BT_UT (1 << 6) -#define QUADD_HDR_FLAG_BT_UT_CE (1 << 7) -#define QUADD_HDR_FLAG_BT_DWARF (1 << 8) -#define QUADD_HDR_FLAG_USE_ARCH_TIMER (1 << 9) -#define QUADD_HDR_FLAG_STACK_OFFSET (1 << 10) -#define QUADD_HDR_FLAG_HAS_CPUID (1 << 11) -#define QUADD_HDR_FLAG_MODE_SAMPLING (1 << 12) -#define QUADD_HDR_FLAG_MODE_TRACING (1 << 13) -#define QUADD_HDR_FLAG_MODE_SAMPLE_ALL (1 << 14) -#define QUADD_HDR_FLAG_MODE_TRACE_ALL (1 << 15) -#define QUADD_HDR_FLAG_MODE_SAMPLE_TREE (1 << 16) -#define QUADD_HDR_FLAG_MODE_TRACE_TREE (1 << 17) +#define QUADD_HDR_FLAG_BACKTRACE (1ULL << 0) +#define QUADD_HDR_FLAG_USE_FREQ (1ULL << 1) +#define QUADD_HDR_FLAG_POWER_RATE (1ULL << 2) +#define QUADD_HDR_FLAG_DEBUG_SAMPLES (1ULL << 3) +#define QUADD_HDR_FLAG_GET_MMAP (1ULL << 4) +#define QUADD_HDR_FLAG_BT_FP (1ULL << 5) +#define QUADD_HDR_FLAG_BT_UT (1ULL << 6) +#define QUADD_HDR_FLAG_BT_UT_CE (1ULL << 7) +#define QUADD_HDR_FLAG_BT_DWARF (1ULL << 8) +#define QUADD_HDR_FLAG_USE_ARCH_TIMER (1ULL << 9) +#define QUADD_HDR_FLAG_STACK_OFFSET (1ULL << 10) +#define QUADD_HDR_FLAG_HAS_CPUID (1ULL << 11) +#define QUADD_HDR_FLAG_MODE_SAMPLING (1ULL << 12) +#define QUADD_HDR_FLAG_MODE_TRACING (1ULL << 13) +#define QUADD_HDR_FLAG_MODE_SAMPLE_ALL (1ULL << 14) +#define QUADD_HDR_FLAG_MODE_TRACE_ALL (1ULL << 15) +#define QUADD_HDR_FLAG_MODE_SAMPLE_TREE (1ULL << 16) +#define QUADD_HDR_FLAG_MODE_TRACE_TREE (1ULL << 17) struct quadd_header_data { u16 magic; @@ -578,6 +584,8 @@ struct quadd_sec_info { u64 mmap_offset; }; +#define QUADD_SECTIONS_FLAG_IS_SHARED (1ULL << 0) + struct quadd_sections { u64 vm_start; u64 vm_end; @@ -585,8 +593,10 @@ struct quadd_sections { struct quadd_sec_info sec[QUADD_SEC_TYPE_MAX]; u64 user_mmap_start; + u32 file_hash; - u64 reserved[4]; /* reserved fields for future extensions */ + u32 pid; + u64 flags; }; struct quadd_mmap_rb_info { -- cgit v1.2.2