summaryrefslogtreecommitdiff
path: root/kdump/kdump.c
diff options
context:
space:
mode:
Diffstat (limited to 'kdump/kdump.c')
-rw-r--r--kdump/kdump.c327
1 files changed, 0 insertions, 327 deletions
diff --git a/kdump/kdump.c b/kdump/kdump.c
deleted file mode 100644
index de46d28..0000000
--- a/kdump/kdump.c
+++ /dev/null
@@ -1,327 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <endian.h>
-#include <elf.h>
-
-#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN) || !defined(__BIG_ENDIAN)
-#error Endian defines missing
-#endif
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-# define ELFDATALOCAL ELFDATA2LSB
-#elif __BYTE_ORDER == __BIG_ENDIAN
-# define ELFDATALOCAL ELFDATA2MSB
-#else
-# error Unknown byte order
-#endif
-
-#define MAP_WINDOW_SIZE (64*1024*1024)
-#define DEV_MEM "/dev/mem"
-
-#define ALIGN_MASK(x,y) (((x) + (y)) & ~(y))
-#define ALIGN(x,y) ALIGN_MASK(x, (y) - 1)
-
-static void *map_addr(int fd, unsigned long size, off_t offset)
-{
- unsigned long page_size = getpagesize();
- unsigned long map_offset = offset & (page_size - 1);
- size_t len = ALIGN(size + map_offset, page_size);
- void *result;
-
- result = mmap(0, len, PROT_READ, MAP_SHARED, fd, offset - map_offset);
- if (result == MAP_FAILED) {
- fprintf(stderr, "Cannot mmap " DEV_MEM " offset: %#llx size: %lu: %s\n",
- (unsigned long long)offset, size, strerror(errno));
- exit(5);
- }
- return result + map_offset;
-}
-
-static void unmap_addr(void *addr, unsigned long size)
-{
- unsigned long page_size = getpagesize();
- unsigned long map_offset = (uintptr_t)addr & (page_size - 1);
- size_t len = ALIGN(size + map_offset, page_size);
- int ret;
-
- addr -= map_offset;
-
- ret = munmap(addr, len);
- if (ret < 0) {
- fprintf(stderr, "munmap failed: %s\n",
- strerror(errno));
- exit(6);
- }
-}
-
-static void *xmalloc(size_t size)
-{
- void *result;
- result = malloc(size);
- if (result == NULL) {
- fprintf(stderr, "malloc of %u bytes failed: %s\n",
- (unsigned int)size, strerror(errno));
- exit(7);
- }
- return result;
-}
-
-static void *collect_notes(
- int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdr, size_t *note_bytes)
-{
- int i;
- size_t bytes, result_bytes;
- char *notes;
-
- result_bytes = 0;
- /* Find the worst case note memory usage */
- bytes = 0;
- for(i = 0; i < ehdr->e_phnum; i++) {
- if (phdr[i].p_type == PT_NOTE) {
- bytes += phdr[i].p_filesz;
- }
- }
-
- /* Allocate the worst case note array */
- notes = xmalloc(bytes);
-
- /* Walk through and capture the notes */
- for(i = 0; i < ehdr->e_phnum; i++) {
- Elf64_Nhdr *hdr, *lhdr, *nhdr;
- void *pnotes;
- if (phdr[i].p_type != PT_NOTE) {
- continue;
- }
- /* First snapshot the notes */
- pnotes = map_addr(fd, phdr[i].p_filesz, phdr[i].p_offset);
- memcpy(notes + result_bytes, pnotes, phdr[i].p_filesz);
- unmap_addr(pnotes, phdr[i].p_filesz);
-
- /* Walk through the new notes and find the real length */
- hdr = (Elf64_Nhdr *)(notes + result_bytes);
- lhdr = (Elf64_Nhdr *)(notes + result_bytes + phdr[i].p_filesz);
- for(; hdr < lhdr; hdr = nhdr) {
- size_t hdr_size;
- /* If there is not a name this is a invalid/reserved note
- * stop here.
- */
- if (hdr->n_namesz == 0) {
- break;
- }
- hdr_size =
- sizeof(*hdr) +
- ((hdr->n_namesz + 3) & ~3) +
- ((hdr->n_descsz + 3) & ~3);
-
- nhdr = (Elf64_Nhdr *)(((char *)hdr) + hdr_size);
- /* if the note does not fit in the segment stop here */
- if (nhdr > lhdr) {
- break;
- }
- /* Update result_bytes for after each good header */
- result_bytes = ((char *)hdr) - notes;
- }
- }
- *note_bytes = result_bytes;
- return notes;
-}
-
-static void *generate_new_headers(
- Elf64_Ehdr *ehdr, Elf64_Phdr *phdr, size_t note_bytes, size_t *header_bytes)
-{
- unsigned phnum;
- size_t bytes;
- char *headers;
- Elf64_Ehdr *nehdr;
- Elf64_Phdr *nphdr;
- unsigned long long offset;
- int i;
- /* Count the number of program headers.
- * When we are done there will be only one note header.
- */
- phnum = 1;
- for(i = 0; i < ehdr->e_phnum; i++) {
- if (phdr[i].p_type == PT_NOTE) {
- continue;
- }
- phnum++;
- }
-
- /* Compute how many bytes we will need for headers */
- bytes = sizeof(*ehdr) + sizeof(*phdr)*phnum;
-
- /* Allocate memory for the headers */
- headers = xmalloc(bytes);
-
- /* Setup pointers to the new headers */
- nehdr = (Elf64_Ehdr *)headers;
- nphdr = (Elf64_Phdr *)(headers + sizeof(*nehdr));
-
- /* Copy and adjust the Elf header */
- memcpy(nehdr, ehdr, sizeof(*nehdr));
- nehdr->e_phoff = sizeof(*nehdr);
- nehdr->e_phnum = phnum;
- nehdr->e_shoff = 0;
- nehdr->e_shentsize = 0;
- nehdr->e_shnum = 0;
- nehdr->e_shstrndx = 0;
-
- /* Write the note program header */
- nphdr->p_type = PT_NOTE;
- nphdr->p_offset = bytes;
- nphdr->p_vaddr = 0;
- nphdr->p_paddr = 0;
- nphdr->p_filesz = note_bytes;
- nphdr->p_memsz = note_bytes;
- nphdr->p_flags = 0;
- nphdr->p_align = 0;
- nphdr++;
-
- /* Write the rest of the program headers */
- offset = bytes + note_bytes;
- for(i = 0; i < ehdr->e_phnum; i++) {
- if (phdr[i].p_type == PT_NOTE) {
- continue;
- }
- memcpy(nphdr, &phdr[i], sizeof(*nphdr));
- nphdr->p_offset = offset;
- nphdr++;
- offset += phdr[i].p_filesz;
- }
-
- *header_bytes = bytes;
- return headers;
-}
-
-static void write_all(int fd, const void *buf, size_t count)
-{
- ssize_t result;
- size_t written = 0;
- const char *ptr;
- size_t left;
- ptr = buf;
- left = count;
- do {
- result = write(fd, ptr, left);
- if (result >= 0) {
- written += result;
- ptr += result;
- left -= result;
- }
- else if ((errno != EAGAIN) && (errno != EINTR)) {
- fprintf(stderr, "write failed: %s\n",
- strerror(errno));
- exit(8);
- }
- } while(written < count);
-}
-
-int main(int argc, char **argv)
-{
- char *start_addr_str, *end;
- unsigned long long start_addr;
- Elf64_Ehdr *ehdr;
- Elf64_Phdr *phdr;
- void *notes, *headers;
- size_t note_bytes, header_bytes;
- int fd;
- int i;
- start_addr_str = 0;
- if (argc > 2) {
- fprintf(stderr, "Invalid argument count\n");
- exit(9);
- }
- if (argc == 2) {
- start_addr_str = argv[1];
- }
- if (!start_addr_str) {
- start_addr_str = getenv("elfcorehdr");
- }
- if (!start_addr_str) {
- fprintf(stderr, "Cannot find the start of the core dump\n");
- exit(1);
- }
- start_addr = strtoull(start_addr_str, &end, 0);
- if ((start_addr_str == end) || (*end != '\0')) {
- fprintf(stderr, "Bad core dump start addres: %s\n",
- start_addr_str);
- exit(2);
- }
-
- fd = open(DEV_MEM, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Cannot open " DEV_MEM ": %s\n",
- strerror(errno));
- exit(3);
- }
-
- /* Get the elf header */
- ehdr = map_addr(fd, sizeof(*ehdr), start_addr);
-
- /* Verify the ELF header */
- if ( (ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
- (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
- (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
- (ehdr->e_ident[EI_MAG3] != ELFMAG3) ||
- (ehdr->e_ident[EI_CLASS] != ELFCLASS64) ||
- (ehdr->e_ident[EI_DATA] != ELFDATALOCAL) ||
- (ehdr->e_ident[EI_VERSION] != EV_CURRENT) ||
- (ehdr->e_type != ET_CORE) ||
- (ehdr->e_version != EV_CURRENT) ||
- (ehdr->e_ehsize != sizeof(Elf64_Ehdr)) ||
- (ehdr->e_phentsize != sizeof(Elf64_Phdr)) ||
- (ehdr->e_phnum == 0))
- {
- fprintf(stderr, "Invalid Elf header\n");
- exit(4);
- }
-
- /* Get the program header */
- phdr = map_addr(fd, sizeof(*phdr)*(ehdr->e_phnum),
- start_addr + ehdr->e_phoff);
-
- /* Collect up the notes */
- note_bytes = 0;
- notes = collect_notes(fd, ehdr, phdr, &note_bytes);
-
- /* Generate new headers */
- header_bytes = 0;
- headers = generate_new_headers(ehdr, phdr, note_bytes, &header_bytes);
-
- /* Write out everything */
- write_all(STDOUT_FILENO, headers, header_bytes);
- write_all(STDOUT_FILENO, notes, note_bytes);
- for(i = 0; i < ehdr->e_phnum; i++) {
- unsigned long long offset, size;
- size_t wsize;
- if (phdr[i].p_type == PT_NOTE) {
- continue;
- }
- offset = phdr[i].p_offset;
- size = phdr[i].p_filesz;
- wsize = MAP_WINDOW_SIZE;
- if (wsize > size) {
- wsize = size;
- }
- for(;size > 0; size -= wsize, offset += wsize) {
- void *buf;
- wsize = MAP_WINDOW_SIZE;
- if (wsize > size) {
- wsize = size;
- }
- buf = map_addr(fd, wsize, offset);
- write_all(STDOUT_FILENO, buf, wsize);
- unmap_addr(buf, wsize);
- }
- }
- free(notes);
- close(fd);
- return 0;
-}