diff options
author | Baoquan He <bhe@redhat.com> | 2014-09-01 12:17:47 +0900 |
---|---|---|
committer | Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp> | 2014-09-02 10:13:38 +0900 |
commit | 61087227ef4b3c698c6466a11dd06203c21f0de8 (patch) | |
tree | f1a9e5976f6533cb93b63a3ffedf16b260999c07 /elf_info.c | |
parent | b3e8ea79f283b1061c8a9aecbfcd10da9ecb8dc0 (diff) |
[PATCH v6 5/8] Prepare the dump loads for kcore analysis.
In kcore, only "System Ram" and "kernel text" program segments
are needed. And to be more precise, exclude the crashkernel
memory range.
Signed-off-by: Baoquan He <bhe@redhat.com>
Diffstat (limited to 'elf_info.c')
-rw-r--r-- | elf_info.c | 142 |
1 files changed, 142 insertions, 0 deletions
@@ -777,6 +777,148 @@ get_elf_loads(int fd, char *filename) return TRUE; } +static int exclude_segment(struct pt_load_segment **pt_loads, + unsigned int *num_pt_loads, uint64_t start, uint64_t end) +{ + int i, j, tidx = -1; + unsigned long long vstart, vend, kvstart, kvend; + struct pt_load_segment temp_seg = {0}; + kvstart = (ulong)start | PAGE_OFFSET; + kvend = (ulong)end | PAGE_OFFSET; + unsigned long size; + + for (i = 0; i < (*num_pt_loads); i++) { + vstart = (*pt_loads)[i].virt_start; + vend = (*pt_loads)[i].virt_end; + if (kvstart < vend && kvend > vstart) { + if (kvstart != vstart && kvend != vend) { + /* Split load segment */ + temp_seg.phys_start = end + 1; + temp_seg.phys_end = (*pt_loads)[i].phys_end; + temp_seg.virt_start = kvend + 1; + temp_seg.virt_end = vend; + temp_seg.file_offset = (*pt_loads)[i].file_offset + + temp_seg.virt_start - (*pt_loads)[i].virt_start; + + (*pt_loads)[i].virt_end = kvstart - 1; + (*pt_loads)[i].phys_end = start - 1; + + tidx = i+1; + } else if (kvstart != vstart) { + (*pt_loads)[i].phys_end = start - 1; + (*pt_loads)[i].virt_end = kvstart - 1; + } else { + (*pt_loads)[i].phys_start = end + 1; + (*pt_loads)[i].virt_start = kvend + 1; + } + } + } + /* Insert split load segment, if any. */ + if (tidx >= 0) { + size = (*num_pt_loads + 1) * sizeof((*pt_loads)[0]); + (*pt_loads) = realloc((*pt_loads), size); + if (!(*pt_loads)) { + ERRMSG("Cannot realloc %ld bytes: %s\n", + size + 0UL, strerror(errno)); + exit(1); + } + for (j = (*num_pt_loads - 1); j >= tidx; j--) + (*pt_loads)[j+1] = (*pt_loads)[j]; + (*pt_loads)[tidx] = temp_seg; + (*num_pt_loads)++; + } + return 0; +} + +static int +process_dump_load(struct pt_load_segment *pls) +{ + unsigned long long paddr; + + paddr = vaddr_to_paddr(pls->virt_start); + pls->phys_start = paddr; + pls->phys_end = paddr + (pls->virt_end - pls->virt_start); + DEBUG_MSG("process_dump_load\n"); + DEBUG_MSG(" phys_start : %llx\n", pls->phys_start); + DEBUG_MSG(" phys_end : %llx\n", pls->phys_end); + DEBUG_MSG(" virt_start : %llx\n", pls->virt_start); + DEBUG_MSG(" virt_end : %llx\n", pls->virt_end); + + return TRUE; +} + +int get_kcore_dump_loads(void) +{ + struct pt_load_segment *pls; + int i, j, loads = 0; + + for (i = 0; i < num_pt_loads; ++i) { + struct pt_load_segment *p = &pt_loads[i]; + if (is_vmalloc_addr(p->virt_start)) + continue; + loads++; + } + + if (!loads) { + ERRMSG("Can't get the correct number of PT_LOAD. %s\n", + strerror(errno)); + return FALSE; + } + + pls = calloc(sizeof(struct pt_load_segment), loads); + if (pls == NULL) { + ERRMSG("Can't allocate memory for the PT_LOAD. %s\n", + strerror(errno)); + return FALSE; + } + + for (i = 0, j = 0; i < num_pt_loads; ++i) { + struct pt_load_segment *p = &pt_loads[i]; + if (is_vmalloc_addr(p->virt_start)) + continue; + if (j >= loads) + return FALSE; + + if (j == 0) { + offset_pt_load_memory = p->file_offset; + if (offset_pt_load_memory == 0) { + ERRMSG("Can't get the offset of page data.\n"); + return FALSE; + } + } + + pls[j] = *p; + process_dump_load(&pls[j]); + j++; + } + + free(pt_loads); + pt_loads = pls; + num_pt_loads = loads; + + for (i = 0; i < crash_reserved_mem_nr; i++) { + exclude_segment(&pt_loads, &num_pt_loads, + crash_reserved_mem[i].start, crash_reserved_mem[i].end); + } + + max_file_offset = 0; + for (i = 0; i < num_pt_loads; ++i) { + struct pt_load_segment *p = &pt_loads[i]; + max_file_offset = MAX(max_file_offset, + p->file_offset + p->phys_end - p->phys_start); + } + + for (i = 0; i < num_pt_loads; ++i) { + struct pt_load_segment *p = &pt_loads[i]; + DEBUG_MSG("LOAD (%d)\n", i); + DEBUG_MSG(" phys_start : %llx\n", p->phys_start); + DEBUG_MSG(" phys_end : %llx\n", p->phys_end); + DEBUG_MSG(" virt_start : %llx\n", p->virt_start); + DEBUG_MSG(" virt_end : %llx\n", p->virt_end); + } + + return TRUE; +} /* * Get ELF information about /proc/vmcore. |