[PATCH] ARM: Fix uvtop conversion on LPAE
by HAGIO KAZUHITO(萩尾 一仁)
Currently arm_uvtop() calls arm_lpae_vtop() with the LPAE and it uses
LPAE_VTOP() also for a user virtual address, but it looks incorrect.
Without this patch, commands that use uvtop conversion such as "ps -a",
"gcore" fail as readmem() for a uvaddr returns a seek error:
crash> ps -a 357
...
ps: cannot access user stack address: bef2f97c
crash> gcore
gcore: seek error: physical address: 7ec56eab type: "fill_psinfo: pr_psargs"
Failed.
Fixes: https://github.com/crash-utility/crash-extensions/issues/2
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
arm.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/arm.c b/arm.c
index e52d29f04015..05324691da17 100644
--- a/arm.c
+++ b/arm.c
@@ -1125,17 +1125,18 @@ arm_lpae_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr, int verbose)
pmd_t pmd_pte;
pte_t pte;
- if (!vt->vmalloc_start) {
- *paddr = LPAE_VTOP(vaddr);
- return TRUE;
- }
-
- if (!IS_VMALLOC_ADDR(vaddr)) {
- *paddr = LPAE_VTOP(vaddr);
- if (!verbose)
+ if (IS_KVADDR(vaddr)) {
+ if (!vt->vmalloc_start) {
+ *paddr = LPAE_VTOP(vaddr);
return TRUE;
- }
+ }
+ if (!IS_VMALLOC_ADDR(vaddr)) {
+ *paddr = LPAE_VTOP(vaddr);
+ if (!verbose)
+ return TRUE;
+ }
+ }
if (verbose)
fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
--
1.8.3.1
3 years, 8 months
[PATCH] extensions: remove trace.c and point to the new repository
by HAGIO KAZUHITO(萩尾 一仁)
The trace.c extension module moved to the separate repository:
https://github.com/fujitsu/crash-trace
Remove the trace.c file from the crash repository and instead add
trace.c.README file to point to the new repository for a while.
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
Lianbo,
I can see that the spec file of RHEL's crash-trace-command points to
the tarball in the crash-extensions repository, we can remove trace.c
in the crash repository?
extensions/trace.c | 2592 -------------------------------------
extensions/trace.c.README | 7 +
2 files changed, 7 insertions(+), 2592 deletions(-)
delete mode 100644 extensions/trace.c
create mode 100644 extensions/trace.c.README
diff --git a/extensions/trace.c b/extensions/trace.c
deleted file mode 100644
index c33907f98b00..000000000000
--- a/extensions/trace.c
+++ /dev/null
@@ -1,2592 +0,0 @@
-/*
- * trace extension module for crash
- *
- * Copyright (C) 2009, 2010 FUJITSU LIMITED
- * Author: Lai Jiangshan <laijs(a)cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- */
-
-#define _GNU_SOURCE
-#include "defs.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <setjmp.h>
-#include <stdlib.h>
-
-static int verbose = 0;
-
-static int nr_cpu_ids;
-
-/*
- * lockless ring_buffer and old non-lockless ring_buffer are both supported.
- */
-static int lockless_ring_buffer;
-static int per_cpu_buffer_sizes;
-/*
- * global and encapsulated current_trace are both supported
- */
-static int encapsulated_current_trace;
-/*
- * array_buffer (trace_buffer pre v5.6) is supported
- */
-static int array_buffer_available;
-/*
- * max_buffer is supported
- */
-static int max_buffer_available;
-/*
- * multiple trace instances are supported
- */
-static int multiple_instances_available;
-
-/*
- * buffer_page has "real_end"
- */
-static int buffer_page_real_end_available;
-
-#define koffset(struct, member) struct##_##member##_offset
-
-static int koffset(trace_array, current_trace);
-static int koffset(trace_array, array_buffer);
-static int koffset(trace_array, max_buffer);
-static int koffset(array_buffer, buffer);
-static int koffset(trace_array, buffer);
-static int koffset(tracer, name);
-
-static int koffset(trace_buffer, pages);
-static int koffset(trace_buffer, flags);
-static int koffset(trace_buffer, cpus);
-static int koffset(trace_buffer, buffers);
-
-static int koffset(ring_buffer_per_cpu, cpu);
-static int koffset(ring_buffer_per_cpu, pages);
-static int koffset(ring_buffer_per_cpu, nr_pages);
-static int koffset(ring_buffer_per_cpu, head_page);
-static int koffset(ring_buffer_per_cpu, tail_page);
-static int koffset(ring_buffer_per_cpu, commit_page);
-static int koffset(ring_buffer_per_cpu, reader_page);
-static int koffset(ring_buffer_per_cpu, overrun);
-static int koffset(ring_buffer_per_cpu, entries);
-
-static int koffset(buffer_page, read);
-static int koffset(buffer_page, list);
-static int koffset(buffer_page, page);
-static int koffset(buffer_page, real_end);
-
-static int koffset(list_head, next);
-
-static int koffset(ftrace_event_call, list);
-
-static int koffset(ftrace_event_field, link);
-static int koffset(ftrace_event_field, name);
-static int koffset(ftrace_event_field, type);
-static int koffset(ftrace_event_field, offset);
-static int koffset(ftrace_event_field, size);
-static int koffset(ftrace_event_field, is_signed);
-
-static int koffset(trace_array, name);
-
-static int koffset(POINTER_SYM, POINTER) = 0;
-
-struct ring_buffer_per_cpu {
- ulong kaddr;
-
- ulong head_page;
- ulong tail_page;
- ulong commit_page;
- ulong reader_page;
- ulong real_head_page;
-
- int head_page_index;
- unsigned long nr_pages;
- ulong *pages;
-
- ulong *linear_pages;
- int nr_linear_pages;
-
- ulong overrun;
- ulong entries;
-};
-
-static ulong global_trace;
-static ulong max_tr_trace;
-
-struct trace_instance {
- char name[NAME_MAX + 1];
- ulong array_buffer;
- ulong max_buffer;
- ulong trace_buffer;
- unsigned pages;
- struct ring_buffer_per_cpu *buffers;
-
- ulong max_tr_ring_buffer;
- unsigned max_tr_pages;
- struct ring_buffer_per_cpu *max_tr_buffers;
-};
-
-static ulong ftrace_trace_arrays;
-static struct trace_instance global_trace_instance;
-static struct trace_instance *trace_instances = NULL;
-static int instance_count;
-
-static ulong ftrace_events;
-static ulong current_trace;
-static const char *current_tracer_name;
-
-static void ftrace_destroy_event_types(void);
-static int ftrace_init_event_types(void);
-
-/* at = ((struct *)ptr)->member */
-#define read_value(at, ptr, struct, member) \
- do { \
- if (!readmem(ptr + koffset(struct, member), KVADDR, \
- &at, sizeof(at), #struct "'s " #member, \
- RETURN_ON_ERROR)) \
- goto out_fail;\
- } while (0)
-
-/* Remove the "const" qualifiers for ptr */
-#define free(ptr) free((void *)(ptr))
-
-static int write_and_check(int fd, void *data, size_t size)
-{
- size_t tot = 0;
- size_t w;
-
- do {
- w = write(fd, data, size - tot);
- tot += w;
-
- if (w <= 0)
- return -1;
- } while (tot != size);
-
- return 0;
-}
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-static int init_offsets(void)
-{
-#define check_offset(struct, member) do { \
- if (koffset(struct, member) < 0) { \
- fprintf(fp, "failed to init the offset, struct:"\
- #struct ", member:" #member); \
- fprintf(fp, "\n"); \
- return -1; \
- } \
- } while (0)
-
-#define init_offset(struct, member) do { \
- koffset(struct, member) = MEMBER_OFFSET(#struct, #member); \
- check_offset(struct, member); \
- } while (0)
-
-#define init_offset_alternative(struct, member, alt_struct, alt_member) do { \
- koffset(struct, member) = MEMBER_OFFSET(#alt_struct, #alt_member); \
- check_offset(struct, member); \
- } while (0)
-
- if (encapsulated_current_trace)
- init_offset(trace_array, current_trace);
-
- if (array_buffer_available) {
- if (MEMBER_EXISTS("trace_array", "array_buffer")) {
- init_offset(trace_array, array_buffer);
- init_offset(array_buffer, buffer);
- } else {
- init_offset_alternative(trace_array, array_buffer,
- trace_array, trace_buffer);
- init_offset_alternative(array_buffer, buffer,
- trace_buffer, buffer);
- }
-
- if (max_buffer_available)
- init_offset(trace_array, max_buffer);
- } else {
- init_offset(trace_array, buffer);
- }
- init_offset(tracer, name);
-
- if (MEMBER_EXISTS("ring_buffer_per_cpu", "nr_pages")) {
- per_cpu_buffer_sizes = 1;
- if (verbose)
- fprintf(fp, "per cpu buffer sizes\n");
- }
-
- if (machine_type("PPC64") && kernel_symbol_exists(".ring_buffer_read"))
- gdb_set_crash_scope(symbol_value(".ring_buffer_read"), ".ring_buffer_read");
- else if (kernel_symbol_exists("ring_buffer_read"))
- gdb_set_crash_scope(symbol_value("ring_buffer_read"), "ring_buffer_read");
-
- if (STREQ(MEMBER_TYPE_NAME("trace_buffer", "buffer"), "ring_buffer")) {
- if (!per_cpu_buffer_sizes)
- init_offset_alternative(trace_buffer, pages, ring_buffer, pages);
- init_offset_alternative(trace_buffer, flags, ring_buffer, flags);
- init_offset_alternative(trace_buffer, cpus, ring_buffer, cpus);
- init_offset_alternative(trace_buffer, buffers, ring_buffer, buffers);
- } else {
- if (!per_cpu_buffer_sizes)
- init_offset(trace_buffer, pages);
- init_offset(trace_buffer, flags);
- init_offset(trace_buffer, cpus);
- init_offset(trace_buffer, buffers);
- }
-
- if (MEMBER_SIZE("ring_buffer_per_cpu", "pages") == sizeof(ulong)) {
- lockless_ring_buffer = 1;
- if (verbose)
- fprintf(fp, "lockless\n");
- }
-
- if (per_cpu_buffer_sizes)
- init_offset(ring_buffer_per_cpu, nr_pages);
- init_offset(ring_buffer_per_cpu, cpu);
- init_offset(ring_buffer_per_cpu, pages);
- init_offset(ring_buffer_per_cpu, head_page);
- init_offset(ring_buffer_per_cpu, tail_page);
- init_offset(ring_buffer_per_cpu, commit_page);
- init_offset(ring_buffer_per_cpu, reader_page);
- init_offset(ring_buffer_per_cpu, overrun);
- init_offset(ring_buffer_per_cpu, entries);
-
- init_offset(buffer_page, read);
- init_offset(buffer_page, list);
- init_offset(buffer_page, page);
- init_offset(buffer_page, real_end);
-
- init_offset(list_head, next);
-
- koffset(ftrace_event_call, list) = MAX(MEMBER_OFFSET("ftrace_event_call", "list"),
- MEMBER_OFFSET("trace_event_call", "list"));
- if (koffset(ftrace_event_call, list) < 0) {
- fprintf(fp, "failed to init the offset, struct:[f]trace_event_call member:list)\n");
- return -1; \
- }
-
- init_offset(ftrace_event_field, link);
- init_offset(ftrace_event_field, name);
- init_offset(ftrace_event_field, type);
- init_offset(ftrace_event_field, offset);
- init_offset(ftrace_event_field, size);
- init_offset(ftrace_event_field, is_signed);
-
- if (MEMBER_EXISTS("trace_array", "name"))
- init_offset(trace_array, name);
-
- return 0;
-#undef init_offset
-}
-
-static void print_offsets(void)
-{
- if (!verbose)
- return;
-
-#define print_offset(struct, member) fprintf(fp, \
- "koffset(" #struct ", " #member ") = %d\n", koffset(struct, member))
-
- print_offset(trace_array, buffer);
- print_offset(tracer, name);
-
- print_offset(trace_buffer, pages);
- print_offset(trace_buffer, flags);
- print_offset(trace_buffer, cpus);
- print_offset(trace_buffer, buffers);
-
- print_offset(ring_buffer_per_cpu, cpu);
- print_offset(ring_buffer_per_cpu, pages);
- print_offset(ring_buffer_per_cpu, head_page);
- print_offset(ring_buffer_per_cpu, tail_page);
- print_offset(ring_buffer_per_cpu, commit_page);
- print_offset(ring_buffer_per_cpu, reader_page);
- print_offset(ring_buffer_per_cpu, overrun);
- print_offset(ring_buffer_per_cpu, entries);
-
- print_offset(buffer_page, read);
- print_offset(buffer_page, list);
- print_offset(buffer_page, page);
- print_offset(buffer_page, real_end);
-
- print_offset(list_head, next);
-
- print_offset(ftrace_event_call, list);
-
- print_offset(ftrace_event_field, link);
- print_offset(ftrace_event_field, name);
- print_offset(ftrace_event_field, type);
- print_offset(ftrace_event_field, offset);
- print_offset(ftrace_event_field, size);
- print_offset(ftrace_event_field, is_signed);
-#undef print_offset
-}
-
-static int buffer_page_has_data(ulong page)
-{
- uint end;
-
- if (!buffer_page_real_end_available)
- return 1;
-
- /* Only write pages with data in it */
- read_value(end, page, buffer_page, real_end);
- return end;
-out_fail:
- return 0;
-}
-
-static int ftrace_init_pages(struct ring_buffer_per_cpu *cpu_buffer,
- unsigned nr_pages)
-{
- unsigned j = 0, count = 0;
- ulong head, page;
- ulong real_head_page = cpu_buffer->head_page;
-
- cpu_buffer->pages = calloc(sizeof(ulong), nr_pages);
- if (cpu_buffer->pages == NULL)
- return -1;
-
- cpu_buffer->linear_pages = calloc(sizeof(ulong), nr_pages + 1);
- if (cpu_buffer->linear_pages == NULL) {
- return -1;
- }
-
- if (lockless_ring_buffer) {
- read_value(head, cpu_buffer->kaddr, ring_buffer_per_cpu, pages);
- cpu_buffer->pages[j++] = head - koffset(buffer_page, list);
- } else
- head = cpu_buffer->kaddr + koffset(ring_buffer_per_cpu, pages);
-
- page = head;
- for (;;) {
- read_value(page, page, list_head, next);
- if (page & 3) {
- /* lockless_ring_buffer */
- page &= ~3;
- real_head_page = page - koffset(buffer_page, list);
- }
-
- if (j == nr_pages)
- break;
-
- if (page == head) {
- error(INFO, "Num of pages is less than %d\n", nr_pages);
- goto out_fail;
- }
-
- cpu_buffer->pages[j++] = page - koffset(buffer_page, list);
- }
-
- if (page != head) {
- error(INFO, "Num of pages is larger than %d\n", nr_pages);
- goto out_fail;
- }
-
- /* find head page and head_page_index */
-
- cpu_buffer->real_head_page = real_head_page;
- cpu_buffer->head_page_index = -1;
-
- for (j = 0; j < nr_pages; j++) {
- if (cpu_buffer->pages[j] == real_head_page) {
- cpu_buffer->head_page_index = j;
- break;
- }
- }
-
- if (cpu_buffer->head_page_index == -1) {
- error(INFO, "error for resolve head_page_index\n");
- goto out_fail;
- }
-
- /* Setup linear pages */
-
- if (buffer_page_has_data(cpu_buffer->reader_page))
- cpu_buffer->linear_pages[count++] = cpu_buffer->reader_page;
-
- if (cpu_buffer->reader_page == cpu_buffer->commit_page)
- goto done;
-
- j = cpu_buffer->head_page_index;
- for (;;) {
- cpu_buffer->linear_pages[count++] = cpu_buffer->pages[j];
-
- if (cpu_buffer->pages[j] == cpu_buffer->commit_page)
- break;
-
- j++;
- if (j == nr_pages)
- j = 0;
-
- if (j == cpu_buffer->head_page_index) {
- /* cpu_buffer->commit_page may be corrupted */
- break;
- }
- }
-
-done:
- cpu_buffer->nr_linear_pages = count;
-
- return 0;
-
-out_fail:
- return -1;
-}
-
-static void ftrace_destroy_buffers(struct ring_buffer_per_cpu *buffers)
-{
- int i;
-
- for (i = 0; i < nr_cpu_ids; i++) {
- if (!buffers[i].kaddr)
- continue;
-
- free(buffers[i].pages);
- free(buffers[i].linear_pages);
- }
-}
-
-static int ftrace_init_buffers(struct ring_buffer_per_cpu *buffers,
- ulong trace_buffer, unsigned pages)
-{
- int i;
- ulong buffers_array;
-
- read_value(buffers_array, trace_buffer, trace_buffer, buffers);
-
- for (i = 0; i < nr_cpu_ids; i++) {
- if (!readmem(buffers_array + sizeof(ulong) * i, KVADDR,
- &buffers[i].kaddr, sizeof(ulong),
- "ring_buffer's cpu buffer", RETURN_ON_ERROR))
- goto out_fail;
-
- if (!buffers[i].kaddr)
- continue;
-
-#define buffer_read_value(member) read_value(buffers[i].member, \
- buffers[i].kaddr, ring_buffer_per_cpu, member)
-
- buffer_read_value(head_page);
- buffer_read_value(tail_page);
- buffer_read_value(commit_page);
- buffer_read_value(reader_page);
- buffer_read_value(overrun);
- buffer_read_value(entries);
- if (per_cpu_buffer_sizes) {
- if (MEMBER_SIZE("ring_buffer_per_cpu", "nr_pages") == sizeof(unsigned int)) {
- unsigned int tmp_nr_pages;
- read_value(tmp_nr_pages, buffers[i].kaddr, ring_buffer_per_cpu, nr_pages);
- buffers[i].nr_pages = (unsigned long) tmp_nr_pages;
- } else {
- buffer_read_value(nr_pages);
- }
- pages = buffers[i].nr_pages;
- } else
- buffers[i].nr_pages = pages;
-
-#undef buffer_read_value
-
- if (ftrace_init_pages(buffers + i, pages) < 0)
- goto out_fail;
-
- if (verbose) {
- fprintf(fp, "overrun=%lu\n", buffers[i].overrun);
- fprintf(fp, "entries=%lu\n", buffers[i].entries);
- }
- }
-
- return 0;
-
-out_fail:
- ftrace_destroy_buffers(buffers);
- return -1;
-}
-
-static int ftrace_init_trace(struct trace_instance *ti, ulong instance_addr)
-{
- if (array_buffer_available) {
- ti->array_buffer = instance_addr +
- koffset(trace_array, array_buffer);
- read_value(ti->trace_buffer, ti->array_buffer,
- array_buffer, buffer);
-
- if (max_buffer_available) {
- ti->max_buffer = instance_addr +
- koffset(trace_array, max_buffer);
- read_value(ti->max_tr_ring_buffer, ti->max_buffer,
- array_buffer, buffer);
- }
- } else {
- read_value(ti->trace_buffer, instance_addr, trace_array, buffer);
- read_value(ti->pages, ti->trace_buffer, trace_buffer, pages);
-
- read_value(ti->max_tr_ring_buffer, max_tr_trace, trace_array, buffer);
- if (ti->max_tr_ring_buffer)
- read_value(ti->max_tr_pages, ti->max_tr_ring_buffer, trace_buffer, pages);
- }
-
- ti->buffers = calloc(sizeof(*ti->buffers), nr_cpu_ids);
- if (ti->buffers == NULL)
- goto out_fail;
-
- if (ftrace_init_buffers(ti->buffers, ti->trace_buffer,
- ti->pages) < 0)
- goto out_fail;
-
- if (!ti->max_tr_ring_buffer)
- return 0;
-
- ti->max_tr_buffers = calloc(sizeof(*ti->max_tr_buffers), nr_cpu_ids);
- if (ti->max_tr_buffers == NULL)
- goto out_fail;
-
- if (ftrace_init_buffers(ti->max_tr_buffers, ti->max_tr_ring_buffer,
- ti->max_tr_pages) < 0)
- goto out_fail;
-
- return 0;
-
-out_fail:
- free(ti->max_tr_buffers);
- free(ti->buffers);
- return -1;
-}
-
-static void ftrace_destroy_all_instance_buffers()
-{
- int i;
-
- for (i = 0; i < instance_count; i++)
- {
- struct trace_instance *ti = &trace_instances[i];
-
- if (ti->max_tr_ring_buffer) {
- ftrace_destroy_buffers(ti->max_tr_buffers);
- free(ti->max_tr_buffers);
- }
-
- ftrace_destroy_buffers(ti->buffers);
- free(ti->buffers);
- }
-}
-
-static void ftrace_destroy_instances()
-{
- ftrace_destroy_all_instance_buffers();
- free(trace_instances);
-}
-
-static int ftrace_init_instances()
-{
- int i;
- struct trace_instance *ti;
- struct list_data list_data;
- struct list_data *ld = &list_data;
-
- if (!multiple_instances_available)
- return 0;
-
- BZERO(ld, sizeof(struct list_data));
- ld->start = ftrace_trace_arrays;
- ld->end = global_trace;
- ld->flags = LIST_ALLOCATE;
- instance_count = do_list(ld);
-
- /* The do_list count includes the list_head, which is not a
- * proper instance */
- instance_count--;
- if (instance_count <= 0)
- return 0;
-
- trace_instances = calloc(sizeof(struct trace_instance), instance_count);
-
- /* We start i at 1 to skip over the list_head and continue to the last
- * instance, which lies at index instance_count */
- for (i = 1; i <= instance_count; i++)
- {
- ulong instance_ptr;
- ulong name_addr;
- int ret;
-
- ti = &trace_instances[i-1];
- instance_ptr = ld->list_ptr[i];
- read_value(name_addr, instance_ptr, trace_array, name);
- if (!name_addr)
- {
- console("Instance name is NULL\n");
- }
- else if (!read_string(name_addr, ti->name, sizeof(ti->name)))
- {
- console("Failed to read instance name at address %p\n", (void*)name_addr);
- goto out_fail;
- }
-
- ret = ftrace_init_trace(ti, instance_ptr);
- if (ret < 0)
- goto out_fail;
- }
- FREEBUF(ld->list_ptr);
-
- return 0;
-
-out_fail:
- /* We've already freed the current instance's trace buffer info, so
- * we'll clear that out to avoid double freeing in
- * ftrace_destroy_instances() */
- BZERO(ti, sizeof(struct trace_instance));
- ftrace_destroy_instances();
-
- return -1;
-}
-
-static int ftrace_init_current_tracer(void)
-{
- ulong addr;
- char tmp[128];
-
- /* Get current tracer name */
- if (encapsulated_current_trace) {
- read_value(addr, global_trace, trace_array, current_trace);
- } else {
- read_value(addr, current_trace, POINTER_SYM, POINTER);
- }
-
- read_value(addr, addr, tracer, name);
- read_string(addr, tmp, 128);
-
- current_tracer_name = strdup(tmp);
- if (current_tracer_name == NULL)
- goto out_fail;
-
- return 0;
-
-out_fail:
- return -1;
-}
-
-static int ftrace_init(void)
-{
- struct syment *sym_global_trace;
- struct syment *sym_max_tr_trace;
- struct syment *sym_ftrace_events;
- struct syment *sym_current_trace;
- struct syment *sym_ftrace_trace_arrays;
-
- sym_global_trace = symbol_search("global_trace");
- sym_ftrace_events = symbol_search("ftrace_events");
- sym_ftrace_trace_arrays = symbol_search("ftrace_trace_arrays");
-
- if (sym_global_trace == NULL || sym_ftrace_events == NULL)
- return -1;
-
- global_trace = sym_global_trace->value;
- ftrace_events = sym_ftrace_events->value;
-
- if (sym_ftrace_trace_arrays)
- {
- multiple_instances_available = 1;
- ftrace_trace_arrays = sym_ftrace_trace_arrays->value;
- }
-
- if (MEMBER_EXISTS("buffer_page", "real_end"))
- buffer_page_real_end_available = 1;
-
- if (MEMBER_EXISTS("trace_array", "current_trace")) {
- encapsulated_current_trace = 1;
- } else {
- sym_current_trace = symbol_search("current_trace");
- if (sym_current_trace == NULL)
- return -1;
-
- current_trace = sym_current_trace->value;
- }
-
- if (MEMBER_EXISTS("trace_array", "array_buffer") ||
- MEMBER_EXISTS("trace_array", "trace_buffer")) {
- array_buffer_available = 1;
-
- if (MEMBER_EXISTS("trace_array", "max_buffer"))
- max_buffer_available = 1;
- } else {
- sym_max_tr_trace = symbol_search("max_tr");
- if (sym_max_tr_trace == NULL)
- return -1;
-
- max_tr_trace = sym_max_tr_trace->value;
- }
-
- if (!try_get_symbol_data("nr_cpu_ids", sizeof(int), &nr_cpu_ids))
- nr_cpu_ids = 1;
-
- if (init_offsets() < 0)
- return -1;
- print_offsets();
-
- if (ftrace_init_trace(&global_trace_instance, global_trace) < 0)
- goto out_0;
-
- if (ftrace_init_instances() < 0)
- goto out_1;
-
- if (ftrace_init_event_types() < 0)
- goto out_2;
-
- if (ftrace_init_current_tracer() < 0)
- goto out_3;
-
- return 0;
-
-out_3:
- ftrace_destroy_event_types();
-out_2:
- ftrace_destroy_instances();
-out_1:
- if (global_trace_instance.max_tr_ring_buffer) {
- ftrace_destroy_buffers(global_trace_instance.max_tr_buffers);
- free(global_trace_instance.max_tr_buffers);
- }
- ftrace_destroy_buffers(global_trace_instance.buffers);
- free(global_trace_instance.buffers);
-out_0:
- return -1;
-}
-
-static void ftrace_destroy(void)
-{
- free(current_tracer_name);
- ftrace_destroy_event_types();
-
- ftrace_destroy_instances();
-
- if (global_trace_instance.max_tr_ring_buffer) {
- ftrace_destroy_buffers(global_trace_instance.max_tr_buffers);
- free(global_trace_instance.max_tr_buffers);
- }
-
- ftrace_destroy_buffers(global_trace_instance.buffers);
- free(global_trace_instance.buffers);
-}
-
-static int ftrace_dump_page(int fd, ulong page, void *page_tmp)
-{
- ulong raw_page;
-
- read_value(raw_page, page, buffer_page, page);
-
- if (!readmem(raw_page, KVADDR, page_tmp, PAGESIZE(), "get page context",
- RETURN_ON_ERROR))
- goto out_fail;
-
- if (write_and_check(fd, page_tmp, PAGESIZE()))
- return -1;
-
- return 0;
-
-out_fail:
- return -1;
-}
-
-static
-void ftrace_dump_buffer(int fd, struct ring_buffer_per_cpu *cpu_buffer,
- unsigned pages, void *page_tmp)
-{
- int i;
-
- for (i = 0; i < cpu_buffer->nr_linear_pages; i++) {
- if (ftrace_dump_page(fd, cpu_buffer->linear_pages[i],
- page_tmp) < 0)
- break;
- }
-}
-
-static int try_mkdir(const char *pathname, mode_t mode)
-{
- int ret;
-
- ret = mkdir(pathname, mode);
- if (ret < 0) {
- if (errno == EEXIST)
- return 0;
-
- error(INFO, "mkdir failed\n");
- return -1;
- }
-
- return 0;
-}
-
-static int ftrace_dump_buffers(const char *per_cpu_path,
- struct trace_instance *ti)
-{
- int i;
- void *page_tmp;
- char path[PATH_MAX];
- int fd;
-
- page_tmp = malloc(PAGESIZE());
- if (page_tmp == NULL)
- return -1;
-
- for (i = 0; i < nr_cpu_ids; i++) {
- struct ring_buffer_per_cpu *cpu_buffer = &ti->buffers[i];
-
- if (!cpu_buffer->kaddr)
- continue;
-
- snprintf(path, sizeof(path), "%s/cpu%d", per_cpu_path, i);
- if (try_mkdir(path, 0755) < 0)
- goto out_fail;
-
- snprintf(path, sizeof(path), "%s/cpu%d/trace_pipe_raw",
- per_cpu_path, i);
- fd = open(path, O_WRONLY | O_CREAT, 0644);
- if (fd < 0)
- goto out_fail;
-
- ftrace_dump_buffer(fd, cpu_buffer, ti->pages, page_tmp);
- close(fd);
- }
-
- free(page_tmp);
- return 0;
-
-out_fail:
- free(page_tmp);
- return -1;
-}
-
-#define MAX_CACHE_ID 256
-
-struct ftrace_field {
- const char *name;
- const char *type;
- int offset;
- int size;
- int is_signed;
-};
-
-struct event_type {
- struct event_type *next;
- const char *system;
- const char *name;
- int plugin;
- const char *print_fmt;
- int id;
- int nfields;
- struct ftrace_field *fields;
-};
-
-static struct event_type *event_type_cache[MAX_CACHE_ID];
-static struct event_type **event_types;
-static int nr_event_types;
-
-static struct ftrace_field *ftrace_common_fields;
-static int ftrace_common_fields_count;
-
-static int syscall_get_enter_fields(ulong call, ulong *fields)
-{
- static int inited;
- static int data_offset;
- static int enter_fields_offset;
-
- ulong metadata;
-
- if (inited)
- goto work;
-
- inited = 1;
- data_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "data"),
- MEMBER_OFFSET("trace_event_call", "data"));
- if (data_offset < 0) {
- /*
- * rhel-7.6 moved the .data member into an anonymous union.
- */
- if (MEMBER_EXISTS("ftrace_event_call", "rh_data") &&
- MEMBER_EXISTS("ftrace_event_data", "data")) {
- data_offset = MEMBER_OFFSET("ftrace_event_call", "rh_data") +
- MEMBER_OFFSET("ftrace_event_data", "data");
- inited = 2;
- } else
- return -1;
- }
-
- enter_fields_offset = MEMBER_OFFSET("syscall_metadata", "enter_fields");
- if (enter_fields_offset < 0)
- return -1;
-
-work:
- if (data_offset < 0 || enter_fields_offset < 0)
- return -1;
-
- if (!readmem(call + data_offset, KVADDR, &metadata, sizeof(metadata),
- "read ftrace_event_call data", RETURN_ON_ERROR))
- return -1;
-
- if (inited == 2) {
- if (!readmem(metadata, KVADDR, &metadata, sizeof(metadata),
- "read ftrace_event_call data (indirect rh_data)", RETURN_ON_ERROR))
- return -1;
- }
-
- *fields = metadata + enter_fields_offset;
- return 0;
-}
-
-static int syscall_get_exit_fields_old(ulong call, ulong *fields)
-{
- static int inited;
- static int data_offset;
- static int exit_fields_offset;
-
- ulong metadata;
-
- if (inited)
- goto work;
-
- inited = 1;
- data_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "data"),
- MEMBER_OFFSET("trace_event_call", "data"));
- if (data_offset < 0)
- return -1;
-
- exit_fields_offset = MEMBER_OFFSET("syscall_metadata", "exit_fields");
- if (exit_fields_offset < 0)
- return -1;
-
-work:
- if (data_offset < 0 || exit_fields_offset < 0)
- return -1;
-
- if (!readmem(call + data_offset, KVADDR, &metadata, sizeof(metadata),
- "read ftrace_event_call data", RETURN_ON_ERROR))
- return -1;
-
- *fields = metadata + exit_fields_offset;
- return 0;
-}
-
-static int syscall_get_exit_fields(ulong call, ulong *fields)
-{
- static int inited;
- static ulong syscall_exit_fields_value;
-
- if (!inited) {
- struct syment *sp;
-
- if (!(sp = symbol_search("syscall_exit_fields"))) {
- inited = -1;
- } else {
- syscall_exit_fields_value = sp->value;
- inited = 1;
- }
- }
-
- if (inited == -1)
- return syscall_get_exit_fields_old(call, fields);
-
- *fields = syscall_exit_fields_value;
-
- return 0;
-}
-
-static
-int ftrace_get_event_type_fields(ulong call, ulong *fields)
-{
- static int inited;
- static int fields_offset;
- static int class_offset;
- static int get_fields_offset;
- static ulong syscall_get_enter_fields_value;
- static ulong syscall_get_exit_fields_value;
-
- struct syment *sp;
- ulong class, get_fields;
-
- if (inited)
- goto work;
-
- inited = 1;
- fields_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "fields"),
- MEMBER_OFFSET("trace_event_call", "fields"));
-
- class_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "class"),
- MEMBER_OFFSET("trace_event_call", "class"));
- if (class_offset < 0)
- goto work;
-
- inited = 2;
- fields_offset = MAX(MEMBER_OFFSET("ftrace_event_class", "fields"),
- MEMBER_OFFSET("trace_event_class", "fields"));
- if (fields_offset < 0)
- return -1;
-
- get_fields_offset = MAX(MEMBER_OFFSET("ftrace_event_class", "get_fields"),
- MEMBER_OFFSET("trace_event_class", "get_fields"));
- if ((sp = symbol_search("syscall_get_enter_fields")) != NULL)
- syscall_get_enter_fields_value = sp->value;
- if ((sp = symbol_search("syscall_get_exit_fields")) != NULL)
- syscall_get_exit_fields_value = sp->value;
-
-work:
- if (fields_offset < 0)
- return -1;
-
- if (inited == 1) {
- *fields = call + fields_offset;
- return 0;
- }
-
- if (!readmem(call + class_offset, KVADDR, &class, sizeof(class),
- "read ftrace_event_call class", RETURN_ON_ERROR))
- return -1;
-
- if (!readmem(class + get_fields_offset, KVADDR, &get_fields,
- sizeof(get_fields), "read ftrace_event_call get_fields",
- RETURN_ON_ERROR))
- return -1;
-
- if (!get_fields) {
- *fields = class + fields_offset;
- return 0;
- }
-
- if (get_fields == syscall_get_enter_fields_value)
- return syscall_get_enter_fields(call, fields);
-
- if (get_fields == syscall_get_exit_fields_value)
- return syscall_get_exit_fields(call, fields);
-
- fprintf(fp, "Unkown get_fields function\n");
- return -1;
-}
-
-static int ftrace_init_event_fields(ulong fields_head, int *pnfields,
- struct ftrace_field **pfields)
-{
- ulong pos;
-
- int nfields = 0, max_fields = 16;
- struct ftrace_field *fields = NULL;
-
- read_value(pos, fields_head, list_head, next);
-
- if (pos == 0) {
- if (verbose)
- fprintf(fp, "no field, head: %lu\n", fields_head);
- return 0;
- }
-
- fields = malloc(sizeof(*fields) * max_fields);
- if (fields == NULL)
- return -1;
-
- while (pos != fields_head) {
- ulong field;
- ulong name_addr, type_addr;
- char field_name[128], field_type[128];
- int offset, size, is_signed;
-
- field = pos - koffset(ftrace_event_field, link);
-
- /* Read a field from the core */
- read_value(name_addr, field, ftrace_event_field, name);
- read_value(type_addr, field, ftrace_event_field, type);
- read_value(offset, field, ftrace_event_field, offset);
- read_value(size, field, ftrace_event_field, size);
- read_value(is_signed, field, ftrace_event_field, is_signed);
-
- if (!read_string(name_addr, field_name, 128))
- goto out_fail;
- if (!read_string(type_addr, field_type, 128))
- goto out_fail;
-
- /* Enlarge fields array when need */
- if (nfields >= max_fields) {
- void *tmp;
-
- max_fields = nfields * 2;
- tmp = realloc(fields, sizeof(*fields) * max_fields);
- if (tmp == NULL)
- goto out_fail;
-
- fields = tmp;
- }
-
- /* Set up and Add a field */
- fields[nfields].offset = offset;
- fields[nfields].size = size;
- fields[nfields].is_signed = is_signed;
-
- fields[nfields].name = strdup(field_name);
- if (fields[nfields].name == NULL)
- goto out_fail;
-
- fields[nfields].type = strdup(field_type);
- if (fields[nfields].type == NULL) {
- free(fields[nfields].name);
- goto out_fail;
- }
-
- nfields++;
-
- /* Advance to the next field */
- read_value(pos, pos, list_head, next);
- }
-
- *pnfields = nfields;
- *pfields = fields;
-
- return 0;
-
-out_fail:
- for (nfields--; nfields >= 0; nfields--) {
- free(fields[nfields].name);
- free(fields[nfields].type);
- }
-
- free(fields);
- return -1;
-}
-
-static int ftrace_init_event_type(ulong call, struct event_type *aevent_type)
-{
- ulong fields_head = 0;
-
- if (ftrace_get_event_type_fields(call, &fields_head) < 0)
- return -1;
-
- return ftrace_init_event_fields(fields_head, &aevent_type->nfields,
- &aevent_type->fields);
-}
-
-static int ftrace_init_common_fields(void)
-{
- ulong ftrace_common_fields_head;
- struct syment *sp;
-
- sp = symbol_search("ftrace_common_fields");
- if (!sp)
- return 0;
-
- ftrace_common_fields_head = sp->value;
-
- return ftrace_init_event_fields(ftrace_common_fields_head,
- &ftrace_common_fields_count, &ftrace_common_fields);
-}
-
-static void ftrace_destroy_event_types(void)
-{
- int i, j;
-
- for (i = 0; i < nr_event_types; i++) {
- for (j = 0; j < event_types[i]->nfields; j++) {
- free(event_types[i]->fields[j].name);
- free(event_types[i]->fields[j].type);
- }
-
- free(event_types[i]->fields);
- free(event_types[i]->system);
- free(event_types[i]->name);
- free(event_types[i]->print_fmt);
- free(event_types[i]);
- }
-
- free(event_types);
- free(ftrace_common_fields);
-}
-
-static
-int ftrace_get_event_type_name(ulong call, char *name, int len)
-{
- static int inited;
- static int name_offset;
- static int flags_offset;
- static int tp_name_offset;
- static long tracepoint_flag;
-
- uint flags;
- ulong name_addr;
-
- if (inited)
- goto work;
-
- name_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "tp"),
- MEMBER_OFFSET("trace_event_call", "tp"));
- if (name_offset >= 0) {
- flags_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "flags"),
- MEMBER_OFFSET("trace_event_call", "flags"));
- if (flags_offset < 0)
- return -1;
-
- tp_name_offset = MEMBER_OFFSET("tracepoint", "name");
- if (tp_name_offset < 0)
- return -1;
-
- if (!enumerator_value("TRACE_EVENT_FL_TRACEPOINT", &tracepoint_flag))
- return -1;
-
- inited = 2;
- } else {
- name_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "name"),
- MEMBER_OFFSET("trace_event_call", "name"));
- inited = 1;
- }
-
-work:
- if (name_offset < 0)
- return -1;
-
- if (!readmem(call + name_offset, KVADDR, &name_addr, sizeof(name_addr),
- "read ftrace_event_call name_addr", RETURN_ON_ERROR))
- return -1;
-
- if (inited == 2) {
- if (!readmem(call + flags_offset, KVADDR, &flags,
- sizeof(flags), "read ftrace_event_call flags",
- RETURN_ON_ERROR))
- return -1;
-
- if (flags & (uint)tracepoint_flag) {
- if (!readmem(name_addr + tp_name_offset, KVADDR,
- &name_addr, sizeof(name_addr),
- "read tracepoint name", RETURN_ON_ERROR))
- return -1;
- }
-
- }
-
- if (!read_string(name_addr, name, len))
- return -1;
-
- return 0;
-}
-
-static
-int ftrace_get_event_type_system(ulong call, char *system, int len)
-{
- static int inited;
- static int sys_offset;
- static int class_offset;
-
- ulong ptr = call;
- ulong sys_addr;
-
- if (inited)
- goto work;
-
- inited = 1;
- sys_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "system"),
- MEMBER_OFFSET("trace_event_call", "system"));
-
- if (sys_offset >= 0)
- goto work;
-
- class_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "class"),
- MEMBER_OFFSET("trace_event_call", "class"));
- if (class_offset < 0)
- return -1;
-
- sys_offset = MAX(MEMBER_OFFSET("ftrace_event_class", "system"),
- MEMBER_OFFSET("trace_event_class", "system"));
- inited = 2;
-
-work:
- if (sys_offset < 0)
- return -1;
-
- if (inited == 2 && !readmem(call + class_offset, KVADDR, &ptr,
- sizeof(ptr), "read ftrace_event_call class_addr",
- RETURN_ON_ERROR))
- return -1;
-
- if (!readmem(ptr + sys_offset, KVADDR, &sys_addr, sizeof(sys_addr),
- "read ftrace_event_call sys_addr", RETURN_ON_ERROR))
- return -1;
-
- if (!read_string(sys_addr, system, len))
- return -1;
-
- return 0;
-}
-
-static int read_long_string(ulong kvaddr, char **buf)
-{
- char strbuf[MIN_PAGE_SIZE], *ret_buf = NULL;
- ulong kp;
- int cnt1, cnt2, size;
-
-again:
- kp = kvaddr;
- size = 0;
-
- for (;;) {
- cnt1 = MIN_PAGE_SIZE - (kp & (MIN_PAGE_SIZE-1));
-
- if (!readmem(kp, KVADDR, strbuf, cnt1,
- "readstring characters", QUIET|RETURN_ON_ERROR))
- return -1;
-
- cnt2 = strnlen(strbuf, cnt1);
- if (ret_buf)
- memcpy(ret_buf + size, strbuf, cnt2);
- kp += cnt2;
- size += cnt2;
-
- if (cnt2 < cnt1) {
- if (ret_buf) {
- break;
- } else {
- ret_buf = malloc(size + 1);
- if (!ret_buf)
- return -1;
- goto again;
- }
- }
- }
-
- ret_buf[size] = '\0';
- *buf = ret_buf;
- return size;
-}
-
-static
-int ftrace_get_event_type_print_fmt(ulong call, char **print_fmt)
-{
- static int inited;
- static int fmt_offset;
-
- ulong fmt_addr;
-
- if (!inited) {
- inited = 1;
- fmt_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "print_fmt"),
- MEMBER_OFFSET("trace_event_call", "print_fmt"));
- }
-
- if (fmt_offset < 0) {
- *print_fmt = strdup("Unknown print_fmt");
- return 0;
- }
-
- if (!readmem(call + fmt_offset, KVADDR, &fmt_addr, sizeof(fmt_addr),
- "read ftrace_event_call fmt_addr", RETURN_ON_ERROR))
- return -1;
-
- return read_long_string(fmt_addr, print_fmt);
-}
-
-static
-int ftrace_get_event_type_id(ulong call, int *id)
-{
- static int inited;
- static int id_offset;
-
- if (!inited) {
- inited = 1;
- id_offset = MAX(MEMBER_OFFSET("ftrace_event_call", "id"),
- MEMBER_OFFSET("trace_event_call", "id"));
-
- if (id_offset < 0) {
- /* id = call->event.type */
- int f1 = MAX(MEMBER_OFFSET("ftrace_event_call", "event"),
- MEMBER_OFFSET("trace_event_call", "event"));
- int f2 = MEMBER_OFFSET("trace_event", "type");
-
- if (f1 >= 0 && f2 >= 0)
- id_offset = f1 + f2;
- }
- }
-
- if (id_offset < 0)
- return -1;
-
- if (!readmem(call + id_offset, KVADDR, id, sizeof(*id),
- "read ftrace_event_call id", RETURN_ON_ERROR))
- return -1;
-
- return 0;
-}
-
-static int ftrace_init_event_types(void)
-{
- ulong event;
- struct event_type *aevent_type;
- int max_types = 128;
-
- event_types = malloc(sizeof(*event_types) * max_types);
- if (event_types == NULL)
- return -1;
-
- read_value(event, ftrace_events, list_head, next);
- while (event != ftrace_events) {
- ulong call;
- char name[128], system[128], *print_fmt;
- int id;
-
- call = event - koffset(ftrace_event_call, list);
-
- /* Read a event type from the core */
- if (ftrace_get_event_type_id(call, &id) < 0 ||
- ftrace_get_event_type_name(call, name, 128) < 0 ||
- ftrace_get_event_type_system(call, system, 128) < 0 ||
- ftrace_get_event_type_print_fmt(call, &print_fmt) < 0)
- goto out_fail;
-
- /* Enlarge event types array when need */
- if (nr_event_types >= max_types) {
- void *tmp;
-
- max_types = 2 * nr_event_types;
- tmp = realloc(event_types,
- sizeof(*event_types) * max_types);
- if (tmp == NULL) {
- free(print_fmt);
- goto out_fail;
- }
-
- event_types = tmp;
- }
-
- /* Create a event type */
- aevent_type = malloc(sizeof(*aevent_type));
- if (aevent_type == NULL) {
- free(print_fmt);
- goto out_fail;
- }
-
- aevent_type->system = strdup(system);
- aevent_type->name = strdup(name);
- aevent_type->print_fmt = print_fmt;
- aevent_type->id = id;
- aevent_type->nfields = 0;
- aevent_type->fields = NULL;
-
- if (aevent_type->system == NULL || aevent_type->name == NULL)
- goto out_fail_free_aevent_type;
-
- if (ftrace_init_event_type(call, aevent_type) < 0)
- goto out_fail_free_aevent_type;
-
- if (!strcmp("ftrace", aevent_type->system))
- aevent_type->plugin = 1;
- else
- aevent_type->plugin = 0;
-
- /* Add a event type */
- event_types[nr_event_types++] = aevent_type;
- if ((unsigned)id < MAX_CACHE_ID)
- event_type_cache[id] = aevent_type;
-
- /* Advance to the next event type */
- read_value(event, event, list_head, next);
- }
-
- if (ftrace_init_common_fields() < 0)
- goto out_fail;
-
- return 0;
-
-out_fail_free_aevent_type:
- free(aevent_type->system);
- free(aevent_type->name);
- free(aevent_type->print_fmt);
- free(aevent_type);
-out_fail:
- ftrace_destroy_event_types();
- return -1;
-}
-
-#define default_common_field_count 5
-
-static int ftrace_dump_event_type(struct event_type *t, const char *path)
-{
- char format_path[PATH_MAX];
- FILE *out;
- int i, nfields;
- struct ftrace_field *fields;
- int printed_common_field = 0;
-
- snprintf(format_path, sizeof(format_path), "%s/format", path);
- out = fopen(format_path, "w");
- if (out == NULL)
- return -1;
-
- fprintf(out, "name: %s\n", t->name);
- fprintf(out, "ID: %d\n", t->id);
- fprintf(out, "format:\n");
-
- if (ftrace_common_fields_count) {
- nfields = ftrace_common_fields_count;
- fields = ftrace_common_fields;
- } else {
- nfields = default_common_field_count;
- fields = &t->fields[t->nfields - nfields];
- }
-
-again:
- for (i = nfields - 1; i >= 0; i--) {
- /*
- * Smartly shows the array type(except dynamic array).
- * Normal:
- * field:TYPE VAR
- * If TYPE := TYPE[LEN], it is shown:
- * field:TYPE VAR[LEN]
- */
- struct ftrace_field *field = &fields[i];
- const char *array_descriptor = strchr(field->type, '[');
-
- if (!strncmp(field->type, "__data_loc", 10))
- array_descriptor = NULL;
-
- if (!array_descriptor) {
- fprintf(out, "\tfield:%s %s;\toffset:%u;"
- "\tsize:%u;\tsigned:%d;\n",
- field->type, field->name, field->offset,
- field->size, !!field->is_signed);
- } else {
- fprintf(out, "\tfield:%.*s %s%s;\toffset:%u;"
- "\tsize:%u;\tsigned:%d;\n",
- (int)(array_descriptor - field->type),
- field->type, field->name,
- array_descriptor, field->offset,
- field->size, !!field->is_signed);
- }
- }
-
- if (!printed_common_field) {
- fprintf(out, "\n");
-
- if (ftrace_common_fields_count)
- nfields = t->nfields;
- else
- nfields = t->nfields - default_common_field_count;
- fields = t->fields;
-
- printed_common_field = 1;
- goto again;
- }
-
- fprintf(out, "\nprint fmt: %s\n", t->print_fmt);
-
- fclose(out);
-
- return 0;
-}
-
-static int ftrace_dump_event_types(const char *events_path)
-{
- int i;
-
- for (i = 0; i < nr_event_types; i++) {
- char path[PATH_MAX];
- struct event_type *t = event_types[i];
-
- snprintf(path, sizeof(path), "%s/%s", events_path, t->system);
- if (try_mkdir(path, 0755) < 0)
- return -1;
-
- snprintf(path, sizeof(path), "%s/%s/%s", events_path,
- t->system, t->name);
- if (try_mkdir(path, 0755) < 0)
- return -1;
-
- if (ftrace_dump_event_type(t, path) < 0)
- return -1;
- }
-
- return 0;
-}
-
-static void show_basic_info(void)
-{
- fprintf(fp, "current tracer is %s\n", current_tracer_name);
-}
-
-static int dump_saved_cmdlines(const char *dump_tracing_dir)
-{
- char path[PATH_MAX];
- FILE *out;
- int i;
- struct task_context *tc;
-
- snprintf(path, sizeof(path), "%s/saved_cmdlines", dump_tracing_dir);
- out = fopen(path, "w");
- if (out == NULL)
- return -1;
-
- tc = FIRST_CONTEXT();
- for (i = 0; i < RUNNING_TASKS(); i++)
- fprintf(out, "%d %s\n", (int)tc[i].pid, tc[i].comm);
-
- fclose(out);
- return 0;
-}
-
-static int dump_kallsyms(const char *dump_tracing_dir)
-{
- char path[PATH_MAX];
- FILE *out;
- int i;
- struct syment *sp;
-
- snprintf(path, sizeof(path), "%s/kallsyms", dump_tracing_dir);
- out = fopen(path, "w");
- if (out == NULL)
- return -1;
-
- for (sp = st->symtable; sp < st->symend; sp++)
- fprintf(out, "%lx %c %s\n", sp->value, sp->type, sp->name);
-
- for (i = 0; i < st->mods_installed; i++) {
- struct load_module *lm = &st->load_modules[i];
-
- for (sp = lm->mod_symtable; sp <= lm->mod_symend; sp++) {
- if (!strncmp(sp->name, "_MODULE_", strlen("_MODULE_")))
- continue;
-
- fprintf(out, "%lx %c %s\t[%s]\n", sp->value, sp->type,
- sp->name, lm->mod_name);
- }
- }
-
- fclose(out);
- return 0;
-}
-
-static int trace_cmd_data_output(int fd);
-
-#define FTRACE_DUMP_SYMBOLS (1 << 0)
-#define FTRACE_DUMP_META_DATA (1 << 1)
-
-static int populate_ftrace_dir_tree(struct trace_instance *ti,
- char *root, uint flags)
-{
- char path[PATH_MAX];
- int ret;
-
- ret = mkdir(root, 0755);
- if (ret < 0) {
- if (errno == EEXIST)
- error(INFO, "mkdir: %s exists\n", root);
- return FALSE;
- }
-
- snprintf(path, sizeof(path), "%s/per_cpu", root);
- if (try_mkdir(path, 0755) < 0)
- return FALSE;
-
- if (ftrace_dump_buffers(path, ti) < 0)
- return FALSE;
-
- if (flags & FTRACE_DUMP_META_DATA) {
- /* Dump event types */
- snprintf(path, sizeof(path), "%s/events", root);
- if (try_mkdir(path, 0755) < 0)
- return FALSE;
-
- if (ftrace_dump_event_types(path) < 0)
- return FALSE;
-
- /* Dump pids with corresponding cmdlines */
- if (dump_saved_cmdlines(root) < 0)
- return FALSE;
- }
-
- if (flags & FTRACE_DUMP_SYMBOLS) {
- /* Dump all symbols of the kernel */
- dump_kallsyms(root);
- }
-
- return TRUE;
-}
-
-static void ftrace_dump(int argc, char *argv[])
-{
- int c;
- int i;
- uint flags = 0;
- char *dump_tracing_dir;
- char instance_path[PATH_MAX];
-
- while ((c = getopt(argc, argv, "smt")) != EOF) {
- switch(c)
- {
- case 's':
- flags |= FTRACE_DUMP_SYMBOLS;
- break;
- case 'm':
- flags |= FTRACE_DUMP_META_DATA;
- break;
- case 't':
- if (flags & FTRACE_DUMP_SYMBOLS ||
- flags & FTRACE_DUMP_META_DATA ||
- argc - optind > 1)
- cmd_usage(pc->curcmd, SYNOPSIS);
- else {
- char *trace_dat = "trace.dat";
- int fd;
-
- if (argc - optind == 0)
- trace_dat = "trace.dat";
- else if (argc - optind == 1)
- trace_dat = argv[optind];
- fd = open(trace_dat, O_WRONLY | O_CREAT
- | O_TRUNC, 0644);
- trace_cmd_data_output(fd);
- close(fd);
- }
- return;
- default:
- cmd_usage(pc->curcmd, SYNOPSIS);
- return;
- }
- }
-
- if (argc - optind == 0) {
- dump_tracing_dir = "dump_tracing_dir";
- } else if (argc - optind == 1) {
- dump_tracing_dir = argv[optind];
- } else {
- cmd_usage(pc->curcmd, SYNOPSIS);
- return;
- }
-
- if (!populate_ftrace_dir_tree(&global_trace_instance, dump_tracing_dir, flags))
- return;
-
- if (!multiple_instances_available || instance_count == 0)
- return;
-
- /* Create an instances directory, and dump instance data in there */
- snprintf(instance_path, sizeof(instance_path),
- "%s/instances", dump_tracing_dir);
- if (try_mkdir(instance_path, 0755) < 0)
- return;
-
- /* Don't care about the flags anymore */
- flags = 0;
-
- for (i = 0; i < instance_count; i++)
- {
- struct trace_instance *ti = &trace_instances[i];
-
- snprintf(instance_path, sizeof(instance_path),
- "%s/instances/%s", dump_tracing_dir,
- ti->name);
-
- if (populate_ftrace_dir_tree(ti, instance_path, flags) < 0)
- break;
- }
-
- return;
-}
-
-static void ftrace_show(int argc, char *argv[])
-{
- char buf[4096];
- char tmp[] = "/tmp/crash.trace_dat.XXXXXX";
- char *trace_cmd = "trace-cmd", *env_trace_cmd = getenv("TRACE_CMD");
- int fd;
- FILE *file;
- size_t ret;
- size_t nitems __attribute__ ((__unused__));
-
- /* check trace-cmd */
- if (env_trace_cmd)
- trace_cmd = env_trace_cmd;
- buf[0] = 0;
- if ((file = popen(trace_cmd, "r"))) {
- ret = fread(buf, 1, sizeof(buf), file);
- buf[ret] = 0;
- pclose(file);
- }
- if (!strstr(buf, "trace-cmd version")) {
- if (env_trace_cmd)
- fprintf(fp, "Invalid environment TRACE_CMD: %s\n",
- env_trace_cmd);
- else
- fprintf(fp, "\"trace show\" requires trace-cmd.\n"
- "please set the environment TRACE_CMD "
- "if you installed it in a special path\n"
- );
- return;
- }
-
- /* dump trace.dat to the temp file */
- fd = mkstemp(tmp);
- if (fd < 0)
- return;
- if (trace_cmd_data_output(fd) < 0)
- goto out;
-
- /* splice the output of trace-cmd to user */
- snprintf(buf, sizeof(buf), "%s report %s", trace_cmd, tmp);
- if (!(file = popen(buf, "r")))
- goto out;
- for (;;) {
- ret = fread(buf, 1, sizeof(buf), file);
- if (ret == 0)
- break;
- nitems = fwrite(buf, 1, ret, fp);
- }
- pclose(file);
-out:
- close(fd);
- unlink(tmp);
- return;
-}
-
-static void cmd_ftrace(void)
-{
- if (argcnt == 1)
- show_basic_info();
- else if (!strcmp(args[1], "dump"))
- ftrace_dump(argcnt - 1, args + 1);
- else if (!strcmp(args[1], "show"))
- ftrace_show(argcnt - 1, args + 1);
- else if (!strcmp(args[1], "report"))
- ftrace_show(argcnt - 1, args + 1);
- else
- cmd_usage(pc->curcmd, SYNOPSIS);
-}
-
-static char *help_ftrace[] = {
-"trace",
-"show or dump the tracing info",
-"[ <show [-c <cpulist>] [-f [no]<flagname>]> | <dump [-sm] <dest-dir>> ] | <dump -t <trace.dat> ]",
-"trace",
-" shows the current tracer and other informations.",
-"",
-"trace show",
-" shows all events with readability text(sorted by timestamp)",
-"",
-"trace report",
-" the same as \"trace show\"",
-"",
-"trace dump [-sm] <dest-dir>",
-" dump ring_buffers to dest-dir. Then you can parse it",
-" by other tracing tools. The dirs and files are generated",
-" the same as debugfs/tracing.",
-" -m: also dump metadata of ftrace.",
-" -s: also dump symbols of the kernel.",
-"trace dump -t [output-file-name]",
-" dump ring_buffers and all meta data to a file that can",
-" be parsed by trace-cmd. Default output file name is \"trace.dat\".",
-NULL
-};
-
-static struct command_table_entry command_table[] = {
- { "trace", cmd_ftrace, help_ftrace, 0 },
- { NULL, 0, 0, 0 }
-};
-
-static int ftrace_initialized;
-
-void __attribute__((constructor))
-trace_init(void)
-{
- if (ftrace_init() < 0)
- return;
-
- ftrace_initialized = 1;
- register_extension(command_table);
-}
-
-void __attribute__((destructor))
-trace_fini(void)
-{
- if (ftrace_initialized)
- ftrace_destroy();
-}
-
-#define TRACE_CMD_FILE_VERSION_STRING "6"
-
-static inline int host_bigendian(void)
-{
- unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
- unsigned int *ptr;
-
- ptr = (unsigned int *)str;
- return *ptr == 0x01020304;
-}
-
-static char *tmp_file_buf;
-static unsigned long long tmp_file_pos;
-static unsigned long long tmp_file_size;
-static int tmp_file_error;
-
-static int init_tmp_file(void)
-{
- tmp_file_buf = malloc(4096);
- if (tmp_file_buf == NULL)
- return -1;
-
- tmp_file_pos = 0;
- tmp_file_size = 4096;
- tmp_file_error = 0;
-
- return 0;
-}
-
-static void destory_tmp_file(void)
-{
- free(tmp_file_buf);
-}
-
-#define tmp_fprintf(fmt...) \
-do { \
- char *__buf = tmp_file_buf; \
- unsigned long long __pos; \
- \
- if (tmp_file_error) \
- break; \
- __pos = tmp_file_pos; \
- __pos += snprintf(__buf + __pos, tmp_file_size - __pos, fmt); \
- if (__pos >= tmp_file_size) { \
- tmp_file_size = __pos + tmp_file_size; \
- __buf = realloc(__buf, tmp_file_size); \
- if (!__buf) { \
- tmp_file_error = 1; \
- break; \
- } \
- tmp_file_buf = __buf; \
- __pos = tmp_file_pos; \
- __pos += snprintf(__buf + __pos, tmp_file_size - __pos, fmt);\
- } \
- tmp_file_pos = __pos; \
-} while (0)
-
-static int tmp_file_record_size4(int fd)
-{
- unsigned int size = tmp_file_pos;
-
- if (tmp_file_error)
- return -1;
- if (write_and_check(fd, &size, 4))
- return -1;
- return 0;
-}
-
-static int tmp_file_record_size8(int fd)
-{
- if (tmp_file_error)
- return -1;
- if (write_and_check(fd, &tmp_file_pos, 8))
- return -1;
- return 0;
-}
-
-static int tmp_file_flush(int fd)
-{
- if (tmp_file_error)
- return -1;
- if (write_and_check(fd, tmp_file_buf, tmp_file_pos))
- return -1;
- tmp_file_pos = 0;
- return 0;
-}
-
-static int save_initial_data(int fd)
-{
- int page_size;
- char buf[20];
-
- if (write_and_check(fd, "\027\010\104tracing", 10))
- return -1;
-
- if (write_and_check(fd, TRACE_CMD_FILE_VERSION_STRING,
- strlen(TRACE_CMD_FILE_VERSION_STRING) + 1))
- return -1;
-
- /* Crash ensure core file endian and the host endian are the same */
- if (host_bigendian())
- buf[0] = 1;
- else
- buf[0] = 0;
-
- if (write_and_check(fd, buf, 1))
- return -1;
-
- /* save size of long (this may not be what the kernel is) */
- buf[0] = sizeof(long);
- if (write_and_check(fd, buf, 1))
- return -1;
-
- page_size = PAGESIZE();
- if (write_and_check(fd, &page_size, 4))
- return -1;
-
- return 0;
-}
-
-static int save_header_files(int fd)
-{
- /* save header_page */
- if (write_and_check(fd, "header_page", 12))
- return -1;
-
- tmp_fprintf("\tfield: u64 timestamp;\toffset:0;\tsize:8;\tsigned:0;\n");
-
- tmp_fprintf("\tfield: local_t commit;\toffset:8;\tsize:%u;\t"
- "signed:1;\n", (unsigned int)sizeof(long));
-
- tmp_fprintf("\tfield: int overwrite;\toffset:8;\tsize:%u;\tsigned:1;\n",
- (unsigned int)sizeof(long));
-
- tmp_fprintf("\tfield: char data;\toffset:%u;\tsize:%u;\tsigned:1;\n",
- (unsigned int)(8 + sizeof(long)),
- (unsigned int)(PAGESIZE() - 8 - sizeof(long)));
-
- if (tmp_file_record_size8(fd))
- return -1;
- if (tmp_file_flush(fd))
- return -1;
-
- /* save header_event */
- if (write_and_check(fd, "header_event", 13))
- return -1;
-
- tmp_fprintf(
- "# compressed entry header\n"
- "\ttype_len : 5 bits\n"
- "\ttime_delta : 27 bits\n"
- "\tarray : 32 bits\n"
- "\n"
- "\tpadding : type == 29\n"
- "\ttime_extend : type == 30\n"
- "\tdata max type_len == 28\n"
- );
-
- if (tmp_file_record_size8(fd))
- return -1;
- if (tmp_file_flush(fd))
- return -1;
-
- return 0;
-}
-
-static int save_event_file(int fd, struct event_type *t)
-{
- int i, nfields;
- struct ftrace_field *fields;
- int printed_common_field = 0;
-
- tmp_fprintf("name: %s\n", t->name);
- tmp_fprintf("ID: %d\n", t->id);
- tmp_fprintf("format:\n");
-
- if (ftrace_common_fields_count) {
- nfields = ftrace_common_fields_count;
- fields = ftrace_common_fields;
- } else {
- nfields = default_common_field_count;
- fields = &t->fields[t->nfields - nfields];
- }
-
-again:
- for (i = nfields - 1; i >= 0; i--) {
- /*
- * Smartly shows the array type(except dynamic array).
- * Normal:
- * field:TYPE VAR
- * If TYPE := TYPE[LEN], it is shown:
- * field:TYPE VAR[LEN]
- */
- struct ftrace_field *field = &fields[i];
- const char *array_descriptor = strchr(field->type, '[');
-
- if (!strncmp(field->type, "__data_loc", 10))
- array_descriptor = NULL;
-
- if (!array_descriptor) {
- tmp_fprintf("\tfield:%s %s;\toffset:%u;"
- "\tsize:%u;\tsigned:%d;\n",
- field->type, field->name, field->offset,
- field->size, !!field->is_signed);
- } else {
- tmp_fprintf("\tfield:%.*s %s%s;\toffset:%u;"
- "\tsize:%u;\tsigned:%d;\n",
- (int)(array_descriptor - field->type),
- field->type, field->name,
- array_descriptor, field->offset,
- field->size, !!field->is_signed);
- }
- }
-
- if (!printed_common_field) {
- tmp_fprintf("\n");
-
- if (ftrace_common_fields_count)
- nfields = t->nfields;
- else
- nfields = t->nfields - default_common_field_count;
- fields = t->fields;
-
- printed_common_field = 1;
- goto again;
- }
-
- tmp_fprintf("\nprint fmt: %s\n", t->print_fmt);
-
- if (tmp_file_record_size8(fd))
- return -1;
- return tmp_file_flush(fd);
-}
-
-static int save_system_files(int fd, int *system_ids, int system_id)
-{
- int i, total = 0;
-
- for (i = 0; i < nr_event_types; i++) {
- if (system_ids[i] == system_id)
- total++;
- }
-
- if (write_and_check(fd, &total, 4))
- return -1;
-
- for (i = 0; i < nr_event_types; i++) {
- if (system_ids[i] != system_id)
- continue;
-
- if (save_event_file(fd, event_types[i]))
- return -1;
- }
-
- return 0;
-}
-
-static int save_events_files(int fd)
-{
- int system_id = 1, *system_ids;
- const char *system = "ftrace";
- int i;
- int nr_systems;
-
- system_ids = calloc(sizeof(*system_ids), nr_event_types);
- if (system_ids == NULL)
- return -1;
-
- for (;;) {
- for (i = 0; i < nr_event_types; i++) {
- if (system_ids[i])
- continue;
- if (!system) {
- system = event_types[i]->system;
- system_ids[i] = system_id;
- continue;
- }
- if (!strcmp(event_types[i]->system, system))
- system_ids[i] = system_id;
- }
- if (!system)
- break;
- system_id++;
- system = NULL;
- }
-
- /* ftrace events */
- if (save_system_files(fd, system_ids, 1))
- goto fail;
-
- /* other systems events */
- nr_systems = system_id - 2;
- if (write_and_check(fd, &nr_systems, 4))
- goto fail;
- for (system_id = 2; system_id < nr_systems + 2; system_id++) {
- for (i = 0; i < nr_event_types; i++) {
- if (system_ids[i] == system_id)
- break;
- }
- if (write_and_check(fd, (void *)event_types[i]->system,
- strlen(event_types[i]->system) + 1))
- goto fail;
- if (save_system_files(fd, system_ids, system_id))
- goto fail;
- }
-
- free(system_ids);
- return 0;
-
-fail:
- free(system_ids);
- return -1;
-}
-
-static int save_proc_kallsyms(int fd)
-{
- int i;
- struct syment *sp;
-
- for (sp = st->symtable; sp < st->symend; sp++)
- tmp_fprintf("%lx %c %s\n", sp->value, sp->type, sp->name);
-
- for (i = 0; i < st->mods_installed; i++) {
- struct load_module *lm = &st->load_modules[i];
-
- for (sp = lm->mod_symtable; sp <= lm->mod_symend; sp++) {
- if (!strncmp(sp->name, "_MODULE_", strlen("_MODULE_")))
- continue;
-
- /* Currently sp->type for modules is not trusted */
- tmp_fprintf("%lx %c %s\t[%s]\n", sp->value, 'm',
- sp->name, lm->mod_name);
- }
- }
-
- if (tmp_file_record_size4(fd))
- return -1;
- return tmp_file_flush(fd);
-}
-
-static int add_print_address(long address)
-{
- char string[4096];
- size_t len;
- int i;
-
- len = read_string(address, string, sizeof(string));
- if (!len)
- return -1;
-
- tmp_fprintf("0x%lx : \"", address);
-
- for (i = 0; string[i]; i++) {
- switch (string[i]) {
- case '\n':
- tmp_fprintf("\\n");
- break;
- case '\t':
- tmp_fprintf("\\t");
- break;
- case '\\':
- tmp_fprintf("\\\\");
- break;
- case '"':
- tmp_fprintf("\\\"");
- break;
- default:
- tmp_fprintf("%c", string[i]);
- }
- }
- tmp_fprintf("\"\n");
-
- return 0;
-}
-
-static int save_ftrace_printk(int fd)
-{
- struct kernel_list_head *mod_fmt;
- struct syment *s, *e, *b;
- long bprintk_fmt_s, bprintk_fmt_e;
- long *address;
- size_t i, count;
- int addr_is_array = 0;
-
- s = symbol_search("__start___trace_bprintk_fmt");
- e = symbol_search("__stop___trace_bprintk_fmt");
- if (s == NULL || e == NULL)
- return -1;
-
- bprintk_fmt_s = s->value;
- bprintk_fmt_e = e->value;
- count = (bprintk_fmt_e - bprintk_fmt_s) / sizeof(long);
-
- if (count == 0)
- goto do_mods;
-
- address = malloc(count * sizeof(long));
- if (address == NULL)
- return -1;
-
- if (!readmem(bprintk_fmt_s, KVADDR, address, count * sizeof(long),
- "get printk address", RETURN_ON_ERROR)) {
- free(address);
- return -1;
- }
-
- for (i = 0; i < count; i++) {
- if (add_print_address(address[i]) < 0) {
- free(address);
- return -1;
- }
- }
-
- free(address);
-
- do_mods:
-
- /* Add modules */
- b = symbol_search("trace_bprintk_fmt_list");
- if (!b)
- goto out;
-
- switch (MEMBER_TYPE("trace_bprintk_fmt", "fmt")) {
- case TYPE_CODE_ARRAY:
- addr_is_array = 1;
- break;
- case TYPE_CODE_PTR:
- default:
- /* default not array */
- break;
- }
-
- mod_fmt = (struct kernel_list_head *)GETBUF(SIZE(list_head));
- if (!readmem(b->value, KVADDR, mod_fmt,
- SIZE(list_head), "trace_bprintk_fmt_list contents",
- RETURN_ON_ERROR))
- goto out_free;
-
- while ((unsigned long)mod_fmt->next != b->value) {
- unsigned long addr;
-
- addr = (unsigned long)mod_fmt->next + SIZE(list_head);
- if (!addr_is_array) {
- if (!readmem(addr, KVADDR, &addr, sizeof(addr),
- "trace_bprintk_fmt_list fmt field",
- RETURN_ON_ERROR))
- goto out_free;
- }
-
- if (!readmem((unsigned long)mod_fmt->next, KVADDR, mod_fmt,
- SIZE(list_head), "trace_bprintk_fmt_list contents",
- RETURN_ON_ERROR))
- goto out_free;
-
- if (add_print_address(addr) < 0)
- goto out_free;
- count++;
- }
-
- out_free:
- FREEBUF(mod_fmt);
- out:
- if (count == 0) {
- unsigned int size = 0;
- return write_and_check(fd, &size, 4);
- }
- if (tmp_file_record_size4(fd))
- return -1;
- return tmp_file_flush(fd);
-}
-
-static int save_ftrace_cmdlines(int fd)
-{
- int i;
- struct task_context *tc = FIRST_CONTEXT();
-
- for (i = 0; i < RUNNING_TASKS(); i++)
- tmp_fprintf("%d %s\n", (int)tc[i].pid, tc[i].comm);
-
- if (tmp_file_record_size8(fd))
- return -1;
- return tmp_file_flush(fd);
-}
-
-/* From trace-cmd.h */
-enum {
- TRACECMD_OPTION_DONE, /* 0 */
- TRACECMD_OPTION_DATE, /* 1 */
- TRACECMD_OPTION_CPUSTAT, /* 2 */
- TRACECMD_OPTION_BUFFER, /* 3 */
- TRACECMD_OPTION_TRACECLOCK, /* 4 */
- TRACECMD_OPTION_UNAME, /* 5 */
- TRACECMD_OPTION_HOOK, /* 6 */
-};
-
-static int write_options(int fd, unsigned long long *buffer_offsets)
-{
- int i;
- unsigned short option;
-
- if (!multiple_instances_available)
- return 0;
-
- if (write_and_check(fd, "options ", 10))
- return -1;
-
- option = TRACECMD_OPTION_BUFFER;
- for (i = 0; i < instance_count; i++)
- {
- char *name = trace_instances[i].name;
- size_t name_size = strlen(name) + 1; /* Name length + '\0' */
- unsigned long long option_size = 8 + name_size;
- unsigned long long offset;
-
- offset = buffer_offsets ? buffer_offsets[i] : 0;
- if (write_and_check(fd, &option, 2))
- return -1;
- if (write_and_check(fd, &option_size, 4))
- return -1;
- if (write_and_check(fd, &offset, 8))
- return -1;
- if (write_and_check(fd, name, name_size))
- return -1;
- }
-
- option = TRACECMD_OPTION_DONE;
- if (write_and_check(fd, &option, 2))
- return -1;
-
- return 0;
-}
-
-static int save_res_data(int fd, int nr_cpu_buffers, unsigned long long *buffer_offsets)
-{
- if (write_and_check(fd, &nr_cpu_buffers, 4))
- return -1;
-
- if (write_options(fd, buffer_offsets))
- return -1;
-
- if (write_and_check(fd, "flyrecord", 10))
- return -1;
-
- return 0;
-}
-
-static int save_record_data(int fd, int nr_cpu_buffers, struct trace_instance *ti)
-{
- int i, j;
- unsigned long long offset, buffer_offset;
- void *page_tmp;
-
- offset = lseek(fd, 0, SEEK_CUR);
- offset += nr_cpu_buffers * 16;
- offset = (offset + (PAGESIZE() - 1)) & ~(PAGESIZE() - 1);
- buffer_offset = offset;
-
- for (i = 0; i < nr_cpu_ids; i++) {
- struct ring_buffer_per_cpu *cpu_buffer = &ti->buffers[i];
- unsigned long long buffer_size;
-
- if (!cpu_buffer->kaddr)
- continue;
-
- buffer_size = PAGESIZE() * cpu_buffer->nr_linear_pages;
- if (write_and_check(fd, &buffer_offset, 8))
- return -1;
- if (write_and_check(fd, &buffer_size, 8))
- return -1;
- buffer_offset += buffer_size;
- }
-
- page_tmp = malloc(PAGESIZE());
- if (page_tmp == NULL)
- return -1;
-
- lseek(fd, offset, SEEK_SET);
- for (i = 0; i < nr_cpu_ids; i++) {
- struct ring_buffer_per_cpu *cpu_buffer = &ti->buffers[i];
-
- if (!cpu_buffer->kaddr)
- continue;
-
- for (j = 0; j < cpu_buffer->nr_linear_pages; j++) {
- if (ftrace_dump_page(fd, cpu_buffer->linear_pages[j],
- page_tmp) < 0) {
- free(page_tmp);
- return -1;
- }
- }
- }
-
- free(page_tmp);
-
- return 0;
-}
-
-static int get_nr_cpu_buffers(struct trace_instance *ti)
-{
- int i;
- int nr_cpu_buffers = 0;
-
- for (i = 0; i < nr_cpu_ids; i++) {
- struct ring_buffer_per_cpu *cpu_buffer = &ti->buffers[i];
-
- if (!cpu_buffer->kaddr)
- continue;
-
- nr_cpu_buffers++;
- }
-
- return nr_cpu_buffers;
-}
-
-static int __trace_cmd_data_output(int fd)
-{
- int nr_cpu_buffers;
- unsigned long long global_res_data_offset;
- unsigned long long *instance_offsets;
-
- instance_offsets = calloc(sizeof(unsigned long long), instance_count);
-
- nr_cpu_buffers = get_nr_cpu_buffers(&global_trace_instance);
-
- if (save_initial_data(fd))
- return -1;
- if (save_header_files(fd))
- return -1;
- if (save_events_files(fd)) /* ftrace events and other systems events */
- return -1;
- if (save_proc_kallsyms(fd))
- return -1;
- if (save_ftrace_printk(fd))
- return -1;
- if (save_ftrace_cmdlines(fd))
- return -1;
-
- /* We don't have the instance buffer offsets yet, so we'll write in 0s
- * for now, and fix it up after we have that information available */
- global_res_data_offset = lseek(fd, 0, SEEK_CUR);
- if (save_res_data(fd, nr_cpu_buffers, NULL))
- return -1;
- if (save_record_data(fd, nr_cpu_buffers, &global_trace_instance))
- return -1;
-
- if (multiple_instances_available)
- {
- int i;
-
- for (i = 0; i < instance_count; i++)
- {
- struct trace_instance *ti = &trace_instances[i];
- nr_cpu_buffers = get_nr_cpu_buffers(ti);
-
- /* Save off the instance offset for fixup later */
- instance_offsets[i] = lseek(fd, 0, SEEK_CUR);
-
- if (write_and_check(fd, "flyrecord", 10))
- return -1;
- if (save_record_data(fd, nr_cpu_buffers, ti))
- return -1;
- }
- }
-
- /* Fix up the global trace's options header with the instance offsets */
- lseek(fd, global_res_data_offset, SEEK_SET);
- nr_cpu_buffers = get_nr_cpu_buffers(&global_trace_instance);
- if (save_res_data(fd, nr_cpu_buffers, instance_offsets))
- return -1;
-
- return 0;
-}
-
-static int trace_cmd_data_output(int fd)
-{
- int ret;
-
- if (init_tmp_file())
- return -1;
-
- ret = __trace_cmd_data_output(fd);
- destory_tmp_file();
-
- return ret;
-}
diff --git a/extensions/trace.c.README b/extensions/trace.c.README
new file mode 100644
index 000000000000..de1d43ce88a2
--- /dev/null
+++ b/extensions/trace.c.README
@@ -0,0 +1,7 @@
+
+The trace.c extension module moved to the separate repository:
+ https://github.com/fujitsu/crash-trace
+
+See also:
+ https://crash-utility.github.io/extensions.html#TRACE
+
--
2.18.4
3 years, 8 months
[PATCH v2] x86_64: Add Linux 5.8+ exception functions to check exception frame
by HAGIO KAZUHITO(萩尾 一仁)
Fix for 'bt' command and options on Linux 5.8-rc1 and later kernels
that contain merge commit 076f14be7fc942e112c94c841baec44124275cd0.
The merged patches changed the name of exception functions that
have been used by the crash utility to check the exception frame.
Without the patch, the command and options cannot display it.
Before:
crash> bt
PID: 8752 TASK: ffff8f80cb244380 CPU: 2 COMMAND: "insmod"
#0 [ffffa3e40187f9f8] machine_kexec at ffffffffab25d267
#1 [ffffa3e40187fa48] __crash_kexec at ffffffffab38e2ed
#2 [ffffa3e40187fb10] crash_kexec at ffffffffab38f1dd
#3 [ffffa3e40187fb28] oops_end at ffffffffab222cbd
#4 [ffffa3e40187fb48] do_trap at ffffffffab21fea1
#5 [ffffa3e40187fb90] do_error_trap at ffffffffab21ff75
#6 [ffffa3e40187fbd0] exc_invalid_op at ffffffffabb76a2c
#7 [ffffa3e40187fbf0] asm_exc_invalid_op at ffffffffabc00a72
#8 [ffffa3e40187fc78] init_module at ffffffffc042b018 [invalid]
#9 [ffffa3e40187fca0] init_module at ffffffffc042b018 [invalid]
#10 [ffffa3e40187fca8] do_one_initcall at ffffffffab202806
#11 [ffffa3e40187fd18] do_init_module at ffffffffab3888ba
#12 [ffffa3e40187fd38] load_module at ffffffffab38afde
After:
crash> bt
PID: 8752 TASK: ffff8f80cb244380 CPU: 2 COMMAND: "insmod"
#0 [ffffa3e40187f9f8] machine_kexec at ffffffffab25d267
#1 [ffffa3e40187fa48] __crash_kexec at ffffffffab38e2ed
#2 [ffffa3e40187fb10] crash_kexec at ffffffffab38f1dd
#3 [ffffa3e40187fb28] oops_end at ffffffffab222cbd
#4 [ffffa3e40187fb48] do_trap at ffffffffab21fea1
#5 [ffffa3e40187fb90] do_error_trap at ffffffffab21ff75
#6 [ffffa3e40187fbd0] exc_invalid_op at ffffffffabb76a2c
#7 [ffffa3e40187fbf0] asm_exc_invalid_op at ffffffffabc00a72
[exception RIP: init_module+24]
RIP: ffffffffc042b018 RSP: ffffa3e40187fca8 RFLAGS: 00010246
RAX: 000000000000001c RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffff8f80fbd18000 RDI: ffff8f80fbd18000
RBP: ffffffffc042b000 R8: 000000000000029d R9: 000000000000002c
R10: 0000000000000000 R11: ffffa3e40187fb58 R12: ffffffffc042d018
R13: ffffa3e40187fdf0 R14: ffffffffc042d000 R15: ffffa3e40187fe90
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#8 [ffffa3e40187fca0] init_module at ffffffffc042b018 [invalid]
#9 [ffffa3e40187fca8] do_one_initcall at ffffffffab202806
#10 [ffffa3e40187fd18] do_init_module at ffffffffab3888ba
#11 [ffffa3e40187fd38] load_module at ffffffffab38afde
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
v1 -> v2
- removed "xen_" prefix from "xen_asm_exc_debug"
defs.h | 1 +
x86_64.c | 43 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/defs.h b/defs.h
index c29b3fa3dee9..f9c711c19d91 100644
--- a/defs.h
+++ b/defs.h
@@ -6026,6 +6026,7 @@ struct machine_specific {
ulong cpu_entry_area_start;
ulong cpu_entry_area_end;
ulong page_offset_force;
+ char **exception_functions;
};
#define KSYMS_START (0x1)
diff --git a/x86_64.c b/x86_64.c
index f5b2f7b5f040..d54a3960db36 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -139,6 +139,9 @@ static void orc_dump(ulong);
struct machine_specific x86_64_machine_specific = { 0 };
+static const char *exception_functions_orig[];
+static const char *exception_functions_5_8[];
+
/*
* Do all necessary machine-specific setup here. This is called several
* times during initialization.
@@ -735,6 +738,12 @@ x86_64_init(int when)
STRUCT_SIZE_INIT(percpu_data, "percpu_data");
GART_init();
+
+ if (kernel_symbol_exists("asm_exc_divide_error"))
+ machdep->machspec->exception_functions = (char **)exception_functions_5_8;
+ else
+ machdep->machspec->exception_functions = (char **)exception_functions_orig;
+
break;
case POST_VM:
@@ -1104,6 +1113,12 @@ x86_64_dump_machdep_table(ulong arg)
fprintf(fp, "%016lx\n", (ulong)ms->cpu_entry_area_end);
else
fprintf(fp, "(unused)\n");
+
+ fprintf(fp, " excpetion_functions: ");
+ if (ms->exception_functions == (char **)exception_functions_5_8)
+ fprintf(fp, "excpetion_functions_5_8\n");
+ else
+ fprintf(fp, "excpetion_functions_orig\n");
}
/*
@@ -3086,7 +3101,7 @@ text_lock_function(char *name, struct bt_info *bt, ulong locktext)
* zeroentry xen_debug do_debug
* zeroentry xen_int3 do_int3
*/
-static const char *exception_functions[] = {
+static const char *exception_functions_orig[] = {
"invalid_TSS",
"segment_not_present",
"alignment_check",
@@ -3109,6 +3124,28 @@ static const char *exception_functions[] = {
NULL,
};
+static const char *exception_functions_5_8[] = {
+ "asm_exc_invalid_tss",
+ "asm_exc_segment_not_present",
+ "asm_exc_alignment_check",
+ "asm_exc_general_protection",
+ "asm_exc_page_fault",
+ "asm_exc_divide_error",
+ "asm_exc_overflow",
+ "asm_exc_bounds",
+ "asm_exc_invalid_op",
+ "asm_exc_device_not_available",
+ "asm_exc_coproc_segment_overrun",
+ "asm_exc_spurious_interrupt_bug",
+ "asm_exc_coprocessor_error",
+ "asm_exc_simd_coprocessor_error",
+ "asm_exc_debug",
+ "xen_asm_exc_stack_segment",
+ "xen_asm_exc_xen_hypervisor_callback",
+ "xen_asm_exc_int3",
+ NULL,
+};
+
/*
* print one entry of a stack trace
*/
@@ -3185,8 +3222,8 @@ x86_64_print_stack_entry(struct bt_info *bt, FILE *ofp, int level,
if ((THIS_KERNEL_VERSION >= LINUX(2,6,29)) &&
(eframe_check == -1) && offset &&
!(bt->flags & (BT_EXCEPTION_FRAME|BT_START|BT_SCHEDULE))) {
- for (i = 0; exception_functions[i]; i++) {
- if (STREQ(name, exception_functions[i])) {
+ for (i = 0; machdep->machspec->exception_functions[i]; i++) {
+ if (STREQ(name, machdep->machspec->exception_functions[i])) {
eframe_check = 8;
break;
}
--
1.8.3.1
3 years, 8 months
[PATCH 1/2] Change functions in extensions/echo.c to be static
by Tao Liu
If a same extension(Eg: extensions/trace.so) with two different names are loaded by
"extend" command twice, it sometimes segfaults crash.
It's because crash uses RTLD_NOW|RTLD_GLOBAL flags of dlopen to load an extension.
RTDL_GLOBAL will make symbols defined by this shared object available for
symbol resolution of subsequently loaded shared objects. So symbols in subsequently
loaded extensions are overwritten by the former loaded one with a same name.
Not only can it cause segfaults, but some other unexpected behaviours.
This patch changes functions within extensions/echo.c to be static, and documents
the issue in code comments, for extensions developers who takes echo.c as reference.
Signed-off-by: Tao Liu <ltao(a)redhat.com>
---
extensions/echo.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/extensions/echo.c b/extensions/echo.c
index ff1e09a..f4bb88f 100644
--- a/extensions/echo.c
+++ b/extensions/echo.c
@@ -17,19 +17,25 @@
#include "defs.h" /* From the crash source top-level directory */
-void echo_init(void); /* constructor function */
-void echo_fini(void); /* destructor function (optional) */
+static void echo_init(void); /* constructor function */
+static void echo_fini(void); /* destructor function (optional) */
-void cmd_echo(void); /* Declare the commands and their help data. */
-char *help_echo[];
+static void cmd_echo(void); /* Declare the commands and their help data. */
+static char *help_echo[];
+/*
+ * Please making the functions and global variables static within your
+ * extension if you don't want to make them visiable to subsequently
+ * loaded extensions. Otherwise, non-static symbols within 2 extensions and
+ * have a same name can cause confliction.
+ */
static struct command_table_entry command_table[] = {
{ "echo", cmd_echo, help_echo, 0}, /* One or more commands, */
{ NULL }, /* terminated by NULL, */
};
-void __attribute__((constructor))
+static void __attribute__((constructor))
echo_init(void) /* Register the command set. */
{
register_extension(command_table);
@@ -39,7 +45,7 @@ echo_init(void) /* Register the command set. */
* This function is called if the shared object is unloaded.
* If desired, perform any cleanups here.
*/
-void __attribute__((destructor))
+static void __attribute__((destructor))
echo_fini(void) { }
@@ -49,7 +55,7 @@ echo_fini(void) { }
* other crash commands for usage of the myriad of utility routines available
* to accomplish what your task.
*/
-void
+static void
cmd_echo(void)
{
int c;
@@ -94,7 +100,7 @@ cmd_echo(void)
*
*/
-char *help_echo[] = {
+static char *help_echo[] = {
"echo", /* command name */
"echoes back its arguments", /* short description */
"arg ...", /* argument synopsis, or " " if none */
--
2.29.2
3 years, 8 months
[PATCH] x86_64: Add Linux 5.8+ exception functions to check exception frame
by HAGIO KAZUHITO(萩尾 一仁)
Fix for 'bt' command and options on Linux 5.8-rc1 or later kernels
that contain merge commit 076f14be7fc942e112c94c841baec44124275cd0.
The merged patches changed the name of exception functions that
have been used by the crash utility to check the exception frame.
Without the patch, the command and options cannot display it.
Before:
crash> bt
PID: 8752 TASK: ffff8f80cb244380 CPU: 2 COMMAND: "insmod"
#0 [ffffa3e40187f9f8] machine_kexec at ffffffffab25d267
#1 [ffffa3e40187fa48] __crash_kexec at ffffffffab38e2ed
#2 [ffffa3e40187fb10] crash_kexec at ffffffffab38f1dd
#3 [ffffa3e40187fb28] oops_end at ffffffffab222cbd
#4 [ffffa3e40187fb48] do_trap at ffffffffab21fea1
#5 [ffffa3e40187fb90] do_error_trap at ffffffffab21ff75
#6 [ffffa3e40187fbd0] exc_invalid_op at ffffffffabb76a2c
#7 [ffffa3e40187fbf0] asm_exc_invalid_op at ffffffffabc00a72
#8 [ffffa3e40187fc78] init_module at ffffffffc042b018 [invalid]
#9 [ffffa3e40187fca0] init_module at ffffffffc042b018 [invalid]
#10 [ffffa3e40187fca8] do_one_initcall at ffffffffab202806
#11 [ffffa3e40187fd18] do_init_module at ffffffffab3888ba
#12 [ffffa3e40187fd38] load_module at ffffffffab38afde
After:
crash> bt
PID: 8752 TASK: ffff8f80cb244380 CPU: 2 COMMAND: "insmod"
#0 [ffffa3e40187f9f8] machine_kexec at ffffffffab25d267
#1 [ffffa3e40187fa48] __crash_kexec at ffffffffab38e2ed
#2 [ffffa3e40187fb10] crash_kexec at ffffffffab38f1dd
#3 [ffffa3e40187fb28] oops_end at ffffffffab222cbd
#4 [ffffa3e40187fb48] do_trap at ffffffffab21fea1
#5 [ffffa3e40187fb90] do_error_trap at ffffffffab21ff75
#6 [ffffa3e40187fbd0] exc_invalid_op at ffffffffabb76a2c
#7 [ffffa3e40187fbf0] asm_exc_invalid_op at ffffffffabc00a72
[exception RIP: init_module+24]
RIP: ffffffffc042b018 RSP: ffffa3e40187fca8 RFLAGS: 00010246
RAX: 000000000000001c RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffff8f80fbd18000 RDI: ffff8f80fbd18000
RBP: ffffffffc042b000 R8: 000000000000029d R9: 000000000000002c
R10: 0000000000000000 R11: ffffa3e40187fb58 R12: ffffffffc042d018
R13: ffffa3e40187fdf0 R14: ffffffffc042d000 R15: ffffa3e40187fe90
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#8 [ffffa3e40187fca0] init_module at ffffffffc042b018 [invalid]
#9 [ffffa3e40187fca8] do_one_initcall at ffffffffab202806
#10 [ffffa3e40187fd18] do_init_module at ffffffffab3888ba
#11 [ffffa3e40187fd38] load_module at ffffffffab38afde
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
defs.h | 1 +
x86_64.c | 43 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/defs.h b/defs.h
index c29b3fa..f9c711c 100644
--- a/defs.h
+++ b/defs.h
@@ -6026,6 +6026,7 @@ struct machine_specific {
ulong cpu_entry_area_start;
ulong cpu_entry_area_end;
ulong page_offset_force;
+ char **exception_functions;
};
#define KSYMS_START (0x1)
diff --git a/x86_64.c b/x86_64.c
index f5b2f7b..3f4a969 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -139,6 +139,9 @@ static void orc_dump(ulong);
struct machine_specific x86_64_machine_specific = { 0 };
+static const char *exception_functions_orig[];
+static const char *exception_functions_5_8[];
+
/*
* Do all necessary machine-specific setup here. This is called several
* times during initialization.
@@ -735,6 +738,12 @@ x86_64_init(int when)
STRUCT_SIZE_INIT(percpu_data, "percpu_data");
GART_init();
+
+ if (kernel_symbol_exists("asm_exc_divide_error"))
+ machdep->machspec->exception_functions = (char **)exception_functions_5_8;
+ else
+ machdep->machspec->exception_functions = (char **)exception_functions_orig;
+
break;
case POST_VM:
@@ -1104,6 +1113,12 @@ x86_64_dump_machdep_table(ulong arg)
fprintf(fp, "%016lx\n", (ulong)ms->cpu_entry_area_end);
else
fprintf(fp, "(unused)\n");
+
+ fprintf(fp, " excpetion_functions: ");
+ if (ms->exception_functions == (char **)exception_functions_5_8)
+ fprintf(fp, "excpetion_functions_5_8\n");
+ else
+ fprintf(fp, "excpetion_functions_orig\n");
}
/*
@@ -3086,7 +3101,7 @@ text_lock_function(char *name, struct bt_info *bt, ulong locktext)
* zeroentry xen_debug do_debug
* zeroentry xen_int3 do_int3
*/
-static const char *exception_functions[] = {
+static const char *exception_functions_orig[] = {
"invalid_TSS",
"segment_not_present",
"alignment_check",
@@ -3109,6 +3124,28 @@ static const char *exception_functions[] = {
NULL,
};
+static const char *exception_functions_5_8[] = {
+ "asm_exc_invalid_tss",
+ "asm_exc_segment_not_present",
+ "asm_exc_alignment_check",
+ "asm_exc_general_protection",
+ "asm_exc_page_fault",
+ "asm_exc_divide_error",
+ "asm_exc_overflow",
+ "asm_exc_bounds",
+ "asm_exc_invalid_op",
+ "asm_exc_device_not_available",
+ "asm_exc_coproc_segment_overrun",
+ "asm_exc_spurious_interrupt_bug",
+ "asm_exc_coprocessor_error",
+ "asm_exc_simd_coprocessor_error",
+ "xen_asm_exc_stack_segment",
+ "xen_asm_exc_xen_hypervisor_callback",
+ "xen_asm_exc_debug"
+ "xen_asm_exc_int3"
+ NULL,
+};
+
/*
* print one entry of a stack trace
*/
@@ -3185,8 +3222,8 @@ x86_64_print_stack_entry(struct bt_info *bt, FILE *ofp, int level,
if ((THIS_KERNEL_VERSION >= LINUX(2,6,29)) &&
(eframe_check == -1) && offset &&
!(bt->flags & (BT_EXCEPTION_FRAME|BT_START|BT_SCHEDULE))) {
- for (i = 0; exception_functions[i]; i++) {
- if (STREQ(name, exception_functions[i])) {
+ for (i = 0; machdep->machspec->exception_functions[i]; i++) {
+ if (STREQ(name, machdep->machspec->exception_functions[i])) {
eframe_check = 8;
break;
}
3 years, 8 months
[PATCHv2 1/2] crash-utility/arm64: rename ARM64_PAGE_OFFSET_ACTUAL as ARM64_FLIP_PAGE_OFFSET_ACTUAL
by Pingfan Liu
Renaming, so it is better to reflect the flip layout of kernel VA, which
is introduced by kernel commit 14c127c957c1 ("arm64: mm: Flip kernel VA space")
Signed-off-by: Pingfan Liu <piliu(a)redhat.com>
Cc: HAGIO KAZUHITO <k-hagio-ab(a)nec.com>
Cc: Lianbo Jiang <lijiang(a)redhat.com>
Cc: Bhupesh Sharma <bhupesh.sharma(a)linaro.org>
Cc: Mark Salter <msalter(a)redhat.com>
Cc: Mark Langsdorf <mlangsdo(a)redhat.com>
Cc: Jeremy Linton <jlinton(a)redhat.com>
To: crash-utility(a)redhat.com
---
v1->v2: referrence to kernel version instead of commit id in notes
arm64.c | 8 ++++----
defs.h | 3 ++-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/arm64.c b/arm64.c
index 5e567ca..db36d98 100644
--- a/arm64.c
+++ b/arm64.c
@@ -221,9 +221,9 @@ arm64_init(int when)
arm64_calc_KERNELPACMASK();
ms = machdep->machspec;
if (ms->VA_BITS_ACTUAL) {
- ms->page_offset = ARM64_PAGE_OFFSET_ACTUAL;
- machdep->identity_map_base = ARM64_PAGE_OFFSET_ACTUAL;
- machdep->kvbase = ARM64_PAGE_OFFSET_ACTUAL;
+ ms->page_offset = ARM64_FLIP_PAGE_OFFSET_ACTUAL;
+ machdep->identity_map_base = ARM64_FLIP_PAGE_OFFSET_ACTUAL;
+ machdep->kvbase = ARM64_FLIP_PAGE_OFFSET_ACTUAL;
ms->userspace_top = ARM64_USERSPACE_TOP_ACTUAL;
} else {
ms->page_offset = ARM64_PAGE_OFFSET;
@@ -404,7 +404,7 @@ arm64_init(int when)
fprintf(fp, "CONFIG_ARM64_VA_BITS: %ld\n", ms->CONFIG_ARM64_VA_BITS);
fprintf(fp, " VA_BITS_ACTUAL: %ld\n", ms->VA_BITS_ACTUAL);
fprintf(fp, "(calculated) VA_BITS: %ld\n", ms->VA_BITS);
- fprintf(fp, " PAGE_OFFSET: %lx\n", ARM64_PAGE_OFFSET_ACTUAL);
+ fprintf(fp, " PAGE_OFFSET: %lx\n", ARM64_FLIP_PAGE_OFFSET_ACTUAL);
fprintf(fp, " VA_START: %lx\n", ms->VA_START);
fprintf(fp, " modules: %lx - %lx\n", ms->modules_vaddr, ms->modules_end);
fprintf(fp, " vmalloc: %lx - %lx\n", ms->vmalloc_start_addr, ms->vmalloc_end);
diff --git a/defs.h b/defs.h
index 09d58e0..812f02f 100644
--- a/defs.h
+++ b/defs.h
@@ -3219,7 +3219,8 @@ typedef signed int s32;
#define ARM64_PAGE_OFFSET ((0xffffffffffffffffUL) \
<< (machdep->machspec->VA_BITS - 1))
-#define ARM64_PAGE_OFFSET_ACTUAL ((0xffffffffffffffffUL) \
+/* kernels > v5.4 the kernel VA space is flipped */
+#define ARM64_FLIP_PAGE_OFFSET_ACTUAL ((0xffffffffffffffffUL) \
- ((1UL) << machdep->machspec->VA_BITS_ACTUAL) + 1)
#define ARM64_USERSPACE_TOP ((1UL) << machdep->machspec->VA_BITS)
--
2.29.2
3 years, 8 months
[PATCH] symbol: fix offset print for function pointers that return pointers
by John Pittman
In the show_member_offset() function, when trying to handle function
pointers, the case for "(*" is handled. However, if the function
pointer returns a pointer or a pointer to a pointer, then the
condition is unhandled. This results in the offset not being printed.
Fix by first checking if the member is potentially a function pointer,
then checking if it returns a pointer or a pointer to a pointer.
Signed-off-by: John Pittman <jpittman(a)redhat.com>
---
symbols.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/symbols.c b/symbols.c
index a2d5c6c..5d7da6e 100644
--- a/symbols.c
+++ b/symbols.c
@@ -8356,8 +8356,15 @@ show_member_offset(FILE *ofp, struct datatype_member *dm, char *inbuf)
}
} else if (c) {
for (i = 0; i < c; i++) {
- if (STRNEQ(arglist[i], "(*")) {
- target = arglist[i]+2;
+ if (strstr(inbuf, "(*")) {
+ if (STRNEQ(arglist[i], "(*"))
+ target = arglist[i]+2;
+ else if (STRNEQ(arglist[i], "*(*"))
+ target = arglist[i]+3;
+ else if (STRNEQ(arglist[i], "**(*"))
+ target = arglist[i]+4;
+ else
+ continue;
if (!(t1 = strstr(target, ")")))
continue;
*t1 = NULLCHAR;
--
2.17.2
3 years, 8 months
[PATCH] arm64: handle 1GB block
by Johan.Erlandsson@sony.com
With enough continuous physical memory we can have 1GB block. This have
been seen only in linear mapping region in kernel space. I have only
verified this for VM_L3_4K.
reference: alloc_init_pud(), use_1G_block() [arch/arm64/mm/mmu.c]
This problem can for instance be seen with vtop command, example:
crash> vtop ffffffd988008000
VIRTUAL PHYSICAL
ffffffd988008000 148008000
PAGE DIRECTORY: ffffff9188c6c000
PGD: ffffff9188c6cb30 => 68000140000711
PMD: ffffffd980000200 => aa0003e2b9402fe1
PAGE: 3e2b9400000 (2MB)
PTE PHYSICAL FLAGS
aa0003e2b9402fe1 3e2b9402000 (VALID|USER|RDONLY|SHARED|AF|NG)
---
arm64.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arm64.c b/arm64.c
index 37aed07..4787fa6 100644
--- a/arm64.c
+++ b/arm64.c
@@ -1260,11 +1260,14 @@ arm64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbos
#define PTE_TO_PHYS(pteval) (machdep->max_physmem_bits == 52 ? \
(((pteval & PTE_ADDR_LOW) | ((pteval & PTE_ADDR_HIGH) << 36))) : (pteval & PTE_ADDR_LOW))
+#define PUD_TYPE_MASK 3
+#define PUD_TYPE_SECT 1
#define PMD_TYPE_MASK 3
#define PMD_TYPE_SECT 1
#define PMD_TYPE_TABLE 2
#define SECTION_PAGE_MASK_2MB ((long)(~((MEGABYTES(2))-1)))
#define SECTION_PAGE_MASK_512MB ((long)(~((MEGABYTES(512))-1)))
+#define SECTION_PAGE_MASK_1GB ((long)(~((GIGABYTES(1))-1)))
static int
arm64_vtop_2level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose)
@@ -1420,6 +1423,15 @@ arm64_vtop_3level_4k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose)
if (!pgd_val)
goto no_page;
+ if ((pgd_val & PUD_TYPE_MASK) == PUD_TYPE_SECT) {
+ ulong sectionbase = (pgd_val & SECTION_PAGE_MASK_1GB) & PHYS_MASK;
+ if (verbose) {
+ fprintf(fp, " PAGE: %lx (1GB)\n\n", sectionbase);
+ arm64_translate_pte(pgd_val, 0, 0);
+ }
+ *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_1GB);
+ return TRUE;
+ }
/*
* #define __PAGETABLE_PUD_FOLDED
*/
--
2.17.1
3 years, 8 months
[PATCH] GDB: fix the failure of 'set scope' command
by Lianbo Jiang
Currently, some command such as 'sys' may cause subsequent 'set scope'
commands to fail because it may not find the correct symtab associated
with PC and SECTION in the find_pc_sect_symtab(), eventually, this will
cause the following failure:
crash> mod -S 3.10.0-957.el7.x86_64
crash> mod -s dm_service_time
crash> set scope st_create
set: gdb cannot find text block for address: st_create
crash> mod -d dm_service_time
crash> mod -sr dm_service_time
crash> set scope st_create
scope: ffffffffc044d270 (st_create)
crash> sys
KERNEL: 3.10.0-957.el7.x86_64/vmlinux
DUMPFILE: crash/vmcore [PARTIAL DUMP]
CPUS: 48
DATE: Sat Aug 3 11:41:00 EDT 2019
UPTIME: 1 days, 10:28:48
LOAD AVERAGE: 2.95, 1.02, 0.40
TASKS: 1060
NODENAME: iop053063.lss.emc.com
RELEASE: 3.10.0-957.el7.x86_64
VERSION: #1 SMP Thu Oct 4 20:48:51 UTC 2018
MACHINE: x86_64 (2999 Mhz)
MEMORY: 127.9 GB
PANIC: "SysRq : Trigger a crash"
crash> set scope st_create
set: gdb cannot find text block for address: st_create
To find the correct symtab, let's check whether there is an address
mapping to 'block' in the symtab searching loop and the PC is in the
range. If the symtab associated with PC is found, and then use it.
Signed-off-by: Lianbo Jiang <lijiang(a)redhat.com>
---
gdb-7.6.patch | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/gdb-7.6.patch b/gdb-7.6.patch
index f64b55fe547a..90629889f8c4 100644
--- a/gdb-7.6.patch
+++ b/gdb-7.6.patch
@@ -2500,4 +2500,40 @@ diff -up gdb-7.6/opcodes/configure.orig gdb-7.6/opcodes/configure
+struct target_desc *tdesc_aarch64;
#include "features/aarch64.c"
#include "features/aarch64-without-fpu.c"
-
+
+--- gdb-7.6/gdb/symtab.c.orig
++++ gdb-7.6/gdb/symtab.c
+@@ -2065,7 +2065,7 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
+ struct symtab *s = NULL;
+ struct symtab *best_s = NULL;
+ struct objfile *objfile;
+- CORE_ADDR distance = 0;
++ CORE_ADDR distance = 0, start, end;
+ struct minimal_symbol *msymbol;
+
+ /* If we know that this is not a text address, return failure. This is
+@@ -2102,10 +2102,20 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+
+- if (BLOCK_START (b) <= pc
+- && BLOCK_END (b) > pc
+- && (distance == 0
+- || BLOCK_END (b) - BLOCK_START (b) < distance))
++ start = BLOCK_START (b);
++ end = BLOCK_END (b);
++
++ /*
++ * If we have an addrmap mapping code addresses to blocks, and pc
++ * is in the range [start, end), let's use it.
++ */
++ if ((pc >= start && pc < end) && BLOCKVECTOR_MAP (bv)) {
++ if (addrmap_find (BLOCKVECTOR_MAP (bv), pc))
++ return s;
++ }
++
++ if ((pc >= start && pc < end) && ((distance == 0)
++ || (end - start < distance)))
+ {
+ /* For an objfile that has its functions reordered,
+ find_pc_psymtab will find the proper partial symbol table
--
2.17.1
3 years, 8 months