FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Crash Utility

 
 
LinkBack Thread Tools
 
Old 05-09-2011, 08:16 AM
Wang Chao
 
Default Use register value in elf note NT_PRSTATUS to do backtrace

Hi Dave and all,

Sent on 2011-5-7 0:11, Dave Anderson wrote:

>> 2) Dump notes related information including total number of notes, their
>> buffers' pointer value and finally offset in the dump file.
>> 3) Move nt_prstatus_percpu and nt_prstatus_percpu to diskdump_data struct.
>> However, bt command may need sp/ip from the notes later, so I guess
>> the buffer should not be freed after diskdump_read_header().
>
> I wish I had understood the s390x implementation a bit better when I
> reviewed your v2 patch. Currently read_dump_header() malloc's a
> single "notes_buf" buffer and copies the complete ELF notes section
> from the dumpfile into it. I believe (but am not completely sure) that
> the s390x code references pieces of that buffer, and that's why they
> originally kept the "notes_buf" buffer permanently allocated. That
> being the case, the "notes_buf" pointer should be moved to the
> diskdump header.
>
> Anyway, in the case of x86/x86_64, your patch:
>
> (1) malloc's dd->nt_prstatus_percpu as an array of pointers,
> (2) malloc's a bunch of individual per-cpu ELF prstatus buffers, and
> then copies the ELF data from the "notes_buf" buffer into
> each per-cpu buffer.
> (4) puts a pointer to each per-cpu buffer into each dd->nt_prstatus_percpu
> pointer.
>
> But given that the original "notes_buf" buffer is permanent, your patch
> should only have to store per-cpu pointers into the original note_buf
> buffer -- rather than redundantly malloc'ing a bunch of new buffers that
> contain copies of what's already permanently available. So I would suggest
> setting it up like this:
>
> dd->nt_prstatus_percpu[cpu] => points into relevant "notes_buf" location
>

Oh, sorry for my misunderstood.

Since we will later refer to ip/sp value in the notes_buf, we should keep the
notes_buf permanently and do not free them at the end of read_diskdump_header.
s390x don't have such problem because the notes are copied to the s390x_cpu_vec
when processing notes_buf.

So just as what you suggested, notes_buf was moved to diskdump header in the
attached v4 patch and nt_prstatus_percpu will store the address in notes_buf then.

Thanks,
Wang Chao
>From 07c17423d32d48e4a9397fc400d92105e44dd256 Mon Sep 17 00:00:00 2001
From: Wang Chao <wang.chao@cn.fujitsu.com>
Date: Mon, 18 Apr 2011 13:06:15 +0800
Subject: [PATCH] Use register value in elf note NT_PRSTATUS to do backtrace

We have a new hardware to do dump, and use makedumpfile to generate
vmcore. Our hardware can work when the OS is out of controll(for
example: dead loop). When we use crash to analyze the vmcore, bt can
not work, because there is no panic task.

We have provide the value of register in the vmcore(the format is
elf_prstatus, it is same with normal kdump's vmcore). So we can use
it when we do not find panic task.

Based on previous patch from wency@cn.fujitsu.com
---
defs.h | 7 +++
diskdump.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++---
main.c | 10 ++++
netdump.c | 79 +++++++++++++++++++++++++++++++
symbols.c | 2 +
task.c | 2 +
x86.c | 11 ++++
x86_64.c | 9 ++++
8 files changed, 265 insertions(+), 8 deletions(-)

diff --git a/defs.h b/defs.h
index d01ace7..890188c 100755
--- a/defs.h
+++ b/defs.h
@@ -242,6 +242,7 @@ struct number_option {
#define ERROR_EXCLUDED (0x4)
#define ZERO_EXCLUDED (0x8)
#define DUMPFILE_SPLIT (0x10)
+#define NO_ELF_NOTES (0x20)
#define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL)
#define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL)
#define KDUMP_SPLIT() (dd->flags & DUMPFILE_SPLIT)
@@ -428,7 +429,9 @@ struct program_context {
char *kvmdump_mapfile; /* storage of physical to file offsets */
ulonglong flags2; /* flags overrun */
#define FLAT (0x1ULL)
+#define ELF_NOTES (0x2ULL)
#define FLAT_FORMAT() (pc->flags2 & FLAT)
+#define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES)
char *cleanup;
char *namelist_orig;
char *namelist_debug_orig;
@@ -1570,6 +1573,7 @@ struct offset_table { /* stash of commonly-used offsets */
long module_init_size;
long module_percpu;
long radix_tree_node_slots;
+ long user_regs_struct_eip;
};

struct size_table { /* stash of commonly-used sizes */
@@ -4604,6 +4608,9 @@ ulong *diskdump_flags;
int is_partial_diskdump(void);
int dumpfile_is_split(void);
void show_split_dumpfiles(void);
+void x86_process_elf_notes(void *, unsigned long);
+void *diskdump_get_prstatus_percpu(int);
+void map_cpus_to_prstatus_kdump_cmprs(void);

/*
* makedumpfile.c
diff --git a/diskdump.c b/diskdump.c
index 9a2f37f..ee4e513 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -49,6 +49,9 @@ struct diskdump_data {
int byte, bit;
char *compressed_page; /* copy of compressed page data */
char *curbufptr; /* ptr to uncompressed page buffer */
+ unsigned char *notes_buf; /* copy of elf notes */
+ void **nt_prstatus_percpu;
+ uint num_prstatus_notes;

/* page cache */
struct page_cache_hdr { /* header for each cached page */
@@ -73,6 +76,7 @@ ulong *diskdump_flags = &diskdump_data.flags;

static int __diskdump_memory_dump(FILE *);
static void dump_vmcoreinfo(FILE *);
+static void dump_nt_prstatus_offset(FILE *);

/* For split dumpfile */
static struct diskdump_data **dd_list = NULL;
@@ -84,6 +88,40 @@ int dumpfile_is_split(void)
return KDUMP_SPLIT();
}

+void
+map_cpus_to_prstatus_kdump_cmprs(void)
+{
+ void **nt_ptr;
+ int online, i, j, nrcpus;
+ size_t size;
+
+ if (!(online = get_cpus_online()) || (online == kt->cpus))
+ return;
+
+ if (CRASHDEBUG(1))
+ error(INFO,
+ "cpus: %d online: %d NT_PRSTATUS notes: %d (remapping)
",
+ kt->cpus, online, dd->num_prstatus_notes);
+
+ size = NR_CPUS * sizeof(void *);
+
+ nt_ptr = (void **)GETBUF(size);
+ BCOPY(dd->nt_prstatus_percpu, nt_ptr, size);
+ BZERO(dd->nt_prstatus_percpu, size);
+
+ /*
+ * Re-populate the array with the notes mapping to online cpus
+ */
+ nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS);
+
+ for (i = 0, j = 0; i < nrcpus; i++) {
+ if (in_cpu_map(ONLINE, i))
+ dd->nt_prstatus_percpu[i] = nt_ptr[j++];
+ }
+
+ FREEBUF(nt_ptr);
+}
+
static void add_diskdump_data(char* name)
{
#define DDL_SIZE 16
@@ -185,12 +223,50 @@ static int open_dump_file(char *file)
return TRUE;
}

+void x86_process_elf_notes(void *note_ptr, unsigned long size_note)
+{
+ Elf32_Nhdr *note32 = NULL;
+ Elf64_Nhdr *note64 = NULL;
+ size_t tot, len = 0;
+ int num = 0;
+
+ for (tot = 0; tot < size_note; tot += len) {
+ if (machine_type("X86_64")) {
+ note64 = note_ptr + tot;
+
+ if (note64->n_type == NT_PRSTATUS) {
+ dd->nt_prstatus_percpu[num] = note64;
+ num++;
+ }
+
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note64->n_namesz, 4);
+ len = roundup(len + note64->n_descsz, 4);
+ } else if (machine_type("X86")) {
+ note32 = note_ptr + tot;
+
+ if (note32->n_type == NT_PRSTATUS) {
+ dd->nt_prstatus_percpu[num] = note32;
+ num++;
+ }
+
+ len = sizeof(Elf32_Nhdr);
+ len = roundup(len + note32->n_namesz, 4);
+ len = roundup(len + note32->n_descsz, 4);
+ }
+ }
+
+ if (num > 0) {
+ pc->flags2 |= ELF_NOTES;
+ dd->num_prstatus_notes = num;
+ }
+}
+
static int read_dump_header(char *file)
{
struct disk_dump_header *header = NULL;
struct disk_dump_sub_header *sub_header = NULL;
struct kdump_sub_header *sub_header_kdump = NULL;
- unsigned char *notes_buf = NULL;
size_t size;
int bitmap_len;
int block_size = (int)sysconf(_SC_PAGESIZE);
@@ -392,18 +468,23 @@ restart:
}

/* process elf notes data */
- if (KDUMP_CMPRS_VALID() && (dd->header->header_version >= 4) &&
+ if (KDUMP_CMPRS_VALID() && !(dd->flags & NO_ELF_NOTES) &&
+ (dd->header->header_version >= 4) &&
(sub_header_kdump->offset_note) &&
(sub_header_kdump->size_note) && (machdep->process_elf_notes)) {
size = sub_header_kdump->size_note;
offset = sub_header_kdump->offset_note;

- if ((notes_buf = malloc(size)) == NULL)
+ if ((dd->notes_buf = malloc(size)) == NULL)
error(FATAL, "compressed kdump: cannot malloc notes"
" buffer
");

+ if ((dd->nt_prstatus_percpu = malloc(NR_CPUS * sizeof(void*))) == NULL)
+ error(FATAL, "compressed kdump: cannot malloc pointer"
+ " to NT_PRSTATUS notes
");
+
if (FLAT_FORMAT()) {
- if (!read_flattened_format(dd->dfd, offset, notes_buf, size)) {
+ if (!read_flattened_format(dd->dfd, offset, dd->notes_buf, size)) {
error(INFO, "compressed kdump: cannot read notes data"
"
");
goto err;
@@ -413,14 +494,14 @@ restart:
error(INFO, "compressed kdump: cannot lseek notes data
");
goto err;
}
- if (read(dd->dfd, notes_buf, size) < size) {
+ if (read(dd->dfd, dd->notes_buf, size) < size) {
error(INFO, "compressed kdump: cannot read notes data"
"
");
goto err;
}
}

- machdep->process_elf_notes(notes_buf, size);
+ machdep->process_elf_notes(dd->notes_buf, size);
}

/* For split dumpfile */
@@ -468,8 +549,6 @@ err:
free(sub_header);
if (sub_header_kdump)
free(sub_header_kdump);
- if (notes_buf)
- free(notes_buf);
if (dd->bitmap)
free(dd->bitmap);
if (dd->dumpable_bitmap)
@@ -913,6 +992,50 @@ err:
return;
}

+static void dump_nt_prstatus_offset(FILE *fp)
+{
+ struct kdump_sub_header *sub_header_kdump = dd->sub_header_kdump;
+ size_t size;
+ off_t offset;
+ Elf32_Nhdr *note32 = NULL;
+ Elf64_Nhdr *note64 = NULL;
+ size_t tot, len = 0;
+
+ if (KDUMP_CMPRS_VALID() && !(dd->flags & NO_ELF_NOTES) &&
+ (dd->header->header_version >= 4) &&
+ (sub_header_kdump->offset_note) &&
+ (sub_header_kdump->size_note) && (machdep->process_elf_notes)) {
+ size = sub_header_kdump->size_note;
+ offset = sub_header_kdump->offset_note;
+
+ fprintf(fp, " NT_PRSTATUS_offset: ");
+ for (tot = 0; tot < size; tot += len) {
+ if (machine_type("X86_64") || machine_type("S390X")) {
+ note64 = (void *)dd->notes_buf + tot;
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note64->n_namesz, 4);
+ len = roundup(len + note64->n_descsz, 4);
+
+ if (note64->n_type == NT_PRSTATUS)
+ fprintf(fp, "%s%lx
",
+ (tot == 0) ? "" : " ",
+ (ulong)(offset + tot));
+
+ } else if (machine_type("X86")) {
+ note32 = (void *)dd->notes_buf + tot;
+ len = sizeof(Elf32_Nhdr);
+ len = roundup(len + note32->n_namesz, 4);
+ len = roundup(len + note32->n_descsz, 4);
+
+ if (note32->n_type == NT_PRSTATUS)
+ fprintf(fp, "%s%lx
",
+ (tot == 0) ? "" : " ",
+ (ulong)(offset + tot));
+ }
+ }
+ }
+}
+
/*
* This function is dump-type independent, and could be used
* to dump the diskdump_data structure contents and perhaps
@@ -942,6 +1065,8 @@ __diskdump_memory_dump(FILE *fp)
fprintf(fp, "%sERROR_EXCLUDED", others++ ? "|" : "");
if (dd->flags & ZERO_EXCLUDED)
fprintf(fp, "%sZERO_EXCLUDED", others++ ? "|" : "");
+ if (dd->flags & NO_ELF_NOTES)
+ fprintf(fp, "%sNO_ELF_NOTES", others++ ? "|" : "");
fprintf(fp, ") %s
", FLAT_FORMAT() ? "[FLAT]" : "");
fprintf(fp, " dfd: %d
", dd->dfd);
fprintf(fp, " ofp: %lx
", (ulong)dd->ofp);
@@ -1101,6 +1226,13 @@ __diskdump_memory_dump(FILE *fp)
(ulong)dd->sub_header_kdump->offset_note);
fprintf(fp, " size_note: %lu
",
dd->sub_header_kdump->size_note);
+ fprintf(fp, " num_prstatus_notes: %d
",
+ dd->num_prstatus_notes);
+ for (i = 0; i < dd->num_prstatus_notes; i++) {
+ fprintf(fp, " notes[%d]: %lx
",
+ i, (ulong)dd->nt_prstatus_percpu[i]);
+ }
+ dump_nt_prstatus_offset(fp);
}
fprintf(fp, "
");
} else
@@ -1226,3 +1358,8 @@ show_split_dumpfiles(void)
fprintf(fp, "
");
}
}
+
+void *diskdump_get_prstatus_percpu(int cpu)
+{
+ return dd->nt_prstatus_percpu[cpu];
+}
diff --git a/main.c b/main.c
index 8c30fed..6b84523 100755
--- a/main.c
+++ b/main.c
@@ -62,6 +62,7 @@ static struct option long_options[] = {
{"mod", required_argument, 0, 0},
{"kvmhost", required_argument, 0, 0},
{"kvmio", required_argument, 0, 0},
+ {"no_elf_notes", 0, 0, 0},
{0, 0, 0, 0}
};

@@ -177,6 +178,15 @@ main(int argc, char **argv)
else if (STREQ(long_options[option_index].name, "zero_excluded"))
*diskdump_flags |= ZERO_EXCLUDED;

+ else if (STREQ(long_options[option_index].name, "no_elf_notes")) {
+ if (machine_type("X86") || machine_type("X86_64"))
+ *diskdump_flags |= NO_ELF_NOTES;
+ else
+ error(INFO,
+ "--no_elf_notes is only applicable to "
+ "the X86 and X86_64 architectures.
");
+ }
+
else if (STREQ(long_options[option_index].name, "no_panic"))
tt->flags |= PANIC_TASK_NOT_FOUND;

diff --git a/netdump.c b/netdump.c
index 7916df1..918de0f 100644
--- a/netdump.c
+++ b/netdump.c
@@ -39,6 +39,7 @@ static physaddr_t xen_kdump_p2m(physaddr_t);
static void check_dumpfile_size(char *);
static int proc_kcore_init_32(FILE *fp);
static int proc_kcore_init_64(FILE *fp);
+static char * get_regs_from_note(char *, ulong *, ulong *);

#define ELFSTORE 1
#define ELFREAD 0
@@ -2170,6 +2171,39 @@ get_netdump_regs(struct bt_info *bt, ulong *eip, ulong *esp)
}
}

+/* get regs from elf note, and return the address of user_regs. */
+static char * get_regs_from_note(char *note, ulong *ip, ulong *sp)
+{
+ Elf32_Nhdr *note32;
+ Elf64_Nhdr *note64;
+ size_t len;
+ char *user_regs;
+ long offset_sp, offset_ip;
+
+ if (machine_type("X86_64")) {
+ note64 = (Elf64_Nhdr *)note;
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note64->n_namesz, 4);
+ len = roundup(len + note64->n_descsz, 4);
+ offset_sp = OFFSET(user_regs_struct_rsp);
+ offset_ip = OFFSET(user_regs_struct_rip);
+ } else if (machine_type("X86")) {
+ note32 = (Elf32_Nhdr *)note;
+ len = sizeof(Elf32_Nhdr);
+ len = roundup(len + note32->n_namesz, 4);
+ len = roundup(len + note32->n_descsz, 4);
+ offset_sp = OFFSET(user_regs_struct_esp);
+ offset_ip = OFFSET(user_regs_struct_eip);
+ } else
+ return NULL;
+
+ user_regs = note + len - SIZE(user_regs_struct) - sizeof(long);
+ *sp = ULONG(user_regs + offset_sp);
+ *ip = ULONG(user_regs + offset_ip);
+
+ return user_regs;
+}
+
struct x86_64_user_regs_struct {
unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
@@ -2186,6 +2220,7 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp)
size_t len;
char *user_regs;
ulong regs_size, rsp_offset, rip_offset;
+ ulong rip, rsp;

if (is_task_active(bt->task))
bt->flags |= BT_DUMPFILE_SEARCH;
@@ -2232,6 +2267,28 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp)
bt->machdep = (void *)user_regs;
}

+ if (ELF_NOTES_VALID() && (bt->flags & BT_DUMPFILE_SEARCH) && DISKDUMP_DUMPFILE()) {
+ note = (Elf64_Nhdr *)
+ diskdump_get_prstatus_percpu(bt->tc->processor);
+ if (note == NULL)
+ goto skip_notes;
+
+ user_regs = get_regs_from_note((char *)note, &rip, &rsp);
+
+ if (CRASHDEBUG(1))
+ netdump_print("ELF prstatus rsp: %lx rip: %lx
",
+ rsp, rip);
+
+ *rspp = rsp;
+ *ripp = rip;
+
+ if (*ripp && *rspp)
+ bt->flags |= BT_KDUMP_ELF_REGS;
+
+ bt->machdep = (void *)user_regs;
+ }
+
+skip_notes:
machdep->get_stack_frame(bt, ripp, rspp);
}

@@ -2423,6 +2480,28 @@ next_sysrq:
goto retry;
}

+ if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) {
+ Elf32_Nhdr *note;
+ char *user_regs;
+ ulong ip, sp;
+
+ note = (Elf32_Nhdr *)
+ diskdump_get_prstatus_percpu(bt->tc->processor);
+ if (note == NULL)
+ goto skip_notes;
+
+ user_regs = get_regs_from_note((char *)note, &ip, &sp);
+ if (is_kernel_text(ip) &&
+ (((sp >= GET_STACKBASE(bt->task)) &&
+ (sp < GET_STACKTOP(bt->task))) ||
+ in_alternate_stack(bt->tc->processor, sp))) {
+ *eip = ip;
+ *esp = sp;
+ return;
+ }
+ }
+
+skip_notes:
if (CRASHDEBUG(1))
error(INFO,
"get_netdump_regs_x86: cannot find anything useful (task: %lx)
", bt->task);
diff --git a/symbols.c b/symbols.c
index 29cb4b4..7e24f79 100755
--- a/symbols.c
+++ b/symbols.c
@@ -7940,6 +7940,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(prio_array_nr_active));
fprintf(fp, " user_regs_struct_ebp: %ld
",
OFFSET(user_regs_struct_ebp));
+ fprintf(fp, " user_regs_struct_eip: %ld
",
+ OFFSET(user_regs_struct_eip));
fprintf(fp, " user_regs_struct_esp: %ld
",
OFFSET(user_regs_struct_esp));
fprintf(fp, " user_regs_struct_rip: %ld
",
diff --git a/task.c b/task.c
index 266b8de..8d4d02b 100755
--- a/task.c
+++ b/task.c
@@ -458,6 +458,8 @@ task_init(void)
else {
if (KDUMP_DUMPFILE())
map_cpus_to_prstatus();
+ else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
+ map_cpus_to_prstatus_kdump_cmprs();
please_wait("determining panic task");
set_context(get_panic_context(), NO_PID);
please_wait_done();
diff --git a/x86.c b/x86.c
index c5cf010..4425ee1 100755
--- a/x86.c
+++ b/x86.c
@@ -1704,6 +1704,9 @@ x86_init(int when)

switch (when)
{
+ case SETUP_ENV:
+ machdep->process_elf_notes = x86_process_elf_notes;
+ break;
case PRE_SYMTAB:
machdep->verify_symbol = x86_verify_symbol;
if (pc->flags & KERNEL_DEBUG_QUERY)
@@ -1797,6 +1800,12 @@ x86_init(int when)
else
MEMBER_OFFSET_INIT(user_regs_struct_esp,
"user_regs_struct", "sp");
+ if (MEMBER_EXISTS("user_regs_struct", "eip"))
+ MEMBER_OFFSET_INIT(user_regs_struct_eip,
+ "user_regs_struct", "eip");
+ else
+ MEMBER_OFFSET_INIT(user_regs_struct_eip,
+ "user_regs_struct", "ip");
if (!VALID_STRUCT(user_regs_struct)) {
/* Use this hardwired version -- sometimes the
* debuginfo doesn't pick this up even though
@@ -1817,6 +1826,8 @@ x86_init(int when)
offsetof(struct x86_user_regs_struct, ebp);
ASSIGN_OFFSET(user_regs_struct_esp) =
offsetof(struct x86_user_regs_struct, esp);
+ ASSIGN_OFFSET(user_regs_struct_eip) =
+ offsetof(struct x86_user_regs_struct, eip);
}
MEMBER_OFFSET_INIT(thread_struct_cr3, "thread_struct", "cr3");
STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86");
diff --git a/x86_64.c b/x86_64.c
index eaf6373..6639cf2 100755
--- a/x86_64.c
+++ b/x86_64.c
@@ -124,6 +124,9 @@ x86_64_init(int when)

switch (when)
{
+ case SETUP_ENV:
+ machdep->process_elf_notes = x86_process_elf_notes;
+ break;
case PRE_SYMTAB:
machdep->verify_symbol = x86_64_verify_symbol;
machdep->machspec = &x86_64_machine_specific;
@@ -4043,6 +4046,12 @@ x86_64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *rip, ulong *rsp)
goto skip_stage;
}
}
+ } else if (ELF_NOTES_VALID()) {
+ user_regs = bt->machdep;
+ ur_rip = ULONG(user_regs +
+ OFFSET(user_regs_struct_rip));
+ ur_rsp = ULONG(user_regs +
+ OFFSET(user_regs_struct_rsp));
}

panic = FALSE;
--
1.7.3

--
Crash-utility mailing list
Crash-utility@redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility
 

Thread Tools




All times are GMT. The time now is 10:30 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org