This patch is used to upgrade makedumpfile from v1.3.5 to v1.5.3 of upstream. The base is rhel6.5 kexec-tools 2.0.0-262. The manual change is for keeping the old version number and date, e.g the version number is still v1.3.5, and the date is '11 November 2009'. The other change is about '-b option' help message adding. In rhel6, this adding is only added into kexec-tools of rhel, but not posted into upstream. Now remove it to keep consistent with v1.5.3 of upstream. diff -Nupr makedumpfile-1.3.5/arch/arm.c makedumpfile-1.5.3/arch/arm.c --- makedumpfile-1.3.5/arch/arm.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/arm.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,169 @@ +/* + * arm.c + * + * Created by: Mika Westerberg + * Copyright (C) 2010 Nokia Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifdef __arm__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + +#define PMD_TYPE_MASK 3 +#define PMD_TYPE_SECT 2 +#define PMD_TYPE_TABLE 1 + +#define pgd_index(vaddr) ((vaddr) >> PGDIR_SHIFT) +#define pte_index(vaddr) ((vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) + +#define pgd_offset(pgdir, vaddr) \ + ((pgdir) + pgd_index(vaddr) * 2 * sizeof(unsigned long)) +#define pmd_offset(dir, vaddr) (dir) +#define pte_offset(pmd, vaddr) \ + (pmd_page_vaddr(pmd) + pte_index(vaddr) * sizeof(unsigned long)) + +/* + * These only work for kernel directly mapped addresses. + */ +#define __va(paddr) ((paddr) - info->phys_base + info->page_offset) +#define __pa(vaddr) ((vaddr) - info->page_offset + info->phys_base) + +static inline unsigned long +pmd_page_vaddr(unsigned long pmd) +{ + unsigned long ptr; + + ptr = pmd & ~(PTRS_PER_PTE * sizeof(void *) - 1); + ptr += PTRS_PER_PTE * sizeof(void *); + + return __va(ptr); +} + +int +get_phys_base_arm(void) +{ + unsigned long phys_base = ULONG_MAX; + unsigned long long phys_start; + int i; + + /* + * We resolve phys_base from PT_LOAD segments. LMA contains physical + * address of the segment, and we use the first one. + */ + for (i = 0; get_pt_load(i, &phys_start, NULL, NULL, NULL); i++) { + if (phys_start < phys_base) + phys_base = phys_start; + } + + if (phys_base == ULONG_MAX) { + ERRMSG("Can't determine phys_base.\n"); + return FALSE; + } + + info->phys_base = phys_base; + DEBUG_MSG("phys_base : %lx\n", phys_base); + + return TRUE; +} + +int +get_machdep_info_arm(void) +{ + info->page_offset = SYMBOL(_stext) & 0xffff0000UL; + info->max_physmem_bits = _MAX_PHYSMEM_BITS; + info->kernel_start = SYMBOL(_stext); + info->section_size_bits = _SECTION_SIZE_BITS; + + DEBUG_MSG("page_offset : %lx\n", info->page_offset); + DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); + + return TRUE; +} + +/* + * vtop_arm() - translate arbitrary virtual address to physical + * @vaddr: virtual address to translate + * + * Function translates @vaddr into physical address using page tables. This + * address can be any virtual address. Returns physical address of the + * corresponding virtual address or %NOT_PADDR when there is no translation. + */ +static unsigned long long +vtop_arm(unsigned long vaddr) +{ + unsigned long long paddr = NOT_PADDR; + unsigned long ptr, pgd, pte, pmd; + + if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); + return NOT_PADDR; + } + + ptr = pgd_offset(SYMBOL(swapper_pg_dir), vaddr); + if (!readmem(VADDR, ptr, &pgd, sizeof(pmd))) { + ERRMSG("Can't read pgd\n"); + return NOT_PADDR; + } + + if (info->vaddr_for_vtop == vaddr) + MSG(" PGD : %08lx => %08lx\n", ptr, pgd); + + pmd = pmd_offset(pgd, vaddr); + + switch (pmd & PMD_TYPE_MASK) { + case PMD_TYPE_TABLE: { + /* 4k small page */ + ptr = pte_offset(pmd, vaddr); + if (!readmem(VADDR, ptr, &pte, sizeof(pte))) { + ERRMSG("Can't read pte\n"); + return NOT_PADDR; + } + + if (info->vaddr_for_vtop == vaddr) + MSG(" PTE : %08lx => %08lx\n", ptr, pte); + + if (!(pte & _PAGE_PRESENT)) { + ERRMSG("Can't get a valid pte.\n"); + return NOT_PADDR; + } + + paddr = PAGEBASE(pte) + (vaddr & (PAGESIZE() - 1)); + break; + } + + case PMD_TYPE_SECT: + /* 1MB section */ + pte = pmd & PMD_MASK; + paddr = pte + (vaddr & (PMD_SIZE - 1)); + break; + } + + return paddr; +} + +unsigned long long +vaddr_to_paddr_arm(unsigned long vaddr) +{ + /* + * Only use translation tables when user has explicitly requested us to + * perform translation for a given address. Otherwise we assume that the + * translation is done within the kernel direct mapped region. + */ + if (info->vaddr_for_vtop == vaddr) + return vtop_arm(vaddr); + + return __pa(vaddr); +} + +#endif /* __arm__ */ diff -Nupr makedumpfile-1.3.5/arch/ia64.c makedumpfile-1.5.3/arch/ia64.c --- makedumpfile-1.3.5/arch/ia64.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/ia64.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,389 @@ +/* + * ia64.c + * + * Copyright (C) 2006, 2007, 2008 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifdef __ia64__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + + +/* + * vmalloc() starting address is either the traditional 0xa000000000000000 or + * bumped up in 2.6 to 0xa000000200000000. + */ +int +is_vmalloc_addr_ia64(unsigned long vaddr) +{ + return ((vaddr >= info->vmalloc_start) && + (vaddr < (unsigned long)KERNEL_UNCACHED_BASE)); +} + +int +get_phys_base_ia64(void) +{ + int i; + unsigned long long phys_start; + unsigned long long virt_start; + + /* + * Default to 64MB. + */ + info->phys_base = DEFAULT_PHYS_START; + + for (i = 0; get_pt_load(i, &phys_start, NULL, &virt_start, NULL); i++) { + if (VADDR_REGION(virt_start) == KERNEL_VMALLOC_REGION) { + + info->phys_base = phys_start; + break; + } + } + return TRUE; +} + +int +get_machdep_info_ia64(void) +{ + /* + * Get kernel_start and vmalloc_start. + */ + if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) + return FALSE; + + info->kernel_start = SYMBOL(_stext); + + if (VADDR_REGION(info->kernel_start) == KERNEL_VMALLOC_REGION) + info->vmalloc_start = info->kernel_start + 4*1024UL*1024UL*1024UL; + else + info->vmalloc_start = KERNEL_VMALLOC_BASE; + + /* + * Check the pgtable (3 Levels or 4 Levels). + */ + if ((vt.mem_flags & MEMORY_PAGETABLE_4L) + || !strncmp(SRCFILE(pud_t), STR_PUD_T_4L, strlen(STR_PUD_T_4L))) { + vt.mem_flags |= MEMORY_PAGETABLE_4L; + DEBUG_MSG("PAGETABLE_4L : ON\n"); + } else if ((vt.mem_flags & MEMORY_PAGETABLE_3L) + || !strncmp(SRCFILE(pud_t), STR_PUD_T_3L, strlen(STR_PUD_T_3L))) { + vt.mem_flags |= MEMORY_PAGETABLE_3L; + DEBUG_MSG("PAGETABLE_3L : ON\n"); + } else { + MSG("Can't distinguish the pgtable.\n"); + } + + info->section_size_bits = _SECTION_SIZE_BITS; + info->max_physmem_bits = _MAX_PHYSMEM_BITS; + + return TRUE; +} + +/* + * Translate a virtual address to a physical address by using 3 levels paging. + */ +unsigned long long +vtop3_ia64(unsigned long vaddr) +{ + unsigned long long paddr, temp, page_dir, pgd_pte, page_middle, pmd_pte; + unsigned long long page_table, pte; + + if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); + return NOT_PADDR; + } + + /* + * Get PGD + */ + temp = vaddr & MASK_PGD_3L; + temp = temp >> (PGDIR_SHIFT_3L - 3); + page_dir = SYMBOL(swapper_pg_dir) + temp; + if (!readmem(VADDR, page_dir, &pgd_pte, sizeof pgd_pte)) { + ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PGD : %16llx => %16llx\n", page_dir, pgd_pte); + + /* + * Get PMD + */ + temp = vaddr & MASK_PMD; + temp = temp >> (PMD_SHIFT - 3); + page_middle = pgd_pte + temp; + if (!readmem(PADDR, page_middle, &pmd_pte, sizeof pmd_pte)) { + ERRMSG("Can't get pmd_pte (page_middle:%llx).\n", page_middle); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PMD : %16llx => %16llx\n", page_middle, pmd_pte); + + /* + * Get PTE + */ + temp = vaddr & MASK_PTE; + temp = temp >> (PAGESHIFT() - 3); + page_table = pmd_pte + temp; + if (!readmem(PADDR, page_table, &pte, sizeof pte)) { + ERRMSG("Can't get pte (page_table:%llx).\n", page_table); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PTE : %16llx => %16llx\n", page_table, pte); + + /* + * Get physical address + */ + temp = vaddr & MASK_POFFSET; + paddr = (pte & _PAGE_PPN_MASK) + temp; + + return paddr; +} + +/* + * Translate a virtual address to a physical address by using 4 levels paging. + */ +unsigned long long +vtop4_ia64(unsigned long vaddr) +{ + unsigned long long paddr, temp, page_dir, pgd_pte, page_upper, pud_pte; + unsigned long long page_middle, pmd_pte, page_table, pte; + + if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); + return NOT_PADDR; + } + + /* + * Get PGD + */ + temp = vaddr & MASK_PGD_4L; + temp = temp >> (PGDIR_SHIFT_4L - 3); + page_dir = SYMBOL(swapper_pg_dir) + temp; + if (!readmem(VADDR, page_dir, &pgd_pte, sizeof pgd_pte)) { + ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PGD : %16llx => %16llx\n", page_dir, pgd_pte); + + /* + * Get PUD + */ + temp = vaddr & MASK_PUD; + temp = temp >> (PUD_SHIFT - 3); + page_upper = pgd_pte + temp; + if (!readmem(PADDR, page_upper, &pud_pte, sizeof pud_pte)) { + ERRMSG("Can't get pud_pte (page_upper:%llx).\n", page_upper); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PUD : %16llx => %16llx\n", page_upper, pud_pte); + + /* + * Get PMD + */ + temp = vaddr & MASK_PMD; + temp = temp >> (PMD_SHIFT - 3); + page_middle = pud_pte + temp; + if (!readmem(PADDR, page_middle, &pmd_pte, sizeof pmd_pte)) { + ERRMSG("Can't get pmd_pte (page_middle:%llx).\n", page_middle); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PMD : %16llx => %16llx\n", page_middle, pmd_pte); + + /* + * Get PTE + */ + temp = vaddr & MASK_PTE; + temp = temp >> (PAGESHIFT() - 3); + page_table = pmd_pte + temp; + if (!readmem(PADDR, page_table, &pte, sizeof pte)) { + ERRMSG("Can't get pte (page_table:%llx).\n", page_table); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PTE : %16llx => %16llx\n", page_table, pte); + + /* + * Get physical address + */ + temp = vaddr & MASK_POFFSET; + paddr = (pte & _PAGE_PPN_MASK) + temp; + + return paddr; +} + +unsigned long long +vtop_ia64(unsigned long vaddr) +{ + unsigned long long paddr; + + if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) { + ERRMSG("vaddr(%lx) is not KERNEL_VMALLOC_REGION.\n", vaddr); + return NOT_PADDR; + } + paddr = vaddr_to_paddr_general(vaddr); + if (paddr != NOT_PADDR) + return paddr; + + if (!is_vmalloc_addr_ia64(vaddr)) { + paddr = vaddr - info->kernel_start + + (info->phys_base & KERNEL_TR_PAGE_MASK); + return paddr; + } + + if (vt.mem_flags & MEMORY_PAGETABLE_4L) + return vtop4_ia64(vaddr); + else + return vtop3_ia64(vaddr); +} + +/* + * Translate a virtual address to physical address. + */ +unsigned long long +vaddr_to_paddr_ia64(unsigned long vaddr) +{ + unsigned long long paddr; + + switch (VADDR_REGION(vaddr)) { + case KERNEL_CACHED_REGION: + paddr = vaddr - (ulong)(KERNEL_CACHED_BASE); + break; + + case KERNEL_UNCACHED_REGION: + paddr = vaddr - (ulong)(KERNEL_UNCACHED_BASE); + break; + + case KERNEL_VMALLOC_REGION: + paddr = vtop_ia64(vaddr); + break; + + default: + ERRMSG("Unknown region (%ld)\n", VADDR_REGION(vaddr)); + return 0x0; + } + return paddr; +} + +/* + * for Xen extraction + */ +unsigned long long +kvtop_xen_ia64(unsigned long kvaddr) +{ + unsigned long long addr, dirp, entry; + + if (!is_xen_vaddr(kvaddr)) + return NOT_PADDR; + + if (is_direct(kvaddr)) + return (unsigned long)kvaddr - DIRECTMAP_VIRT_START; + + if (!is_frame_table_vaddr(kvaddr)) + return NOT_PADDR; + + addr = kvaddr - VIRT_FRAME_TABLE_ADDR; + + dirp = SYMBOL(frametable_pg_dir) - DIRECTMAP_VIRT_START; + dirp += ((addr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + dirp = entry & _PFN_MASK; + if (!dirp) + return NOT_PADDR; + + dirp += ((addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + dirp = entry & _PFN_MASK; + if (!dirp) + return NOT_PADDR; + + dirp += ((addr >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_P)) + return NOT_PADDR; + + entry = (entry & _PFN_MASK) + (addr & ((1UL << PAGESHIFT()) - 1)); + + return entry; +} + +int +get_xen_basic_info_ia64(void) +{ + unsigned long xen_start, xen_end; + + info->frame_table_vaddr = VIRT_FRAME_TABLE_ADDR; /* "frame_table" is same value */ + + if (!info->xen_crash_info.com || + info->xen_crash_info.com->xen_major_version < 4) { + if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of xenheap_phys_end.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end, + sizeof(xen_end))) { + ERRMSG("Can't get the value of xenheap_phys_end.\n"); + return FALSE; + } + if (SYMBOL(xen_pstart) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of xen_pstart.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(xen_pstart), &xen_start, + sizeof(xen_start))) { + ERRMSG("Can't get the value of xen_pstart.\n"); + return FALSE; + } + info->xen_heap_start = paddr_to_pfn(xen_start); + info->xen_heap_end = paddr_to_pfn(xen_end); + } + + return TRUE; +} + +int +get_xen_info_ia64(void) +{ + unsigned long xen_heap_start; + int i; + + if (SYMBOL(xen_heap_start) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of xen_heap_start.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(xen_heap_start), &xen_heap_start, + sizeof(xen_heap_start))) { + ERRMSG("Can't get the value of xen_heap_start.\n"); + return FALSE; + } + for (i = 0; i < info->num_domain; i++) { + info->domain_list[i].pickled_id = (unsigned int) + (info->domain_list[i].domain_addr - xen_heap_start); + } + + return TRUE; +} + +#endif /* ia64 */ + diff -Nupr makedumpfile-1.3.5/arch/ppc64.c makedumpfile-1.5.3/arch/ppc64.c --- makedumpfile-1.3.5/arch/ppc64.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/ppc64.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,121 @@ +/* + * ppc64.c + * + * Created by: Sachin Sant (sachinp@in.ibm.com) + * Copyright (C) IBM Corporation, 2006. All rights reserved + * + * 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 (version 2 of the License). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __powerpc64__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + +int +set_ppc64_max_physmem_bits(void) +{ + long array_len = ARRAY_LENGTH(mem_section); + /* + * The older ppc64 kernels uses _MAX_PHYSMEM_BITS as 42 and the + * newer kernels 3.7 onwards uses 46 bits. + */ + + info->max_physmem_bits = _MAX_PHYSMEM_BITS_ORIG ; + if ((array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT_EXTREME())) + || (array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT()))) + return TRUE; + + info->max_physmem_bits = _MAX_PHYSMEM_BITS_3_7; + if ((array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT_EXTREME())) + || (array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT()))) + return TRUE; + + return FALSE; +} + +int +get_machdep_info_ppc64(void) +{ + unsigned long vmlist, vmalloc_start; + + info->section_size_bits = _SECTION_SIZE_BITS; + if (!set_ppc64_max_physmem_bits()) { + ERRMSG("Can't detect max_physmem_bits.\n"); + return FALSE; + } + info->page_offset = __PAGE_OFFSET; + + if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of _stext.\n"); + return FALSE; + } + info->kernel_start = SYMBOL(_stext); + DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); + + /* + * For the compatibility, makedumpfile should run without the symbol + * vmlist and the offset of vm_struct.addr if they are not necessary. + */ + if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) + || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { + return TRUE; + } + if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) { + ERRMSG("Can't get vmlist.\n"); + return FALSE; + } + if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start, + sizeof(vmalloc_start))) { + ERRMSG("Can't get vmalloc_start.\n"); + return FALSE; + } + info->vmalloc_start = vmalloc_start; + DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); + + return TRUE; +} + +int +is_vmalloc_addr_ppc64(unsigned long vaddr) +{ + return (info->vmalloc_start && vaddr >= info->vmalloc_start); +} + +unsigned long long +vaddr_to_paddr_ppc64(unsigned long vaddr) +{ + unsigned long long paddr; + + paddr = vaddr_to_paddr_general(vaddr); + if (paddr != NOT_PADDR) + return paddr; + + if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) + || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { + ERRMSG("Can't get necessary information for vmalloc translation.\n"); + return NOT_PADDR; + } + if (!is_vmalloc_addr_ppc64(vaddr)) + return (vaddr - info->kernel_start); + + /* + * TODO: Support vmalloc translation. + */ + ERRMSG("This makedumpfile does not support vmalloc translation.\n"); + return NOT_PADDR; +} + +#endif /* powerpc64 */ diff -Nupr makedumpfile-1.3.5/arch/ppc.c makedumpfile-1.5.3/arch/ppc.c --- makedumpfile-1.3.5/arch/ppc.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/ppc.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,101 @@ +/* + * ppc.c + * + * Created by: Suzuki K. Poulose + * - Based on ppc64 implementation + * Copyright (C) IBM Corporation, 2012. All rights reserved + * + * 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 (version 2 of the License). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __powerpc32__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + +int +get_machdep_info_ppc(void) +{ + unsigned long vmlist, vmalloc_start; + + info->section_size_bits = _SECTION_SIZE_BITS; + info->max_physmem_bits = _MAX_PHYSMEM_BITS; + info->page_offset = __PAGE_OFFSET; + + if (SYMBOL(_stext) != NOT_FOUND_SYMBOL) + info->kernel_start = SYMBOL(_stext); + else { + ERRMSG("Can't get the symbol of _stext.\n"); + return FALSE; + } + + DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); + + /* + * For the compatibility, makedumpfile should run without the symbol + * vmlist and the offset of vm_struct.addr if they are not necessary. + */ + if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) + || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { + return TRUE; + } + if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) { + ERRMSG("Can't get vmlist.\n"); + return FALSE; + } + if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start, + sizeof(vmalloc_start))) { + ERRMSG("Can't get vmalloc_start.\n"); + return FALSE; + } + info->vmalloc_start = vmalloc_start; + DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); + + return TRUE; +} + +int +is_vmalloc_addr_ppc(unsigned long vaddr) +{ + return (info->vmalloc_start && vaddr >= info->vmalloc_start); +} + +unsigned long long +vaddr_to_paddr_ppc(unsigned long vaddr) +{ + unsigned long *pgd, *pmd; + unsigned long long pte; + unsigned long long paddr; + + paddr = vaddr_to_paddr_general(vaddr); + if (paddr != NOT_PADDR) + return paddr; + + if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) + || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { + ERRMSG("Can't get necessary information for vmalloc translation.\n"); + return NOT_PADDR; + } + if (!is_vmalloc_addr_ppc(vaddr)) + return (vaddr - info->kernel_start); + + /* + * TODO: Support vmalloc translation. + */ + ERRMSG("This makedumpfile does not support vmalloc translation.\n"); + return NOT_PADDR; +} + +#endif /* powerpc32 */ diff -Nupr makedumpfile-1.3.5/arch/s390x.c makedumpfile-1.5.3/arch/s390x.c --- makedumpfile-1.3.5/arch/s390x.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/s390x.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,309 @@ +/* + * s390x.c + * + * Created by: Michael Holzheu (holzheu@de.ibm.com) + * Copyright IBM Corp. 2010 + * + * 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 (version 2 of the License). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __s390x__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + +#define TABLE_SIZE 4096 + +/* + * Bits in the virtual address + * + * |<----- RX ---------->| + * | RFX | RSX | RTX | SX | PX | BX | + * 0 11 22 33 44 52 63 + * + * RX: Region Index + * RFX: Region first index + * RSX: Region second index + * RTX: Region third index + * SX: Segment index + * PX: Page index + * BX: Byte index + * + * RX part of vaddr is divided into three fields RFX, RSX and RTX each of + * 11 bit in size + */ +#define _REGION_INDEX_SHIFT 11 +#define _PAGE_INDEX_MASK 0xff000UL /* page index (PX) mask */ +#define _BYTE_INDEX_MASK 0x00fffUL /* Byte index (BX) mask */ +#define _PAGE_BYTE_INDEX_MASK (_PAGE_INDEX_MASK | _BYTE_INDEX_MASK) + +/* Region/segment table index */ +#define rsg_index(x, y) \ + (((x) >> ((_REGION_INDEX_SHIFT * y) + _SEGMENT_INDEX_SHIFT)) \ + & _REGION_OFFSET_MASK) +/* Page table index */ +#define pte_index(x) (((x) >> _PAGE_INDEX_SHIFT) & _PAGE_OFFSET_MASK) + +#define rsg_offset(x, y) (rsg_index( x, y) * sizeof(unsigned long)) +#define pte_offset(x) (pte_index(x) * sizeof(unsigned long)) + +int +set_s390x_max_physmem_bits(void) +{ + long array_len = ARRAY_LENGTH(mem_section); + /* + * The older s390x kernels uses _MAX_PHYSMEM_BITS as 42 and the + * newer kernels uses 46 bits. + */ + + info->max_physmem_bits = _MAX_PHYSMEM_BITS_ORIG ; + if ((array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT_EXTREME())) + || (array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT()))) + return TRUE; + + info->max_physmem_bits = _MAX_PHYSMEM_BITS_3_3; + if ((array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT_EXTREME())) + || (array_len == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT()))) + return TRUE; + + return FALSE; +} + +int +get_machdep_info_s390x(void) +{ + unsigned long vmalloc_start; + char *term_str = getenv("TERM"); + + if (term_str && strcmp(term_str, "dumb") == 0) + /* '\r' control character is ignored on "dumb" terminal. */ + flag_ignore_r_char = 1; + + info->section_size_bits = _SECTION_SIZE_BITS; + if (!set_s390x_max_physmem_bits()) { + ERRMSG("Can't detect max_physmem_bits.\n"); + return FALSE; + } + info->page_offset = __PAGE_OFFSET; + + if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of _stext.\n"); + return FALSE; + } + info->kernel_start = SYMBOL(_stext); + DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); + + /* + * Obtain the vmalloc_start address from high_memory symbol. + */ + if (SYMBOL(high_memory) == NOT_FOUND_SYMBOL) { + return TRUE; + } + if (!readmem(VADDR, SYMBOL(high_memory), &vmalloc_start, + sizeof(vmalloc_start))) { + ERRMSG("Can't get vmalloc_start.\n"); + return FALSE; + } + info->vmalloc_start = vmalloc_start; + DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); + + return TRUE; +} + +static int +is_vmalloc_addr_s390x(unsigned long vaddr) +{ + return (info->vmalloc_start && vaddr >= info->vmalloc_start); +} + +static int +rsg_table_entry_bad(unsigned long entry, int level) +{ + unsigned long mask = ~_REGION_ENTRY_INVALID + & ~_REGION_ENTRY_TYPE_MASK + & ~_REGION_ENTRY_LENGTH; + + if (level) + mask &= ~_REGION_ENTRY_ORIGIN; + else + mask &= ~_SEGMENT_ENTRY_ORIGIN; + + return (entry & mask) != 0; +} + +/* Region or segment table traversal function */ +static unsigned long +_kl_rsg_table_deref_s390x(unsigned long vaddr, unsigned long table, + int len, int level) +{ + unsigned long offset, entry; + + offset = rsg_offset(vaddr, level); + + /* check if offset is over the table limit. */ + if (offset >= ((len + 1) * TABLE_SIZE)) { + ERRMSG("offset is over the table limit.\n"); + return 0; + } + + if (!readmem(VADDR, table + offset, &entry, sizeof(entry))) { + if (level) + ERRMSG("Can't read region table %d entry\n", level); + else + ERRMSG("Can't read segment table entry\n"); + return 0; + } + /* + * Check if the segment table entry could be read and doesn't have + * any of the reserved bits set. + */ + if (rsg_table_entry_bad(entry, level)) { + ERRMSG("Bad region/segment table entry.\n"); + return 0; + } + /* + * Check if the region/segment table entry is with valid + * level and not invalid. + */ + if ((RSG_TABLE_LEVEL(entry) != level) + && (entry & _REGION_ENTRY_INVALID)) { + ERRMSG("Invalid region/segment table level or entry.\n"); + return 0; + } + + return entry; +} + +/* Page table traversal function */ +static ulong _kl_pg_table_deref_s390x(unsigned long vaddr, unsigned long table) +{ + unsigned long offset, entry; + + offset = pte_offset(vaddr); + readmem(VADDR, table + offset, &entry, sizeof(entry)); + /* + * Check if the page table entry could be read and doesn't have + * the reserved bit set. + * Check if the page table entry has the invalid bit set. + */ + if (entry & (_PAGE_ZERO | _PAGE_INVALID)) { + ERRMSG("Invalid page table entry.\n"); + return 0; + } + + return entry; +} + +/* vtop_s390x() - translate virtual address to physical + * @vaddr: virtual address to translate + * + * Function converts the @vaddr into physical address using page tables. + * + * Return: + * Physical address or NOT_PADDR if translation fails. + */ +static unsigned long long +vtop_s390x(unsigned long vaddr) +{ + unsigned long long paddr = NOT_PADDR; + unsigned long table, entry; + int level, len; + + if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); + return NOT_PADDR; + } + table = SYMBOL(swapper_pg_dir); + + /* Read the first entry to find the number of page table levels. */ + readmem(VADDR, table, &entry, sizeof(entry)); + level = TABLE_LEVEL(entry); + len = TABLE_LENGTH(entry); + + if ((vaddr >> (_SEGMENT_PAGE_SHIFT + (_REGION_INDEX_SHIFT * level)))) { + ERRMSG("Address too big for the number of page table " \ + "levels.\n"); + return NOT_PADDR; + } + + /* + * Walk the region and segment tables. + */ + while (level >= 0) { + entry = _kl_rsg_table_deref_s390x(vaddr, table, len, level); + if (!entry) { + return NOT_PADDR; + } + table = entry & _REGION_ENTRY_ORIGIN; + if ((entry & _REGION_ENTRY_LARGE) && (level == 1)) { + table &= ~0x7fffffffUL; + paddr = table + (vaddr & 0x7fffffffUL); + return paddr; + } + len = RSG_TABLE_LENGTH(entry); + level--; + } + + /* + * Check if this is a large page. + * if yes, then add the 1MB page offset (PX + BX) and return the value. + * if no, then get the page table entry using PX index. + */ + if (entry & _SEGMENT_ENTRY_LARGE) { + table &= ~_PAGE_BYTE_INDEX_MASK; + paddr = table + (vaddr & _PAGE_BYTE_INDEX_MASK); + } else { + entry = _kl_pg_table_deref_s390x(vaddr, + entry & _SEGMENT_ENTRY_ORIGIN); + if (!entry) + return NOT_PADDR; + + /* + * Isolate the page origin from the page table entry. + * Add the page offset (BX). + */ + paddr = (entry & _REGION_ENTRY_ORIGIN) + + (vaddr & _BYTE_INDEX_MASK); + } + + return paddr; +} + +unsigned long long +vaddr_to_paddr_s390x(unsigned long vaddr) +{ + unsigned long long paddr; + + paddr = vaddr_to_paddr_general(vaddr); + if (paddr != NOT_PADDR) + return paddr; + + if (SYMBOL(high_memory) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get necessary information for vmalloc " + "translation.\n"); + return NOT_PADDR; + } + + if (is_vmalloc_addr_s390x(vaddr)) { + paddr = vtop_s390x(vaddr); + } + else { + paddr = vaddr - KVBASE; + } + + return paddr; +} + +#endif /* __s390x__ */ diff -Nupr makedumpfile-1.3.5/arch/x86_64.c makedumpfile-1.5.3/arch/x86_64.c --- makedumpfile-1.3.5/arch/x86_64.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/x86_64.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,451 @@ +/* + * x86_64.c + * + * Copyright (C) 2006, 2007, 2008 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifdef __x86_64__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + +int +is_vmalloc_addr(ulong vaddr) +{ + /* + * vmalloc, virtual memmap, and module space as VMALLOC space. + */ + return ((vaddr >= VMALLOC_START && vaddr <= VMALLOC_END) + || (vaddr >= VMEMMAP_START && vaddr <= VMEMMAP_END) + || (vaddr >= MODULES_VADDR && vaddr <= MODULES_END)); +} + +static unsigned long +get_xen_p2m_mfn(void) +{ + if (info->xen_crash_info_v >= 2) + return info->xen_crash_info.v2-> + dom0_pfn_to_mfn_frame_list_list; + if (info->xen_crash_info_v >= 1) + return info->xen_crash_info.v1-> + dom0_pfn_to_mfn_frame_list_list; + return NOT_FOUND_LONG_VALUE; +} + +int +get_phys_base_x86_64(void) +{ + int i; + unsigned long long phys_start; + unsigned long long virt_start; + + /* + * Get the relocatable offset + */ + info->phys_base = 0; /* default/traditional */ + + for (i = 0; get_pt_load(i, &phys_start, NULL, &virt_start, NULL); i++) { + if ((virt_start >= __START_KERNEL_map) && + !(is_vmalloc_addr(virt_start))) { + + info->phys_base = phys_start - + (virt_start & ~(__START_KERNEL_map)); + + break; + } + } + + return TRUE; +} + +int +get_machdep_info_x86_64(void) +{ + unsigned long p2m_mfn; + int i, j, mfns[MAX_X86_64_FRAMES]; + unsigned long frame_mfn[MAX_X86_64_FRAMES]; + unsigned long buf[MFNS_PER_FRAME]; + + info->section_size_bits = _SECTION_SIZE_BITS; + + if (!is_xen_memory()) + return TRUE; + + /* + * Get the information for translating domain-0's physical + * address into machine address. + */ + p2m_mfn = get_xen_p2m_mfn(); + if (p2m_mfn == (unsigned long)NOT_FOUND_LONG_VALUE) { + ERRMSG("Can't get p2m_mfn address.\n"); + return FALSE; + } + if (!readmem(MADDR_XEN, pfn_to_paddr(p2m_mfn), + &frame_mfn, PAGESIZE())) { + ERRMSG("Can't read p2m_mfn.\n"); + return FALSE; + } + + /* + * Count the number of p2m frame. + */ + for (i = 0; i < MAX_X86_64_FRAMES; i++) { + mfns[i] = 0; + if (!frame_mfn[i]) + break; + + if (!readmem(MADDR_XEN, pfn_to_paddr(frame_mfn[i]), &buf, + PAGESIZE())) { + ERRMSG("Can't get frame_mfn[%d].\n", i); + return FALSE; + } + for (j = 0; j < MFNS_PER_FRAME; j++) { + if (!buf[j]) + break; + + mfns[i]++; + } + info->p2m_frames += mfns[i]; + } + info->p2m_mfn_frame_list + = malloc(sizeof(unsigned long) * info->p2m_frames); + if (info->p2m_mfn_frame_list == NULL) { + ERRMSG("Can't allocate memory for p2m_mfn_frame_list. %s\n", + strerror(errno)); + return FALSE; + } + + /* + * Get p2m_mfn_frame_list. + */ + for (i = 0; i < MAX_X86_64_FRAMES; i++) { + if (!frame_mfn[i]) + break; + + if (!readmem(MADDR_XEN, pfn_to_paddr(frame_mfn[i]), + &info->p2m_mfn_frame_list[i * MFNS_PER_FRAME], + mfns[i] * sizeof(unsigned long))) { + ERRMSG("Can't get p2m_mfn_frame_list.\n"); + return FALSE; + } + if (mfns[i] != MFNS_PER_FRAME) + break; + } + return TRUE; +} + +int +get_versiondep_info_x86_64(void) +{ + /* + * On linux-2.6.26, MAX_PHYSMEM_BITS is changed to 44 from 40. + */ + if (info->kernel_version < KERNEL_VERSION(2, 6, 26)) + info->max_physmem_bits = _MAX_PHYSMEM_BITS_ORIG; + else if (info->kernel_version < KERNEL_VERSION(2, 6, 31)) + info->max_physmem_bits = _MAX_PHYSMEM_BITS_2_6_26; + else + info->max_physmem_bits = _MAX_PHYSMEM_BITS_2_6_31; + + if (info->kernel_version < KERNEL_VERSION(2, 6, 27)) + info->page_offset = __PAGE_OFFSET_ORIG; + else + info->page_offset = __PAGE_OFFSET_2_6_27; + + if (info->kernel_version < KERNEL_VERSION(2, 6, 31)) { + info->vmalloc_start = VMALLOC_START_ORIG; + info->vmalloc_end = VMALLOC_END_ORIG; + info->vmemmap_start = VMEMMAP_START_ORIG; + info->vmemmap_end = VMEMMAP_END_ORIG; + } else { + info->vmalloc_start = VMALLOC_START_2_6_31; + info->vmalloc_end = VMALLOC_END_2_6_31; + info->vmemmap_start = VMEMMAP_START_2_6_31; + info->vmemmap_end = VMEMMAP_END_2_6_31; + } + + return TRUE; +} + +/* + * Translate a virtual address to a physical address by using 4 levels paging. + */ +unsigned long long +vtop4_x86_64(unsigned long vaddr) +{ + unsigned long page_dir, pml4, pgd_paddr, pgd_pte, pmd_paddr, pmd_pte; + unsigned long pte_paddr, pte; + + if (SYMBOL(init_level4_pgt) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of init_level4_pgt.\n"); + return NOT_PADDR; + } + + /* + * Get PGD. + */ + page_dir = SYMBOL(init_level4_pgt); + page_dir += pml4_index(vaddr) * sizeof(unsigned long); + if (!readmem(VADDR, page_dir, &pml4, sizeof pml4)) { + ERRMSG("Can't get pml4 (page_dir:%lx).\n", page_dir); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PGD : %16lx => %16lx\n", page_dir, pml4); + + if (!(pml4 & _PAGE_PRESENT)) { + ERRMSG("Can't get a valid pml4.\n"); + return NOT_PADDR; + } + + /* + * Get PUD. + */ + pgd_paddr = pml4 & ENTRY_MASK; + pgd_paddr += pgd_index(vaddr) * sizeof(unsigned long); + if (!readmem(PADDR, pgd_paddr, &pgd_pte, sizeof pgd_pte)) { + ERRMSG("Can't get pgd_pte (pgd_paddr:%lx).\n", pgd_paddr); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PUD : %16lx => %16lx\n", pgd_paddr, pgd_pte); + + if (!(pgd_pte & _PAGE_PRESENT)) { + ERRMSG("Can't get a valid pgd_pte.\n"); + return NOT_PADDR; + } + if (pgd_pte & _PAGE_PSE) /* 1GB pages */ + return (pgd_pte & ENTRY_MASK & PGDIR_MASK) + + (vaddr & ~PGDIR_MASK); + + /* + * Get PMD. + */ + pmd_paddr = pgd_pte & ENTRY_MASK; + pmd_paddr += pmd_index(vaddr) * sizeof(unsigned long); + if (!readmem(PADDR, pmd_paddr, &pmd_pte, sizeof pmd_pte)) { + ERRMSG("Can't get pmd_pte (pmd_paddr:%lx).\n", pmd_paddr); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PMD : %16lx => %16lx\n", pmd_paddr, pmd_pte); + + if (!(pmd_pte & _PAGE_PRESENT)) { + ERRMSG("Can't get a valid pmd_pte.\n"); + return NOT_PADDR; + } + if (pmd_pte & _PAGE_PSE) /* 2MB pages */ + return (pmd_pte & ENTRY_MASK & PMD_MASK) + + (vaddr & ~PMD_MASK); + + /* + * Get PTE. + */ + pte_paddr = pmd_pte & ENTRY_MASK; + pte_paddr += pte_index(vaddr) * sizeof(unsigned long); + if (!readmem(PADDR, pte_paddr, &pte, sizeof pte)) { + ERRMSG("Can't get pte (pte_paddr:%lx).\n", pte_paddr); + return NOT_PADDR; + } + if (info->vaddr_for_vtop == vaddr) + MSG(" PTE : %16lx => %16lx\n", pte_paddr, pte); + + if (!(pte & _PAGE_PRESENT)) { + ERRMSG("Can't get a valid pte.\n"); + return NOT_PADDR; + } + return (pte & ENTRY_MASK) + PAGEOFFSET(vaddr); +} + +unsigned long long +vaddr_to_paddr_x86_64(unsigned long vaddr) +{ + unsigned long phys_base; + unsigned long long paddr; + + /* + * Check the relocatable kernel. + */ + if (SYMBOL(phys_base) != NOT_FOUND_SYMBOL) + phys_base = info->phys_base; + else + phys_base = 0; + + if (is_vmalloc_addr(vaddr)) { + if ((paddr = vtop4_x86_64(vaddr)) == NOT_PADDR) { + ERRMSG("Can't convert a virtual address(%lx) to " \ + "physical address.\n", vaddr); + return NOT_PADDR; + } + } else if (vaddr >= __START_KERNEL_map) { + paddr = vaddr - __START_KERNEL_map + phys_base; + + } else { + if (is_xen_memory()) + paddr = vaddr - PAGE_OFFSET_XEN_DOM0; + else + paddr = vaddr - PAGE_OFFSET; + } + return paddr; +} + +/* + * for Xen extraction + */ +unsigned long long +kvtop_xen_x86_64(unsigned long kvaddr) +{ + unsigned long long dirp, entry; + + if (!is_xen_vaddr(kvaddr)) + return NOT_PADDR; + + if (is_xen_text(kvaddr)) + return (unsigned long)kvaddr - XEN_VIRT_START + info->xen_phys_start; + + if (is_direct(kvaddr)) + return (unsigned long)kvaddr - DIRECTMAP_VIRT_START; + + if ((dirp = kvtop_xen_x86_64(SYMBOL(pgd_l4))) == NOT_PADDR) + return NOT_PADDR; + dirp += pml4_index(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) + return NOT_PADDR; + + dirp = entry & ENTRY_MASK; + dirp += pgd_index(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) + return NOT_PADDR; + + if (entry & _PAGE_PSE) /* 1GB pages */ + return (entry & ENTRY_MASK & PGDIR_MASK) + + (kvaddr & ~PGDIR_MASK); + + dirp = entry & ENTRY_MASK; + dirp += pmd_index(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) + return NOT_PADDR; + + if (entry & _PAGE_PSE) /* 2MB pages */ + return (entry & ENTRY_MASK & PMD_MASK) + + (kvaddr & ~PMD_MASK); + + dirp = entry & ENTRY_MASK; + dirp += pte_index(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) { + return NOT_PADDR; + } + + return (entry & ENTRY_MASK) + PAGEOFFSET(kvaddr); +} + +int get_xen_basic_info_x86_64(void) +{ + if (!info->xen_phys_start) { + if (info->xen_crash_info_v < 2) { + ERRMSG("Can't get Xen physical start address.\n" + "Please use the --xen_phys_start option."); + return FALSE; + } + info->xen_phys_start = info->xen_crash_info.v2->xen_phys_start; + } + + if (info->xen_crash_info.com && + info->xen_crash_info.com->xen_major_version >= 4) { + info->xen_virt_start = XEN_VIRT_START_V4; + info->directmap_virt_end = DIRECTMAP_VIRT_END_V4; + } else { + info->xen_virt_start = XEN_VIRT_START_V3; + info->directmap_virt_end = DIRECTMAP_VIRT_END_V3; + } + + if (SYMBOL(pgd_l4) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get pml4.\n"); + return FALSE; + } + + if (SYMBOL(frame_table) != NOT_FOUND_SYMBOL) { + unsigned long frame_table_vaddr; + + if (!readmem(VADDR_XEN, SYMBOL(frame_table), + &frame_table_vaddr, sizeof(frame_table_vaddr))) { + ERRMSG("Can't get the value of frame_table.\n"); + return FALSE; + } + info->frame_table_vaddr = frame_table_vaddr; + } else + info->frame_table_vaddr = FRAMETABLE_VIRT_START; + + if (!info->xen_crash_info.com || + info->xen_crash_info.com->xen_major_version < 4) { + unsigned long xen_end; + + if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of xenheap_phys_end.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end, + sizeof(xen_end))) { + ERRMSG("Can't get the value of xenheap_phys_end.\n"); + return FALSE; + } + info->xen_heap_start = 0; + info->xen_heap_end = paddr_to_pfn(xen_end); + } + + return TRUE; +} + +int get_xen_info_x86_64(void) +{ + int i; + + if (info->xen_crash_info.com && + (info->xen_crash_info.com->xen_major_version >= 4 || + (info->xen_crash_info.com->xen_major_version == 3 && + info->xen_crash_info.com->xen_minor_version >= 4))) { + /* + * cf. changeset 0858f961c77a + */ + for (i = 0; i < info->num_domain; i++) { + info->domain_list[i].pickled_id = + (info->domain_list[i].domain_addr - + DIRECTMAP_VIRT_START) >> PAGESHIFT(); + } + } else { + /* + * pickled_id == domain addr for x86_64 + */ + for (i = 0; i < info->num_domain; i++) { + info->domain_list[i].pickled_id = + info->domain_list[i].domain_addr; + } + } + + return TRUE; +} + +#endif /* x86_64 */ + diff -Nupr makedumpfile-1.3.5/arch/x86.c makedumpfile-1.5.3/arch/x86.c --- makedumpfile-1.3.5/arch/x86.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/arch/x86.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,355 @@ +/* + * x86.c + * + * Copyright (C) 2006, 2007, 2008 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifdef __x86__ + +#include "../print_info.h" +#include "../elf_info.h" +#include "../makedumpfile.h" + +static int max_numnodes; +static unsigned long *remap_start_vaddr; +static unsigned long *remap_end_vaddr; +static unsigned long *remap_start_pfn; + +static int +remap_init(void) +{ + int n; + + if (SYMBOL(node_remap_start_vaddr) == NOT_FOUND_SYMBOL) + return TRUE; + if (SYMBOL(node_remap_end_vaddr) == NOT_FOUND_SYMBOL) + return TRUE; + if (SYMBOL(node_remap_start_pfn) == NOT_FOUND_SYMBOL) + return TRUE; + if (ARRAY_LENGTH(node_remap_start_pfn) == NOT_FOUND_STRUCTURE) + return TRUE; + + n = ARRAY_LENGTH(node_remap_start_pfn); + remap_start_vaddr = calloc(3 * n, sizeof(unsigned long)); + if (!remap_start_vaddr) { + ERRMSG("Can't allocate remap allocator info.\n"); + return FALSE; + } + remap_end_vaddr = remap_start_vaddr + n; + remap_start_pfn = remap_end_vaddr + n; + + if (!readmem(VADDR, SYMBOL(node_remap_start_vaddr), remap_start_vaddr, + n * sizeof(unsigned long))) { + ERRMSG("Can't get node_remap_start_vaddr.\n"); + return FALSE; + } + if (!readmem(VADDR, SYMBOL(node_remap_end_vaddr), remap_end_vaddr, + n * sizeof(unsigned long))) { + ERRMSG("Can't get node_remap_end_vaddr.\n"); + return FALSE; + } + if (!readmem(VADDR, SYMBOL(node_remap_start_pfn), remap_start_pfn, + n * sizeof(unsigned long))) { + ERRMSG("Can't get node_remap_start_pfn.\n"); + return FALSE; + } + + max_numnodes = n; + return TRUE; +} + +int +get_machdep_info_x86(void) +{ + unsigned long vmlist, vmalloc_start; + + /* PAE */ + if ((vt.mem_flags & MEMORY_X86_PAE) + || ((SYMBOL(pkmap_count) != NOT_FOUND_SYMBOL) + && (SYMBOL(pkmap_count_next) != NOT_FOUND_SYMBOL) + && ((SYMBOL(pkmap_count_next)-SYMBOL(pkmap_count))/sizeof(int)) + == 512)) { + DEBUG_MSG("\n"); + DEBUG_MSG("PAE : ON\n"); + vt.mem_flags |= MEMORY_X86_PAE; + info->max_physmem_bits = _MAX_PHYSMEM_BITS_PAE; + } else { + DEBUG_MSG("\n"); + DEBUG_MSG("PAE : OFF\n"); + info->max_physmem_bits = _MAX_PHYSMEM_BITS; + } + info->page_offset = __PAGE_OFFSET; + + if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of _stext.\n"); + return FALSE; + } + info->kernel_start = SYMBOL(_stext) & ~KVBASE_MASK; + DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); + + if (!remap_init()) + return FALSE; + + /* + * For the compatibility, makedumpfile should run without the symbol + * vmlist and the offset of vm_struct.addr if they are not necessary. + */ + if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) + || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { + return TRUE; + } + if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) { + ERRMSG("Can't get vmlist.\n"); + return FALSE; + } + if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start, + sizeof(vmalloc_start))) { + ERRMSG("Can't get vmalloc_start.\n"); + return FALSE; + } + info->vmalloc_start = vmalloc_start; + DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); + + return TRUE; +} + +int +get_versiondep_info_x86(void) +{ + /* + * SECTION_SIZE_BITS of PAE has been changed to 29 from 30 since + * linux-2.6.26. + */ + if (vt.mem_flags & MEMORY_X86_PAE) { + if (info->kernel_version < KERNEL_VERSION(2, 6, 26)) + info->section_size_bits = _SECTION_SIZE_BITS_PAE_ORIG; + else + info->section_size_bits = _SECTION_SIZE_BITS_PAE_2_6_26; + } else + info->section_size_bits = _SECTION_SIZE_BITS; + + return TRUE; +} + +unsigned long long +vtop_x86_remap(unsigned long vaddr) +{ + int i; + for (i = 0; i < max_numnodes; ++i) + if (vaddr >= remap_start_vaddr[i] && + vaddr < remap_end_vaddr[i]) + return pfn_to_paddr(remap_start_pfn[i]) + + vaddr - remap_start_vaddr[i]; + return NOT_PADDR; +} + +unsigned long long +vtop_x86_PAE(unsigned long vaddr) +{ + unsigned long long page_dir, pgd_pte, pmd_paddr, pmd_pte; + unsigned long long pte_paddr, pte; + + if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); + return NOT_PADDR; + } + + page_dir = SYMBOL(swapper_pg_dir); + page_dir += pgd_index_PAE(vaddr) * sizeof(unsigned long long); + if (!readmem(VADDR, page_dir, &pgd_pte, sizeof(pgd_pte))) { + ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir); + return NOT_PADDR; + } + if (!(pgd_pte & _PAGE_PRESENT)) + return NOT_PADDR; + + if (info->vaddr_for_vtop == vaddr) + MSG(" PGD : %16llx => %16llx\n", page_dir, pgd_pte); + + pmd_paddr = pgd_pte & ENTRY_MASK; + pmd_paddr += pmd_index(vaddr) * sizeof(unsigned long long); + if (!readmem(PADDR, pmd_paddr, &pmd_pte, sizeof(pmd_pte))) { + ERRMSG("Can't get pmd_pte (pmd_paddr:%llx).\n", pmd_paddr); + return NOT_PADDR; + } + if (!(pmd_pte & _PAGE_PRESENT)) + return NOT_PADDR; + + if (info->vaddr_for_vtop == vaddr) + MSG(" PMD : %16llx => %16llx\n", pmd_paddr, pmd_pte); + + if (pmd_pte & _PAGE_PSE) + return (pmd_pte & ENTRY_MASK) + (vaddr & ((1UL << PMD_SHIFT) - 1)); + + pte_paddr = pmd_pte & ENTRY_MASK; + pte_paddr += pte_index(vaddr) * sizeof(unsigned long long); + if (!readmem(PADDR, pte_paddr, &pte, sizeof(pte))) + return NOT_PADDR; + + if (!(pte & _PAGE_PRESENT)) + return NOT_PADDR; + + if (info->vaddr_for_vtop == vaddr) + MSG(" PTE : %16llx => %16llx\n", pte_paddr, pte); + + return (pte & ENTRY_MASK) + (vaddr & ((1UL << PTE_SHIFT) - 1)); +} + +int +is_vmalloc_addr_x86(unsigned long vaddr) +{ + return (info->vmalloc_start && vaddr >= info->vmalloc_start); +} + +unsigned long long +vaddr_to_paddr_x86(unsigned long vaddr) +{ + unsigned long long paddr; + + if ((paddr = vtop_x86_remap(vaddr)) != NOT_PADDR) + return paddr; + + if ((paddr = vaddr_to_paddr_general(vaddr)) != NOT_PADDR) + return paddr; + + if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) + || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { + ERRMSG("Can't get necessary information for vmalloc translation.\n"); + return NOT_PADDR; + } + if (!is_vmalloc_addr_x86(vaddr)) + return (vaddr - info->kernel_start); + + if (vt.mem_flags & MEMORY_X86_PAE) { + paddr = vtop_x86_PAE(vaddr); + } else { + /* + * TODO: Support vmalloc translation of not-PAE kernel. + */ + ERRMSG("This makedumpfile does not support vmalloc translation of not-PAE kernel.\n"); + return NOT_PADDR; + } + + return paddr; +} + +/* + * for Xen extraction + */ +unsigned long long +kvtop_xen_x86(unsigned long kvaddr) +{ + unsigned long long dirp, entry; + + if (!is_xen_vaddr(kvaddr)) + return NOT_PADDR; + + if (is_direct(kvaddr)) + return (unsigned long)kvaddr - DIRECTMAP_VIRT_START; + + if ((dirp = kvtop_xen_x86(SYMBOL(pgd_l3))) == NOT_PADDR) + return NOT_PADDR; + dirp += pgd_index_PAE(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) + return NOT_PADDR; + + dirp = entry & ENTRY_MASK; + dirp += pmd_index(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) + return NOT_PADDR; + + if (entry & _PAGE_PSE) { + entry = (entry & ENTRY_MASK) + (kvaddr & ((1UL << PMD_SHIFT) - 1)); + return entry; + } + + dirp = entry & ENTRY_MASK; + dirp += pte_index(kvaddr) * sizeof(unsigned long long); + if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) + return NOT_PADDR; + + if (!(entry & _PAGE_PRESENT)) { + return NOT_PADDR; + } + + entry = (entry & ENTRY_MASK) + (kvaddr & ((1UL << PTE_SHIFT) - 1)); + + return entry; +} + +int get_xen_basic_info_x86(void) +{ + if (SYMBOL(pgd_l2) == NOT_FOUND_SYMBOL && + SYMBOL(pgd_l3) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get pgd.\n"); + return FALSE; + } + + if (SYMBOL(pgd_l3) == NOT_FOUND_SYMBOL) { + ERRMSG("non-PAE not support right now.\n"); + return FALSE; + } + + if (SYMBOL(frame_table) != NOT_FOUND_SYMBOL) { + unsigned long frame_table_vaddr; + + if (!readmem(VADDR_XEN, SYMBOL(frame_table), + &frame_table_vaddr, sizeof(frame_table_vaddr))) { + ERRMSG("Can't get the value of frame_table.\n"); + return FALSE; + } + info->frame_table_vaddr = frame_table_vaddr; + } else + info->frame_table_vaddr = FRAMETABLE_VIRT_START; + + if (!info->xen_crash_info.com || + info->xen_crash_info.com->xen_major_version < 4) { + unsigned long xen_end; + + if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of xenheap_phys_end.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end, + sizeof(xen_end))) { + ERRMSG("Can't get the value of xenheap_phys_end.\n"); + return FALSE; + } + info->xen_heap_start = 0; + info->xen_heap_end = paddr_to_pfn(xen_end); + } + + return TRUE; +} + +int get_xen_info_x86(void) +{ + int i; + + /* + * pickled_id == domain addr for x86 + */ + for (i = 0; i < info->num_domain; i++) { + info->domain_list[i].pickled_id = + info->domain_list[i].domain_addr; + } + + return TRUE; +} +#endif /* x86 */ + diff -Nupr makedumpfile-1.3.5/cache.c makedumpfile-1.5.3/cache.c --- makedumpfile-1.3.5/cache.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/cache.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,119 @@ +/* + * cache.h + * + * Created by: Petr Tesarik + * + * Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "makedumpfile.h" +#include "cache.h" + +struct cache_entry { + unsigned long long paddr; + void *bufptr; + struct cache_entry *next, *prev; +}; + +struct cache { + struct cache_entry *head, *tail; +}; + +/* 8 pages covers 4-level paging plus 4 data pages */ +#define CACHE_SIZE 8 +static struct cache_entry pool[CACHE_SIZE]; +static int avail = CACHE_SIZE; + +static struct cache used, pending; + +static void +add_entry(struct cache *cache, struct cache_entry *entry) +{ + entry->next = cache->head; + entry->prev = NULL; + if (cache->head) + cache->head->prev = entry; + cache->head = entry; + if (!cache->tail) + cache->tail = entry; +} + +static void +remove_entry(struct cache *cache, struct cache_entry *entry) +{ + if (entry->next) + entry->next->prev = entry->prev; + else + cache->tail = entry->prev; + + if (entry->prev) + entry->prev->next = entry->next; + else + cache->head = entry->next; +} + +void * +cache_search(unsigned long long paddr) +{ + struct cache_entry *entry; + for (entry = used.head; entry; entry = entry->next) + if (entry->paddr == paddr) { + if (entry != used.head) { + remove_entry(&used, entry); + add_entry(&used, entry); + } + return entry->bufptr; + } + + return NULL; /* cache miss */ +} + +void * +cache_alloc(unsigned long long paddr) +{ + struct cache_entry *entry = NULL; + + if (avail) { + void *bufptr = malloc(info->page_size); + if (bufptr) { + entry = &pool[--avail]; + entry->bufptr = bufptr; + } + } + + if (!entry) { + if (used.tail) { + entry = used.tail; + remove_entry(&used, entry); + } else + return NULL; + } + + entry->paddr = paddr; + add_entry(&pending, entry); + + return entry->bufptr; +} + +void +cache_add(unsigned long long paddr) +{ + struct cache_entry *entry; + for (entry = pending.head; entry; entry = entry->next) { + if (entry->paddr == paddr) { + remove_entry(&pending, entry); + add_entry(&used, entry); + break; + } + } +} diff -Nupr makedumpfile-1.3.5/cache.h makedumpfile-1.5.3/cache.h --- makedumpfile-1.3.5/cache.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/cache.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,26 @@ +/* + * cache.h + * + * Written by: Petr Tesarik + * + * Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CACHE_H +#define _CACHE_H + +void *cache_search(unsigned long long paddr); +void *cache_alloc(unsigned long long paddr); +void cache_add(unsigned long long paddr); + +#endif /* _CACHE_H */ diff -Nupr makedumpfile-1.3.5/common.h makedumpfile-1.5.3/common.h --- makedumpfile-1.3.5/common.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/common.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,46 @@ +/* + * common.h + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _COMMON_H +#define _COMMON_H + +#define TRUE (1) +#define FALSE (0) +#define ERROR (-1) + +#ifndef LONG_MAX +#define LONG_MAX ((long)(~0UL>>1)) +#endif +#ifndef ULONG_MAX +#define ULONG_MAX (~0UL) +#endif +#define ULONGLONG_MAX (~0ULL) + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define divideup(x, y) (((x) + ((y) - 1)) / (y)) +#define round(x, y) (((x) / (y)) * (y)) +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + +/* + * Incorrect address + */ +#define NOT_MEMMAP_ADDR (0x0) +#define NOT_KV_ADDR (0x0) +#define NOT_PADDR (ULONGLONG_MAX) + +#endif /* COMMON_H */ + diff -Nupr makedumpfile-1.3.5/diskdump_mod.h makedumpfile-1.5.3/diskdump_mod.h --- makedumpfile-1.3.5/diskdump_mod.h 2013-07-03 15:18:37.897089017 +0800 +++ makedumpfile-1.5.3/diskdump_mod.h 2013-02-18 16:47:26.000000000 +0800 @@ -18,10 +18,6 @@ #include -#define divideup(x, y) (((x) + ((y) - 1)) / (y)) -#define round(x, y) (((x) / (y)) * (y)) -#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) - #define DUMP_PARTITION_SIGNATURE "diskdump" #define DISK_DUMP_SIGNATURE "DISKDUMP" #define KDUMP_SIGNATURE "KDUMP " @@ -82,7 +78,10 @@ struct kdump_sub_header { }; /* page flags */ -#define DUMP_DH_COMPRESSED 0x1 /* page is compressed */ +#define DUMP_DH_COMPRESSED_ZLIB 0x1 /* page is compressed with zlib */ +#define DUMP_DH_COMPRESSED_LZO 0x2 /* paged is compressed with lzo */ +#define DUMP_DH_COMPRESSED_SNAPPY 0x4 + /* paged is compressed with snappy */ /* descriptor of each page for vmcore */ typedef struct page_desc { diff -Nupr makedumpfile-1.3.5/dwarf_info.c makedumpfile-1.5.3/dwarf_info.c --- makedumpfile-1.3.5/dwarf_info.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/dwarf_info.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,1579 @@ +/* + * dwarf_info.c + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "print_info.h" +#include "dwarf_info.h" + +/* + * Debugging information + */ +#define DEFAULT_DEBUGINFO_PATH "/usr/lib/debug" + +struct dwarf_info { + unsigned int cmd; /* IN */ + int fd_debuginfo; /* IN */ + char *name_debuginfo; /* IN */ + char *module_name; /* IN */ + char *struct_name; /* IN */ + char *symbol_name; /* IN */ + char *member_name; /* IN */ + char *enum_name; /* IN */ + Elf *elfd; /* OUT */ + Dwarf *dwarfd; /* OUT */ + Dwfl *dwfl; /* OUT */ + char *type_name; /* OUT */ + long struct_size; /* OUT */ + long member_offset; /* OUT */ + long array_length; /* OUT */ + long enum_number; /* OUT */ + unsigned char type_flag; /* OUT */ + char src_name[LEN_SRCFILE]; /* OUT */ + Dwarf_Off die_offset; /* OUT */ +}; +static struct dwarf_info dwarf_info; + + +/* + * Internal functions. + */ +static int +is_search_structure(int cmd) +{ + if ((cmd == DWARF_INFO_GET_STRUCT_SIZE) + || (cmd == DWARF_INFO_GET_MEMBER_OFFSET) + || (cmd == DWARF_INFO_GET_MEMBER_TYPE) + || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION) + || (cmd == DWARF_INFO_GET_MEMBER_ARRAY_LENGTH)) + return TRUE; + else + return FALSE; +} + +static int +is_search_number(int cmd) +{ + if (cmd == DWARF_INFO_GET_ENUM_NUMBER) + return TRUE; + else + return FALSE; +} + +static int +is_search_symbol(int cmd) +{ + if ((cmd == DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH) + || (cmd == DWARF_INFO_GET_SYMBOL_TYPE) + || (cmd == DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE)) + return TRUE; + else + return FALSE; +} + +static int +is_search_typedef(int cmd) +{ + if ((cmd == DWARF_INFO_GET_TYPEDEF_SIZE) + || (cmd == DWARF_INFO_GET_TYPEDEF_SRCNAME)) + return TRUE; + else + return FALSE; +} + +static int +is_search_domain(int cmd) +{ + if ((cmd == DWARF_INFO_GET_DOMAIN_STRUCT) + || (cmd == DWARF_INFO_GET_DOMAIN_TYPEDEF) + || (cmd == DWARF_INFO_GET_DOMAIN_ARRAY) + || (cmd == DWARF_INFO_GET_DOMAIN_UNION) + || (cmd == DWARF_INFO_GET_DOMAIN_ENUM) + || (cmd == DWARF_INFO_GET_DOMAIN_REF) + || (cmd == DWARF_INFO_GET_DOMAIN_STRING) + || (cmd == DWARF_INFO_GET_DOMAIN_BASE)) + return TRUE; + else + return FALSE; +} + +static int +is_search_die(int cmd) +{ + if (cmd == DWARF_INFO_GET_DIE) + return TRUE; + else + return FALSE; +} + +static int +process_module (Dwfl_Module *dwflmod, + void **userdata __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + void *arg) +{ + const char *fname, *mod_name, *debugfile; + Dwarf_Addr dwbias; + + /* get a debug context descriptor.*/ + dwarf_info.dwarfd = dwfl_module_getdwarf (dwflmod, &dwbias); + dwarf_info.elfd = dwarf_getelf(dwarf_info.dwarfd); + + mod_name = dwfl_module_info(dwflmod, NULL, NULL, NULL, NULL, NULL, + &fname, &debugfile); + + if (!strcmp(dwarf_info.module_name, mod_name) && + !dwarf_info.name_debuginfo && debugfile) { + /* + * Store the debuginfo filename. Next time we will + * open debuginfo file direclty instead of searching + * for it again. + */ + dwarf_info.name_debuginfo = strdup(debugfile); + } + + return DWARF_CB_OK; +} + +static int +dwfl_report_module_p(const char *modname, const char *filename) +{ + if (filename && !strcmp(modname, dwarf_info.module_name)) + return 1; + return 0; +} + +static void +clean_dwfl_info(void) +{ + if (dwarf_info.dwfl) + dwfl_end(dwarf_info.dwfl); + + dwarf_info.dwfl = NULL; + dwarf_info.dwarfd = NULL; + dwarf_info.elfd = NULL; +} + +/* + * Search module debuginfo. + * This function searches for module debuginfo in default debuginfo path for + * a given module in dwarf_info.module_name. + * + * On success, dwarf_info.name_debuginfo is set to absolute path of + * module debuginfo. + */ +static int +search_module_debuginfo(char *os_release) +{ + Dwfl *dwfl = NULL; + static char *debuginfo_path = DEFAULT_DEBUGINFO_PATH; + static const Dwfl_Callbacks callbacks = { + .section_address = dwfl_offline_section_address, + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + }; + + /* + * Check if We already have debuginfo file name with us. If yes, + * then we don't need to proceed with search method. + */ + if (dwarf_info.name_debuginfo) + return TRUE; + + if ((dwfl = dwfl_begin(&callbacks)) == NULL) { + ERRMSG("Can't create a handle for a new dwfl session.\n"); + return FALSE; + } + + /* Search for module debuginfo file. */ + if (dwfl_linux_kernel_report_offline(dwfl, + os_release, + &dwfl_report_module_p)) { + ERRMSG("Can't get Module debuginfo for module '%s'\n", + dwarf_info.module_name); + dwfl_end(dwfl); + return FALSE; + } + dwfl_report_end(dwfl, NULL, NULL); + dwfl_getmodules(dwfl, &process_module, NULL, 0); + + dwfl_end(dwfl); + clean_dwfl_info(); + + /* Return success if module debuginfo is found. */ + if (dwarf_info.name_debuginfo) + return TRUE; + + return FALSE; +} + +static int +dwarf_no_debuginfo_found(Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + const char *file_name, + const char *debuglink_file, GElf_Word debuglink_crc, + char **debuginfo_file_name) +{ + return -1; +} + +/* + * Initialize the dwarf info. + * Linux kernel module debuginfo are of ET_REL (relocatable) type. + * This function uses dwfl API's to apply relocation before reading the + * dwarf information from module debuginfo. + * On success, this function sets the dwarf_info.elfd and dwarf_info.dwarfd + * after applying relocation to module debuginfo. + */ +static int +init_dwarf_info(void) +{ + Dwfl *dwfl = NULL; + int dwfl_fd = -1; + static const Dwfl_Callbacks callbacks = { + .section_address = dwfl_offline_section_address, + /* + * By the time init_dwarf_info() function is called, we already + * know absolute path of debuginfo either resolved through + * search_module_debuginfo() call OR user specified vmlinux + * debuginfo through '-x' option. In which case .find_debuginfo + * callback is never invoked. + * But we can not deny a situation where user may pass invalid + * file name through '-x' option, where .find_debuginfo gets + * invoked to find a valid vmlinux debuginfo and hence we run + * into seg fault issue. Hence, set .find_debuginfo to a + * funtion pointer that returns -1 to avoid seg fault and let + * the makedumpfile throw error messages against the invalid + * vmlinux file input. + */ + .find_debuginfo = dwarf_no_debuginfo_found + }; + + dwarf_info.elfd = NULL; + dwarf_info.dwarfd = NULL; + + /* + * We already know the absolute path of debuginfo file. Fail if we + * still don't have one. Ideally we should never be in this situation. + */ + if (!dwarf_info.name_debuginfo) { + ERRMSG("Can't find absolute path to debuginfo file.\n"); + return FALSE; + } + + if ((dwfl = dwfl_begin(&callbacks)) == NULL) { + ERRMSG("Can't create a handle for a new dwfl session.\n"); + return FALSE; + } + + /* Open the debuginfo file if it is not already open. */ + if (dwarf_info.fd_debuginfo < 0) + dwarf_info.fd_debuginfo = + open(dwarf_info.name_debuginfo, O_RDONLY); + + dwfl_fd = dup(dwarf_info.fd_debuginfo); + if (dwfl_fd < 0) { + ERRMSG("Failed to get a duplicate handle for" + " debuginfo.\n"); + goto err_out; + } + /* Apply relocations. */ + if (dwfl_report_offline(dwfl, dwarf_info.module_name, + dwarf_info.name_debuginfo, dwfl_fd) == NULL) { + ERRMSG("Failed reading %s: %s\n", + dwarf_info.name_debuginfo, dwfl_errmsg (-1)); + /* dwfl_fd is consumed on success, not on failure */ + close(dwfl_fd); + goto err_out; + } + dwfl_report_end(dwfl, NULL, NULL); + + dwfl_getmodules(dwfl, &process_module, NULL, 0); + + if (dwarf_info.elfd == NULL) { + ERRMSG("Can't get first elf header of %s.\n", + dwarf_info.name_debuginfo); + goto err_out; + } + + if (dwarf_info.dwarfd == NULL) { + ERRMSG("Can't get debug context descriptor for %s.\n", + dwarf_info.name_debuginfo); + goto err_out; + } + dwarf_info.dwfl = dwfl; + return TRUE; +err_out: + if (dwfl) + dwfl_end(dwfl); + + return FALSE; +} + +static int +get_data_member_location(Dwarf_Die *die, long *offset) +{ + size_t expcnt; + Dwarf_Attribute attr; + Dwarf_Op *expr; + + if (dwarf_attr(die, DW_AT_data_member_location, &attr) == NULL) + return FALSE; + + if (dwarf_getlocation(&attr, &expr, &expcnt) < 0) + return FALSE; + + (*offset) = expr[0].number; + + return TRUE; +} + +static int +get_die_type(Dwarf_Die *die, Dwarf_Die *die_type) +{ + Dwarf_Attribute attr; + + if (dwarf_attr(die, DW_AT_type, &attr) == NULL) + return FALSE; + + if (dwarf_formref_die(&attr, die_type) < 0) { + ERRMSG("Can't get CU die.\n"); + return FALSE; + } + return TRUE; +} + +static int +get_data_array_length(Dwarf_Die *die) +{ + int tag; + Dwarf_Attribute attr; + Dwarf_Die die_type; + Dwarf_Word upper_bound; + + if (!get_die_type(die, &die_type)) { + ERRMSG("Can't get CU die of DW_AT_type.\n"); + return FALSE; + } + tag = dwarf_tag(&die_type); + if (tag == DW_TAG_const_type) { + /* This array is of const type. Get the die type again */ + if (!get_die_type(&die_type, &die_type)) { + ERRMSG("Can't get CU die of DW_AT_type.\n"); + return FALSE; + } + tag = dwarf_tag(&die_type); + } + if (tag != DW_TAG_array_type) { + /* + * This kernel doesn't have the member of array. + */ + return TRUE; + } + + /* + * Get the demanded array length. + */ + dwarf_child(&die_type, &die_type); + do { + tag = dwarf_tag(&die_type); + if (tag == DW_TAG_subrange_type) + break; + } while (dwarf_siblingof(&die_type, &die_type)); + + if (tag != DW_TAG_subrange_type) + return FALSE; + + if (dwarf_attr(&die_type, DW_AT_upper_bound, &attr) == NULL) + return FALSE; + + if (dwarf_formudata(&attr, &upper_bound) < 0) + return FALSE; + + if (upper_bound < 0) + return FALSE; + + dwarf_info.array_length = upper_bound + 1; + + return TRUE; +} + +static int +check_array_type(Dwarf_Die *die) +{ + int tag; + Dwarf_Die die_type; + + if (!get_die_type(die, &die_type)) { + ERRMSG("Can't get CU die of DW_AT_type.\n"); + return FALSE; + } + tag = dwarf_tag(&die_type); + if (tag == DW_TAG_array_type) + dwarf_info.array_length = FOUND_ARRAY_TYPE; + + return TRUE; +} + +static int +get_dwarf_base_type(Dwarf_Die *die) +{ + int tag; + const char *name; + + while (get_die_type(die, die)) { + tag = dwarf_tag(die); + switch (tag) { + case DW_TAG_array_type: + dwarf_info.type_flag |= TYPE_ARRAY; + break; + case DW_TAG_pointer_type: + dwarf_info.type_flag |= TYPE_PTR; + break; + case DW_TAG_structure_type: + dwarf_info.type_flag |= TYPE_STRUCT; + break; + case DW_TAG_base_type: + dwarf_info.type_flag |= TYPE_BASE; + break; + } + } + + name = dwarf_diename(die); + if (name) + dwarf_info.type_name = strdup(name); + else if (dwarf_info.type_flag == TYPE_PTR) + dwarf_info.type_name = strdup("void"); + + dwarf_info.struct_size = dwarf_bytesize(die); + + return TRUE; +} + +/* + * Get the die, given the offset + */ +static int +get_die_from_offset(Dwarf_Off offset, Dwarf_Die *die) +{ + if (!init_dwarf_info()) + return FALSE; + + if ((!offset) || (!die)) + return FALSE; + + if (!dwarf_offdie(dwarf_info.dwarfd, offset, die)) { + ERRMSG("Can't find the DIE.\n"); + return FALSE; + } + + return TRUE; +} + +/* + * Function for searching struct page.union.struct.mapping. + */ +static int +is_container(Dwarf_Die *die) +{ + if (dwarf_tag(die) == DW_TAG_structure_type) + return TRUE; + if (dwarf_info.cmd != DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION + && dwarf_tag(die) == DW_TAG_union_type) + return TRUE; + return FALSE; +} + +static void +adjust_member_offset(Dwarf_Die *die) +{ + long offset; + + if (dwarf_info.member_offset == NOT_FOUND_STRUCTURE) + return; + if (!get_data_member_location(die, &offset)) + return; + dwarf_info.member_offset += offset; +} + +static int +search_member(Dwarf_Die *die) +{ + int tag; + long offset; + const char *name; + Dwarf_Die child, *walker, die_type; + + if (dwarf_child(die, &child) != 0) + return FALSE; + + walker = &child; + + do { + tag = dwarf_tag(walker); + name = dwarf_diename(walker); + + if (tag != DW_TAG_member) + continue; + + /* + * Descend into structures/unions and search for member + * there. + */ + if ((!name) || (strcmp(name, dwarf_info.member_name) != 0)) { + if (!get_die_type(walker, &die_type)) + continue; + if (is_container(&die_type)) + if (search_member(&die_type)) { + adjust_member_offset(walker); + return TRUE; + } + } + + switch (dwarf_info.cmd) { + case DWARF_INFO_GET_MEMBER_TYPE: + if ((!name) || strcmp(name, dwarf_info.member_name)) + continue; + /* + * Get the member offset. + */ + if (!get_dwarf_base_type(walker)) + continue; + return TRUE; + case DWARF_INFO_GET_MEMBER_OFFSET: + if ((!name) || strcmp(name, dwarf_info.member_name)) + continue; + /* + * Get the member offset. + */ + if (dwarf_tag(die) == DW_TAG_union_type) + offset = 0; + else if (!get_data_member_location(walker, &offset)) + continue; + dwarf_info.member_offset = offset; + return TRUE; + case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION: + if (!get_die_type(walker, &die_type)) + continue; + if (dwarf_tag(&die_type) != DW_TAG_union_type) + continue; + /* + * Get the member offset. + */ + if (!get_data_member_location(walker, &offset)) + continue; + dwarf_info.member_offset = offset; + return TRUE; + case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: + if ((!name) || strcmp(name, dwarf_info.member_name)) + continue; + /* + * Get the member length. + */ + if (!get_data_array_length(walker)) + continue; + return TRUE; + } + } while (!dwarf_siblingof(walker, walker)); + + /* + * Return even if not found. + */ + return FALSE; +} + +static void +search_structure(Dwarf_Die *die, int *found) +{ + int tag; + const char *name; + + /* + * If we get to here then we don't have any more + * children, check to see if this is a relevant tag + */ + do { + tag = dwarf_tag(die); + name = dwarf_diename(die); + if ((tag != DW_TAG_structure_type) || (!name) + || strcmp(name, dwarf_info.struct_name)) + continue; + /* + * Skip if DW_AT_byte_size is not included. + */ + dwarf_info.struct_size = dwarf_bytesize(die); + + if (dwarf_info.struct_size > 0) + break; + + } while (!dwarf_siblingof(die, die)); + + if (dwarf_info.struct_size <= 0) { + /* + * Not found the demanded structure. + */ + return; + } + + /* + * Found the demanded structure. + */ + *found = TRUE; + switch (dwarf_info.cmd) { + case DWARF_INFO_GET_STRUCT_SIZE: + break; + case DWARF_INFO_GET_MEMBER_TYPE: + case DWARF_INFO_GET_MEMBER_OFFSET: + case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION: + case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: + search_member(die); + break; + } +} + +static void +search_number(Dwarf_Die *die, int *found) +{ + int tag, bytesize; + Dwarf_Word const_value; + Dwarf_Attribute attr; + Dwarf_Die child, *walker; + const char *name; + + do { + tag = dwarf_tag(die); + if (tag != DW_TAG_enumeration_type) + continue; + + if (dwarf_info.cmd == DWARF_INFO_GET_ENUMERATION_TYPE_SIZE) { + name = dwarf_diename(die); + + if (!name || strcmp(name, dwarf_info.struct_name)) + continue; + + if ((bytesize = dwarf_bytesize(die)) <= 0) + continue; + + *found = TRUE; + + dwarf_info.struct_size = bytesize; + + return; + } + + if (dwarf_child(die, &child) != 0) + continue; + + walker = &child; + + do { + tag = dwarf_tag(walker); + name = dwarf_diename(walker); + + if ((tag != DW_TAG_enumerator) || (!name) + || strcmp(name, dwarf_info.enum_name)) + continue; + + if (!dwarf_attr(walker, DW_AT_const_value, &attr)) + continue; + + if (dwarf_formudata(&attr, &const_value) < 0) + continue; + + *found = TRUE; + dwarf_info.enum_number = (long)const_value; + + } while (!dwarf_siblingof(walker, walker)); + + } while (!dwarf_siblingof(die, die)); +} + +static void +search_typedef(Dwarf_Die *die, int *found) +{ + int tag = 0; + char *src_name = NULL; + const char *name; + Dwarf_Die die_type; + + /* + * If we get to here then we don't have any more + * children, check to see if this is a relevant tag + */ + do { + tag = dwarf_tag(die); + name = dwarf_diename(die); + + if ((tag != DW_TAG_typedef) || (!name) + || strcmp(name, dwarf_info.struct_name)) + continue; + + if (dwarf_info.cmd == DWARF_INFO_GET_TYPEDEF_SIZE) { + if (!get_die_type(die, &die_type)) { + ERRMSG("Can't get CU die of DW_AT_type.\n"); + break; + } + dwarf_info.struct_size = dwarf_bytesize(&die_type); + if (dwarf_info.struct_size <= 0) + continue; + + *found = TRUE; + break; + } else if (dwarf_info.cmd == DWARF_INFO_GET_TYPEDEF_SRCNAME) { + src_name = (char *)dwarf_decl_file(die); + if (!src_name) + continue; + + *found = TRUE; + strncpy(dwarf_info.src_name, src_name, LEN_SRCFILE); + break; + } + } while (!dwarf_siblingof(die, die)); +} + +static void +search_symbol(Dwarf_Die *die, int *found) +{ + int tag; + const char *name; + + /* + * If we get to here then we don't have any more + * children, check to see if this is a relevant tag + */ + do { + tag = dwarf_tag(die); + name = dwarf_diename(die); + + if ((tag == DW_TAG_variable) && (name) + && !strcmp(name, dwarf_info.symbol_name)) + break; + + } while (!dwarf_siblingof(die, die)); + + if ((tag != DW_TAG_variable) || (!name) + || strcmp(name, dwarf_info.symbol_name)) { + /* + * Not found the demanded symbol. + */ + return; + } + + /* + * Found the demanded symbol. + */ + *found = TRUE; + switch (dwarf_info.cmd) { + case DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH: + get_data_array_length(die); + break; + case DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE: + check_array_type(die); + break; + case DWARF_INFO_GET_SYMBOL_TYPE: + get_dwarf_base_type(die); + break; + } +} + +static void +search_domain(Dwarf_Die *die, int *found) +{ + int tag; + const char *name; + short flag = 0; + Dwarf_Die die_type; + + do { + tag = dwarf_tag(die); + name = dwarf_diename(die); + + /* + * Descend into members and search for the + * needed domain there. + */ + if ((!name) || strcmp(name, dwarf_info.symbol_name)) { + if (!get_die_type(die, &die_type)) + continue; + + if (is_container(&die_type)) { + Dwarf_Die child; + + if (dwarf_child(&die_type, &child) != 0) + continue; + + search_domain(&child, found); + + if (*found) + return; + } + } + + if ((!name) || strcmp(name, dwarf_info.symbol_name)) + continue; + + switch (dwarf_info.cmd) { + case DWARF_INFO_GET_DOMAIN_STRUCT: + if (tag == DW_TAG_structure_type) + flag = 1; + break; + case DWARF_INFO_GET_DOMAIN_UNION: + if (tag == DW_TAG_union_type) + flag = 1; + break; + case DWARF_INFO_GET_DOMAIN_TYPEDEF: + if (tag == DW_TAG_typedef) + flag = 1; + break; + /* TODO + * Implement functionality for the rest of the domains + */ + } + + if (!flag) + continue; + + dwarf_info.struct_size = dwarf_bytesize(die); + + if (dwarf_info.struct_size > 0) { + if (found) + *found = TRUE; + dwarf_info.die_offset = dwarf_dieoffset(die); + break; + } + } while (!dwarf_siblingof(die, die)); +} + +static void +search_die(Dwarf_Die *die, int *found) +{ + const char *name; + + do { + name = dwarf_diename(die); + + if ((!name) || strcmp(name, dwarf_info.symbol_name)) + continue; + + if (found) + *found = TRUE; + + dwarf_info.die_offset = dwarf_dieoffset(die); + return; + } while (!dwarf_siblingof(die, die)); +} + +static void +search_die_tree(Dwarf_Die *die, int *found) +{ + Dwarf_Die child; + + /* + * start by looking at the children + */ + if (dwarf_child(die, &child) == 0) + search_die_tree(&child, found); + + if (*found) + return; + + if (is_search_structure(dwarf_info.cmd)) + search_structure(die, found); + + else if (is_search_number(dwarf_info.cmd)) + search_number(die, found); + + else if (is_search_symbol(dwarf_info.cmd)) + search_symbol(die, found); + + else if (is_search_typedef(dwarf_info.cmd)) + search_typedef(die, found); + + else if (is_search_domain(dwarf_info.cmd)) + search_domain(die, found); + + else if (is_search_die(dwarf_info.cmd)) + search_die(die, found); +} + +static int +get_debug_info(void) +{ + int found = FALSE; + char *name = NULL; + size_t shstrndx, header_size; + uint8_t address_size, offset_size; + Dwarf *dwarfd = NULL; + Elf *elfd = NULL; + Dwarf_Off off = 0, next_off = 0, abbrev_offset = 0; + Elf_Scn *scn = NULL; + GElf_Shdr scnhdr_mem, *scnhdr = NULL; + Dwarf_Die cu_die; + + int ret = FALSE; + + if (!init_dwarf_info()) + return FALSE; + + elfd = dwarf_info.elfd; + dwarfd = dwarf_info.dwarfd; + + if (elf_getshstrndx(elfd, &shstrndx) < 0) { + ERRMSG("Can't get the section index of the string table.\n"); + goto out; + } + + /* + * Search for ".debug_info" section. + */ + while ((scn = elf_nextscn(elfd, scn)) != NULL) { + scnhdr = gelf_getshdr(scn, &scnhdr_mem); + name = elf_strptr(elfd, shstrndx, scnhdr->sh_name); + if (!strcmp(name, ".debug_info")) + break; + } + if (strcmp(name, ".debug_info")) { + ERRMSG("Can't get .debug_info section.\n"); + goto out; + } + + /* + * Search by each CompileUnit. + */ + while (dwarf_nextcu(dwarfd, off, &next_off, &header_size, + &abbrev_offset, &address_size, &offset_size) == 0) { + off += header_size; + if (dwarf_offdie(dwarfd, off, &cu_die) == NULL) { + ERRMSG("Can't get CU die.\n"); + goto out; + } + search_die_tree(&cu_die, &found); + if (found) + break; + off = next_off; + } + ret = TRUE; +out: + clean_dwfl_info(); + + return ret; +} + + +/* + * External functions. + */ +char * +get_dwarf_module_name(void) +{ + return dwarf_info.module_name; +} + +void +get_fileinfo_of_debuginfo(int *fd, char **name) +{ + *fd = dwarf_info.fd_debuginfo; + *name = dwarf_info.name_debuginfo; +} + +unsigned long long +get_symbol_addr(char *symname) +{ + int i; + unsigned long long symbol = NOT_FOUND_SYMBOL; + Elf *elfd = NULL; + GElf_Shdr shdr; + GElf_Sym sym; + Elf_Data *data = NULL; + Elf_Scn *scn = NULL; + char *sym_name = NULL; + + if (!init_dwarf_info()) + return NOT_FOUND_SYMBOL; + + elfd = dwarf_info.elfd; + + while ((scn = elf_nextscn(elfd, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) == NULL) { + ERRMSG("Can't get section header.\n"); + goto out; + } + if (shdr.sh_type == SHT_SYMTAB) + break; + } + if (!scn) { + ERRMSG("Can't find symbol table.\n"); + goto out; + } + + data = elf_getdata(scn, data); + + if ((!data) || (data->d_size == 0)) { + ERRMSG("No data in symbol table.\n"); + goto out; + } + + for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) { + if (gelf_getsym(data, i, &sym) == NULL) { + ERRMSG("Can't get symbol at index %d.\n", i); + goto out; + } + sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name); + + if (sym_name == NULL) + continue; + + if (!strcmp(sym_name, symname)) { + symbol = sym.st_value; + break; + } + } +out: + clean_dwfl_info(); + + return symbol; +} + +unsigned long +get_next_symbol_addr(char *symname) +{ + int i; + unsigned long symbol = NOT_FOUND_SYMBOL; + unsigned long next_symbol = NOT_FOUND_SYMBOL; + Elf *elfd = NULL; + GElf_Shdr shdr; + GElf_Sym sym; + Elf_Data *data = NULL; + Elf_Scn *scn = NULL; + char *sym_name = NULL; + + if (!init_dwarf_info()) + return NOT_FOUND_SYMBOL; + + elfd = dwarf_info.elfd; + + while ((scn = elf_nextscn(elfd, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) == NULL) { + ERRMSG("Can't get section header.\n"); + goto out; + } + if (shdr.sh_type == SHT_SYMTAB) + break; + } + if (!scn) { + ERRMSG("Can't find symbol table.\n"); + goto out; + } + + data = elf_getdata(scn, data); + + if ((!data) || (data->d_size == 0)) { + ERRMSG("No data in symbol table.\n"); + goto out; + } + + for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) { + if (gelf_getsym(data, i, &sym) == NULL) { + ERRMSG("Can't get symbol at index %d.\n", i); + goto out; + } + sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name); + + if (sym_name == NULL) + continue; + + if (!strcmp(sym_name, symname)) { + symbol = sym.st_value; + break; + } + } + + if (symbol == NOT_FOUND_SYMBOL) + goto out; + + /* + * Search for next symbol. + */ + for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) { + if (gelf_getsym(data, i, &sym) == NULL) { + ERRMSG("Can't get symbol at index %d.\n", i); + goto out; + } + sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name); + + if (sym_name == NULL) + continue; + + if (symbol < sym.st_value) { + if (next_symbol == NOT_FOUND_SYMBOL) + next_symbol = sym.st_value; + + else if (sym.st_value < next_symbol) + next_symbol = sym.st_value; + } + } +out: + clean_dwfl_info(); + + return next_symbol; +} + +/* + * Get the size of structure. + */ +long +get_structure_size(char *structname, int flag_typedef) +{ + if (flag_typedef) + dwarf_info.cmd = DWARF_INFO_GET_TYPEDEF_SIZE; + else + dwarf_info.cmd = DWARF_INFO_GET_STRUCT_SIZE; + + dwarf_info.struct_name = structname; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + + if (!get_debug_info()) + return FAILED_DWARFINFO; + + return dwarf_info.struct_size; +} + +/* + * Get the size of pointer. + */ +long +get_pointer_size(void) +{ + return sizeof(void *); +} + +/* + * Get the type of given symbol. + */ +char * +get_symbol_type_name(char *symname, int cmd, long *size, + unsigned long *flag) +{ + dwarf_info.cmd = cmd; + dwarf_info.symbol_name = symname; + dwarf_info.type_name = NULL; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + dwarf_info.type_flag = 0; + + if (!get_debug_info()) + return NULL; + + if (size) + *size = dwarf_info.struct_size; + + if (flag) + *flag = dwarf_info.type_flag; + + return dwarf_info.type_name; +} + +/* + * Get the offset of member. + */ +long +get_member_offset(char *structname, char *membername, int cmd) +{ + dwarf_info.cmd = cmd; + dwarf_info.struct_name = structname; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + dwarf_info.member_offset = NOT_FOUND_STRUCTURE; + + /* + * When searching a offset of 1st union, member_name is unnecessary. + */ + if (dwarf_info.cmd == DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION) + dwarf_info.member_name = ""; + else + dwarf_info.member_name = membername; + + if (!get_debug_info()) + return FAILED_DWARFINFO; + + return dwarf_info.member_offset; +} + +/* + * Get the type name and size of member. + */ +char * +get_member_type_name(char *structname, char *membername, int cmd, long *size, + unsigned long *flag) +{ + dwarf_info.cmd = cmd; + dwarf_info.struct_name = structname; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + dwarf_info.member_name = membername; + dwarf_info.type_name = NULL; + dwarf_info.type_flag = 0; + + if (!get_debug_info()) + return NULL; + + if (dwarf_info.struct_size == NOT_FOUND_STRUCTURE) + return NULL; + + if (size) + *size = dwarf_info.struct_size; + + if (flag) + *flag = dwarf_info.type_flag; + + return dwarf_info.type_name; +} + +/* + * Get the length of array. + */ +long +get_array_length(char *name01, char *name02, unsigned int cmd) +{ + switch (cmd) { + case DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH: + dwarf_info.symbol_name = name01; + break; + case DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE: + dwarf_info.symbol_name = name01; + break; + case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: + dwarf_info.struct_name = name01; + dwarf_info.member_name = name02; + break; + } + dwarf_info.cmd = cmd; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + dwarf_info.member_offset = NOT_FOUND_STRUCTURE; + dwarf_info.array_length = NOT_FOUND_STRUCTURE; + + if (!get_debug_info()) + return FAILED_DWARFINFO; + + return dwarf_info.array_length; +} + +long +get_enum_number(char *enum_name) +{ + dwarf_info.cmd = DWARF_INFO_GET_ENUM_NUMBER; + dwarf_info.enum_name = enum_name; + dwarf_info.enum_number = NOT_FOUND_NUMBER; + + if (!get_debug_info()) + return FAILED_DWARFINFO; + + return dwarf_info.enum_number; +} + +/* + * Get the source filename. + */ +int +get_source_filename(char *structname, char *src_name, int cmd) +{ + dwarf_info.cmd = cmd; + dwarf_info.struct_name = structname; + + if (!get_debug_info()) + return FALSE; + + strncpy(src_name, dwarf_info.src_name, LEN_SRCFILE); + + return TRUE; +} + +/* + * Get the domain information of the symbol + */ +long +get_domain(char *symname, int cmd, unsigned long long *die) +{ + dwarf_info.cmd = cmd; + dwarf_info.symbol_name = symname; + dwarf_info.type_name = NULL; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + dwarf_info.die_offset = 0; + + if (!get_debug_info()) + return 0; + + if (die) + *die = (unsigned long long) dwarf_info.die_offset; + + return dwarf_info.struct_size; +} + +/* + * Get the number of fields in a structure or union provided the + * die offset of the structure or union + */ +int +get_die_nfields(unsigned long long die_off) +{ + int tag, nfields = 0; + Dwarf_Die result, child, *die; + + if (!get_die_from_offset((Dwarf_Off) die_off, &result)) { + ERRMSG("Can't find the DIE.\n"); + return -1; + } + + die = &result; + tag = dwarf_tag(die); + if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { + ERRMSG("DIE is not of structure or union type.\n"); + return -1; + } + + if (dwarf_child(die, &child) != 0) + return -1; + + /* Find the number of fields in the structure */ + die = &child; + do { + tag = dwarf_tag(die); + if (tag == DW_TAG_member) + nfields++; + else + continue; + } while (!dwarf_siblingof(die, die)); + + return nfields; +} + +/* + * Get the information of the structure member given by index + */ +int +get_die_member(unsigned long long die_off, int index, long *offset, + char **name, int *nbits, int *fbits, unsigned long long *m_die) +{ + int tag, size, nfields = 0; + Dwarf_Die result, child, die_base, *die; + + if (!offset || !nbits || !fbits || !name || !m_die) + return -1; + + if (!get_die_from_offset((Dwarf_Off) die_off, &result)) { + ERRMSG("Can't find the DIE.\n"); + return -1; + } + + die = &result; + tag = dwarf_tag(die); + if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { + ERRMSG("DIE is not of structure or union type.\n"); + return -1; + } + + if (dwarf_child(die, &child) != 0) + return -1; + + /* Find the correct field in the structure */ + die = &child; + do { + tag = dwarf_tag(die); + if (tag == DW_TAG_member) { + if (nfields == index) + break; + else + nfields++; + } + } while (!dwarf_siblingof(die, die)); + + if (nfields != index) { + ERRMSG("No member found at index %d.\n", index); + return -1; + } + + /* Fill in the required info for the member */ + if (!get_data_member_location(die, offset)) + *offset = 0; + + *name = dwarf_diename(die); + *m_die = dwarf_dieoffset(die); + + get_die_type(die, &die_base); + if (dwarf_tag(&die_base) == DW_TAG_array_type) { + dwarf_info.array_length = 0; + get_data_array_length(die); + size = dwarf_info.array_length; + } else { + size = dwarf_bytesize(&die_base); + } + + /* TODO + * Correctly update fbits and nbits + */ + *nbits = *fbits = 0; + + if (size < 0) + return 0; + else + return size; +} + +/* + * Get the die attribute type + */ +int +get_die_attr_type(unsigned long long die_off, int *type_flag, + unsigned long long *die_attr_off) +{ + Dwarf_Die result; + + if (!die_attr_off) + return FALSE; + + if (!get_die_from_offset((Dwarf_Off) die_off, &result)) { + ERRMSG("Can't find the DIE.\n"); + return FALSE; + } + + if (!get_die_type(&result, &result)) + return FALSE; + + *die_attr_off = dwarf_dieoffset(&result); + *type_flag = dwarf_tag(&result); + return TRUE; +} + +/* + * Get name attribute given the die offset + */ +char * +get_die_name(unsigned long long die_off) +{ + Dwarf_Die result; + + if (!die_off) + return NULL; + + if (!get_die_from_offset((Dwarf_Off) die_off, &result)) { + ERRMSG("Can't find the DIE.\n"); + return NULL; + } + + return dwarf_diename(&result); +} + +/* + * Get the die offset given the die name + */ +unsigned long long +get_die_offset(char *sysname) +{ + dwarf_info.cmd = DWARF_INFO_GET_DIE; + dwarf_info.symbol_name = sysname; + dwarf_info.type_name = NULL; + dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + dwarf_info.die_offset = 0; + + if (!sysname) + return 0; + + if (!get_debug_info()) + return 0; + + return (unsigned long long)dwarf_info.die_offset; +} + +/* + * Get length attribute given the die offset + */ +int +get_die_length(unsigned long long die_off, int flag) +{ + Dwarf_Die result, die_base; + + if (!die_off) + return FALSE; + + if (!get_die_from_offset((Dwarf_Off) die_off, &result)) { + ERRMSG("Can't find the DIE.\n"); + return FALSE; + } + + if (flag) + return dwarf_bytesize(&result); + + get_die_type(&result, &die_base); + if (dwarf_tag(&die_base) == DW_TAG_array_type) { + dwarf_info.array_length = 0; + get_data_array_length(&result); + return dwarf_info.array_length; + } else { + return dwarf_bytesize(&die_base); + } +} + +/* + * Set the dwarf_info with kernel/module debuginfo file information. + */ +int +set_dwarf_debuginfo(char *mod_name, char *os_release, + char *name_debuginfo, int fd_debuginfo) +{ + if (!mod_name) + return FALSE; + if (dwarf_info.module_name && !strcmp(dwarf_info.module_name, mod_name)) + return TRUE; + + /* Switching to different module. + * + * Close the file descriptor if previous module is != kernel and + * xen-syms. The reason is, vmlinux file will always be supplied + * by user and code to open/close kernel debuginfo file already + * in place. The module debuginfo files are opened only if '--config' + * option is used. This helps not to break the existing functionlity + * if called without '--config' option. + */ + + if (dwarf_info.module_name + && strcmp(dwarf_info.module_name, "vmlinux") + && strcmp(dwarf_info.module_name, "xen-syms")) { + if (dwarf_info.fd_debuginfo > 0) + close(dwarf_info.fd_debuginfo); + if (dwarf_info.name_debuginfo) + free(dwarf_info.name_debuginfo); + } + if (dwarf_info.module_name) + free(dwarf_info.module_name); + + dwarf_info.fd_debuginfo = fd_debuginfo; + dwarf_info.name_debuginfo = name_debuginfo; + dwarf_info.module_name = strdup(mod_name); + + if (!strcmp(dwarf_info.module_name, "vmlinux") || + !strcmp(dwarf_info.module_name, "xen-syms")) + return TRUE; + + /* check to see whether module debuginfo is available */ + return search_module_debuginfo(os_release); +} + diff -Nupr makedumpfile-1.3.5/dwarf_info.h makedumpfile-1.5.3/dwarf_info.h --- makedumpfile-1.3.5/dwarf_info.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/dwarf_info.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,85 @@ +/* + * dwarf_info.h + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _DWARF_INFO_H +#define _DWARF_INFO_H + +#define LEN_SRCFILE (100) + +#define NOT_FOUND_LONG_VALUE (-1) +#define FAILED_DWARFINFO (-2) +#define INVALID_STRUCTURE_DATA (-3) +#define FOUND_ARRAY_TYPE (LONG_MAX - 1) + +#define NOT_FOUND_SYMBOL (0) +#define NOT_FOUND_STRUCTURE (NOT_FOUND_LONG_VALUE) +#define NOT_FOUND_NUMBER (NOT_FOUND_LONG_VALUE) + +/* flags for dwarf_info.type_flag */ +#define TYPE_BASE 0x01 +#define TYPE_ARRAY 0x02 +#define TYPE_PTR 0x04 +#define TYPE_STRUCT 0x08 +#define TYPE_LIST_HEAD 0x10 + +enum { + DWARF_INFO_GET_STRUCT_SIZE, + DWARF_INFO_GET_MEMBER_OFFSET, + DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION, + DWARF_INFO_GET_MEMBER_ARRAY_LENGTH, + DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH, + DWARF_INFO_GET_TYPEDEF_SIZE, + DWARF_INFO_GET_TYPEDEF_SRCNAME, + DWARF_INFO_GET_ENUM_NUMBER, + DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE, + DWARF_INFO_GET_SYMBOL_TYPE, + DWARF_INFO_GET_MEMBER_TYPE, + DWARF_INFO_GET_ENUMERATION_TYPE_SIZE, + DWARF_INFO_GET_DOMAIN_STRUCT, + DWARF_INFO_GET_DOMAIN_TYPEDEF, + DWARF_INFO_GET_DOMAIN_ARRAY, + DWARF_INFO_GET_DOMAIN_UNION, + DWARF_INFO_GET_DOMAIN_ENUM, + DWARF_INFO_GET_DOMAIN_REF, + DWARF_INFO_GET_DOMAIN_STRING, + DWARF_INFO_GET_DOMAIN_BASE, + DWARF_INFO_GET_DIE, +}; + +char *get_dwarf_module_name(void); +void get_fileinfo_of_debuginfo(int *fd, char **name); +unsigned long long get_symbol_addr(char *symname); +unsigned long get_next_symbol_addr(char *symname); +long get_structure_size(char *structname, int flag_typedef); +long get_pointer_size(void); +char *get_symbol_type_name(char *symname, int cmd, long *size, unsigned long *flag); +long get_member_offset(char *structname, char *membername, int cmd); +char *get_member_type_name(char *structname, char *membername, int cmd, long *size, unsigned long *flag); +long get_array_length(char *name01, char *name02, unsigned int cmd); +long get_enum_number(char *enum_name); +int get_source_filename(char *structname, char *src_name, int cmd); +long get_domain(char *symname, int cmd, unsigned long long *die); +int get_die_nfields(unsigned long long die_off); +int get_die_member(unsigned long long die_off, int index, long *offset, + char **name, int *nbits, int *fbits, unsigned long long *m_die); +int get_die_attr_type(unsigned long long die_off, int *type_flag, + unsigned long long *die_attr_off); +char *get_die_name(unsigned long long die_off); +unsigned long long get_die_offset(char *sysname); +int get_die_length(unsigned long long die_off, int flag); +int set_dwarf_debuginfo(char *mod_name, char *os_release, char *name_debuginfo, int fd_debuginfo); + +#endif /* DWARF_INFO_H */ + diff -Nupr makedumpfile-1.3.5/elf_info.c makedumpfile-1.5.3/elf_info.c --- makedumpfile-1.3.5/elf_info.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/elf_info.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,844 @@ +/* + * elf_info.c + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "print_info.h" +#include "elf_info.h" +#include "makedumpfile.h" + +#define ELF32 (1) +#define ELF64 (2) + +#define VMCOREINFO_NOTE_NAME "VMCOREINFO" +#define VMCOREINFO_NOTE_NAME_BYTES (sizeof(VMCOREINFO_NOTE_NAME)) +#define VMCOREINFO_XEN_NOTE_NAME "VMCOREINFO_XEN" +#define VMCOREINFO_XEN_NOTE_NAME_BYTES (sizeof(VMCOREINFO_XEN_NOTE_NAME)) + +#define XEN_ELFNOTE_CRASH_INFO (0x1000001) + +struct pt_load_segment { + off_t file_offset; + unsigned long long phys_start; + unsigned long long phys_end; + unsigned long long virt_start; + unsigned long long virt_end; +}; + +static int nr_cpus; /* number of cpu */ + +/* + * File information about /proc/vmcore: + */ +static int fd_memory; +static char *name_memory; + +static int flags_memory; +#define MEMORY_ELF64 (1 << 0) +#define MEMORY_XEN (1 << 1) + +/* + * PT_LOAD information about /proc/vmcore: + */ +static unsigned int num_pt_loads; +static struct pt_load_segment *pt_loads; +static off_t offset_pt_load_memory; + +/* + * PT_NOTE information about /proc/vmcore: + */ +static off_t offset_pt_note_memory; +static unsigned long size_pt_note_memory; + +/* + * vmcoreinfo in /proc/vmcore: + */ +static off_t offset_vmcoreinfo; +static unsigned long size_vmcoreinfo; +static off_t offset_vmcoreinfo_xen; +static unsigned long size_vmcoreinfo_xen; + +/* + * erased information in /proc/vmcore: + */ +static off_t offset_eraseinfo; +static unsigned long size_eraseinfo; + +/* + * Xen information: + */ +static off_t offset_xen_crash_info; +static unsigned long size_xen_crash_info; + + +/* + * Internal functions. + */ +static int +get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr) +{ + off_t offset; + + offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * index; + + if (lseek(fd, offset, SEEK_SET) < 0) { + ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (read(fd, phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) { + ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); + return FALSE; + } + return TRUE; +} + +static int +get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr) +{ + off_t offset; + + offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * index; + + if (lseek(fd, offset, SEEK_SET) < 0) { + ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (read(fd, phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)) { + ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); + return FALSE; + } + return TRUE; +} + +static int +check_elf_format(int fd, char *filename, int *phnum, unsigned int *num_load) +{ + int i; + Elf64_Ehdr ehdr64; + Elf64_Phdr load64; + Elf32_Ehdr ehdr32; + Elf32_Phdr load32; + + if (lseek(fd, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (read(fd, &ehdr64, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) { + ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (lseek(fd, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (read(fd, &ehdr32, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)) { + ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); + return FALSE; + } + (*num_load) = 0; + if ((ehdr64.e_ident[EI_CLASS] == ELFCLASS64) + && (ehdr32.e_ident[EI_CLASS] != ELFCLASS32)) { + (*phnum) = ehdr64.e_phnum; + for (i = 0; i < ehdr64.e_phnum; i++) { + if (!get_elf64_phdr(fd, filename, i, &load64)) { + ERRMSG("Can't find Phdr %d.\n", i); + return FALSE; + } + if (load64.p_type == PT_LOAD) + (*num_load)++; + } + return ELF64; + + } else if ((ehdr64.e_ident[EI_CLASS] != ELFCLASS64) + && (ehdr32.e_ident[EI_CLASS] == ELFCLASS32)) { + (*phnum) = ehdr32.e_phnum; + for (i = 0; i < ehdr32.e_phnum; i++) { + if (!get_elf32_phdr(fd, filename, i, &load32)) { + ERRMSG("Can't find Phdr %d.\n", i); + return FALSE; + } + if (load32.p_type == PT_LOAD) + (*num_load)++; + } + return ELF32; + } + ERRMSG("Can't get valid ehdr.\n"); + return FALSE; +} + +static int +dump_Elf_load(Elf64_Phdr *prog, int num_load) +{ + struct pt_load_segment *pls; + + if (prog->p_type != PT_LOAD) { + ERRMSG("Not PT_LOAD.\n"); + return FALSE; + } + + pls = &pt_loads[num_load]; + pls->phys_start = prog->p_paddr; + pls->phys_end = pls->phys_start + prog->p_filesz; + pls->virt_start = prog->p_vaddr; + pls->virt_end = pls->virt_start + prog->p_filesz; + pls->file_offset = prog->p_offset; + + DEBUG_MSG("LOAD (%d)\n", num_load); + 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; +} + +static off_t +offset_next_note(void *note) +{ + off_t offset; + Elf64_Nhdr *note64; + Elf32_Nhdr *note32; + + /* + * Both name and desc in ELF Note elements are padded to + * 4 byte boundary. + */ + if (is_elf64_memory()) { + note64 = (Elf64_Nhdr *)note; + offset = sizeof(Elf64_Nhdr) + + roundup(note64->n_namesz, 4) + + roundup(note64->n_descsz, 4); + } else { + note32 = (Elf32_Nhdr *)note; + offset = sizeof(Elf32_Nhdr) + + roundup(note32->n_namesz, 4) + + roundup(note32->n_descsz, 4); + } + return offset; +} + +static int +note_type(void *note) +{ + int type; + Elf64_Nhdr *note64; + Elf32_Nhdr *note32; + + if (is_elf64_memory()) { + note64 = (Elf64_Nhdr *)note; + type = note64->n_type; + } else { + note32 = (Elf32_Nhdr *)note; + type = note32->n_type; + } + return type; +} + +static int +note_descsz(void *note) +{ + int size; + Elf64_Nhdr *note64; + Elf32_Nhdr *note32; + + if (is_elf64_memory()) { + note64 = (Elf64_Nhdr *)note; + size = note64->n_descsz; + } else { + note32 = (Elf32_Nhdr *)note; + size = note32->n_descsz; + } + return size; +} + +static off_t +offset_note_desc(void *note) +{ + off_t offset; + Elf64_Nhdr *note64; + Elf32_Nhdr *note32; + + if (is_elf64_memory()) { + note64 = (Elf64_Nhdr *)note; + offset = sizeof(Elf64_Nhdr) + roundup(note64->n_namesz, 4); + } else { + note32 = (Elf32_Nhdr *)note; + offset = sizeof(Elf32_Nhdr) + roundup(note32->n_namesz, 4); + } + return offset; +} + +static int +get_pt_note_info(void) +{ + int n_type, size_desc; + off_t offset, offset_desc; + char buf[VMCOREINFO_XEN_NOTE_NAME_BYTES]; + char note[MAX_SIZE_NHDR]; + + nr_cpus = 0; + offset = offset_pt_note_memory; + while (offset < offset_pt_note_memory + size_pt_note_memory) { + if (lseek(fd_memory, offset, SEEK_SET) < 0) { + ERRMSG("Can't seek the dump memory(%s). %s\n", + name_memory, strerror(errno)); + return FALSE; + } + if (read(fd_memory, note, sizeof(note)) != sizeof(note)) { + ERRMSG("Can't read the dump memory(%s). %s\n", + name_memory, strerror(errno)); + return FALSE; + } + if (read(fd_memory, &buf, sizeof(buf)) != sizeof(buf)) { + ERRMSG("Can't read the dump memory(%s). %s\n", + name_memory, strerror(errno)); + return FALSE; + } + n_type = note_type(note); + + if (n_type == NT_PRSTATUS) { + nr_cpus++; + offset += offset_next_note(note); + continue; + } + offset_desc = offset + offset_note_desc(note); + size_desc = note_descsz(note); + + /* + * Check whether /proc/vmcore contains vmcoreinfo, + * and get both the offset and the size. + * + * NOTE: The owner name of xen should be checked at first, + * because its name is "VMCOREINFO_XEN" and the one + * of linux is "VMCOREINFO". + */ + if (!strncmp(VMCOREINFO_XEN_NOTE_NAME, buf, + VMCOREINFO_XEN_NOTE_NAME_BYTES)) { + offset_vmcoreinfo_xen = offset_desc; + size_vmcoreinfo_xen = size_desc; + } else if (!strncmp(VMCOREINFO_NOTE_NAME, buf, + VMCOREINFO_NOTE_NAME_BYTES)) { + set_vmcoreinfo(offset_desc, size_desc); + + /* + * Check whether /proc/vmcore contains xen's note. + */ + } else if (n_type == XEN_ELFNOTE_CRASH_INFO) { + flags_memory |= MEMORY_XEN; + offset_xen_crash_info = offset_desc; + size_xen_crash_info = size_desc; + + /* + * Check whether a source dumpfile contains eraseinfo. + * /proc/vmcore does not contain eraseinfo, because eraseinfo + * is added only by makedumpfile and makedumpfile does not + * create /proc/vmcore. + */ + } else if (!strncmp(ERASEINFO_NOTE_NAME, buf, + ERASEINFO_NOTE_NAME_BYTES)) { + set_eraseinfo(offset_desc, size_desc); + } + offset += offset_next_note(note); + } + if (is_xen_memory()) + DEBUG_MSG("Xen kdump\n"); + else + DEBUG_MSG("Linux kdump\n"); + + return TRUE; +} + + +/* + * External functions. + */ + +/* + * Convert Physical Address to File Offset. + * If this function returns 0x0, File Offset isn't found. + * The File Offset 0x0 is in the ELF header. + * It is not in the memory image. + */ +off_t +paddr_to_offset(unsigned long long paddr) +{ + int i; + off_t offset; + struct pt_load_segment *pls; + + for (i = offset = 0; i < num_pt_loads; i++) { + pls = &pt_loads[i]; + if ((paddr >= pls->phys_start) + && (paddr < pls->phys_end)) { + offset = (off_t)(paddr - pls->phys_start) + + pls->file_offset; + break; + } + } + return offset; +} + +/* + * Same as paddr_to_offset() but makes sure that the specified offset (hint) + * in the segment. + */ +off_t +paddr_to_offset2(unsigned long long paddr, off_t hint) +{ + int i; + off_t offset; + unsigned long long len; + struct pt_load_segment *pls; + + for (i = offset = 0; i < num_pt_loads; i++) { + pls = &pt_loads[i]; + len = pls->phys_end - pls->phys_start; + if ((paddr >= pls->phys_start) + && (paddr < pls->phys_end) + && (hint >= pls->file_offset) + && (hint < pls->file_offset + len)) { + offset = (off_t)(paddr - pls->phys_start) + + pls->file_offset; + break; + } + } + return offset; +} + +unsigned long long +vaddr_to_paddr_general(unsigned long long vaddr) +{ + int i; + unsigned long long paddr = NOT_PADDR; + struct pt_load_segment *pls; + + if (pt_loads == NULL) + return NOT_PADDR; + + for (i = 0; i < num_pt_loads; i++) { + pls = &pt_loads[i]; + if ((vaddr >= pls->virt_start) + && (vaddr < pls->virt_end)) { + paddr = (off_t)(vaddr - pls->virt_start) + + pls->phys_start; + break; + } + } + return paddr; +} + +/* + * This function is slow because it doesn't use the memory. + * It is useful at few calls like get_str_osrelease_from_vmlinux(). + */ +off_t +vaddr_to_offset_slow(int fd, char *filename, unsigned long long vaddr) +{ + off_t offset = 0; + int i, phnum, flag_elf64, elf_format; + unsigned int num_load; + Elf64_Phdr load64; + Elf32_Phdr load32; + + elf_format = check_elf_format(fd, filename, &phnum, &num_load); + if (elf_format == ELF64) + flag_elf64 = TRUE; + else if (elf_format == ELF32) + flag_elf64 = FALSE; + else + return 0; + + for (i = 0; i < phnum; i++) { + if (flag_elf64) { /* ELF64 */ + if (!get_elf64_phdr(fd, filename, i, &load64)) { + ERRMSG("Can't find Phdr %d.\n", i); + return 0; + } + if (load64.p_type != PT_LOAD) + continue; + + if ((vaddr < load64.p_vaddr) + || (load64.p_vaddr + load64.p_filesz <= vaddr)) + continue; + + offset = load64.p_offset + (vaddr - load64.p_vaddr); + break; + } else { /* ELF32 */ + if (!get_elf32_phdr(fd, filename, i, &load32)) { + ERRMSG("Can't find Phdr %d.\n", i); + return 0; + } + if (load32.p_type != PT_LOAD) + continue; + + if ((vaddr < load32.p_vaddr) + || (load32.p_vaddr + load32.p_filesz <= vaddr)) + continue; + + offset = load32.p_offset + (vaddr - load32.p_vaddr); + break; + } + } + return offset; +} + +unsigned long long +get_max_paddr(void) +{ + int i; + unsigned long long max_paddr = 0; + struct pt_load_segment *pls; + + for (i = 0; i < num_pt_loads; i++) { + pls = &pt_loads[i]; + if (max_paddr < pls->phys_end) + max_paddr = pls->phys_end; + } + return max_paddr; +} + +int +get_elf64_ehdr(int fd, char *filename, Elf64_Ehdr *ehdr) +{ + if (lseek(fd, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (read(fd, ehdr, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) { + ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) { + ERRMSG("Can't get valid e_ident.\n"); + return FALSE; + } + return TRUE; +} + +int +get_elf32_ehdr(int fd, char *filename, Elf32_Ehdr *ehdr) +{ + if (lseek(fd, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (read(fd, ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)) { + ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); + return FALSE; + } + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { + ERRMSG("Can't get valid e_ident.\n"); + return FALSE; + } + return TRUE; +} + +/* + * Get ELF information about /proc/vmcore. + */ +int +get_elf_info(int fd, char *filename) +{ + int i, j, phnum, elf_format; + Elf64_Phdr phdr; + + /* + * Check ELF64 or ELF32. + */ + elf_format = check_elf_format(fd, filename, &phnum, &num_pt_loads); + if (elf_format == ELF64) + flags_memory |= MEMORY_ELF64; + else if (elf_format != ELF32) + return FALSE; + + if (!num_pt_loads) { + ERRMSG("Can't get the number of PT_LOAD.\n"); + return FALSE; + } + + /* + * The below file information will be used as /proc/vmcore. + */ + fd_memory = fd; + name_memory = filename; + + pt_loads = calloc(sizeof(struct pt_load_segment), num_pt_loads); + if (pt_loads == NULL) { + ERRMSG("Can't allocate memory for the PT_LOAD. %s\n", + strerror(errno)); + return FALSE; + } + for (i = 0, j = 0; i < phnum; i++) { + if (!get_phdr_memory(i, &phdr)) + return FALSE; + + if (phdr.p_type == PT_NOTE) { + set_pt_note(phdr.p_offset, phdr.p_filesz); + } + if (phdr.p_type != PT_LOAD) + continue; + + if (j == 0) { + offset_pt_load_memory = phdr.p_offset; + if (offset_pt_load_memory == 0) { + ERRMSG("Can't get the offset of page data.\n"); + return FALSE; + } + } + if (j >= num_pt_loads) + return FALSE; + if(!dump_Elf_load(&phdr, j)) + return FALSE; + j++; + } + if (!has_pt_note()) { + ERRMSG("Can't find PT_NOTE Phdr.\n"); + return FALSE; + } + if (!get_pt_note_info()) { + ERRMSG("Can't get PT_NOTE information.\n"); + return FALSE; + } + return TRUE; +} + +void +free_elf_info(void) +{ + free(pt_loads); + pt_loads = NULL; +} + +int +is_elf64_memory(void) +{ + return (flags_memory & MEMORY_ELF64); +} + +int +is_xen_memory(void) +{ + return (flags_memory & MEMORY_XEN); +} + +int +get_phnum_memory(void) +{ + int phnum; + Elf64_Ehdr ehdr64; + Elf32_Ehdr ehdr32; + + if (is_elf64_memory()) { /* ELF64 */ + if (!get_elf64_ehdr(fd_memory, name_memory, &ehdr64)) { + ERRMSG("Can't get ehdr64.\n"); + return FALSE; + } + phnum = ehdr64.e_phnum; + } else { /* ELF32 */ + if (!get_elf32_ehdr(fd_memory, name_memory, &ehdr32)) { + ERRMSG("Can't get ehdr32.\n"); + return FALSE; + } + phnum = ehdr32.e_phnum; + } + return phnum; +} + +int +get_phdr_memory(int index, Elf64_Phdr *phdr) +{ + Elf32_Phdr phdr32; + + if (is_elf64_memory()) { /* ELF64 */ + if (!get_elf64_phdr(fd_memory, name_memory, index, phdr)) { + ERRMSG("Can't find Phdr %d.\n", index); + return FALSE; + } + } else { + if (!get_elf32_phdr(fd_memory, name_memory, index, &phdr32)) { + ERRMSG("Can't find Phdr %d.\n", index); + return FALSE; + } + memset(phdr, 0, sizeof(Elf64_Phdr)); + phdr->p_type = phdr32.p_type; + phdr->p_flags = phdr32.p_flags; + phdr->p_offset = phdr32.p_offset; + phdr->p_vaddr = phdr32.p_vaddr; + phdr->p_paddr = phdr32.p_paddr; + phdr->p_filesz = phdr32.p_filesz; + phdr->p_memsz = phdr32.p_memsz; + phdr->p_align = phdr32.p_align; + } + return TRUE; +} + +off_t +get_offset_pt_load_memory(void) +{ + return offset_pt_load_memory; +} + +int +get_pt_load(int idx, + unsigned long long *phys_start, + unsigned long long *phys_end, + unsigned long long *virt_start, + unsigned long long *virt_end) +{ + struct pt_load_segment *pls; + + if (num_pt_loads <= idx) + return FALSE; + + pls = &pt_loads[idx]; + + if (phys_start) + *phys_start = pls->phys_start; + if (phys_end) + *phys_end = pls->phys_end; + if (virt_start) + *virt_start = pls->virt_start; + if (virt_end) + *virt_end = pls->virt_end; + + return TRUE; +} + +unsigned int +get_num_pt_loads(void) +{ + return num_pt_loads; +} + +void +set_nr_cpus(int num) +{ + nr_cpus = num; +} + +int +get_nr_cpus(void) +{ + return nr_cpus; +} + +int +has_pt_note(void) +{ + if (info->flag_sadump) { + if (size_pt_note_memory) + return TRUE; + } else if (offset_pt_note_memory && size_pt_note_memory) + return TRUE; + return FALSE; +} + +void +set_pt_note(off_t offset, unsigned long size) +{ + offset_pt_note_memory = offset; + size_pt_note_memory = size; +} + +void +get_pt_note(off_t *offset, unsigned long *size) +{ + if (offset) + *offset = offset_pt_note_memory; + if (size) + *size = size_pt_note_memory; +} + +int +has_vmcoreinfo(void) +{ + if (offset_vmcoreinfo && size_vmcoreinfo) + return TRUE; + return FALSE; +} + +void +set_vmcoreinfo(off_t offset, unsigned long size) +{ + offset_vmcoreinfo = offset; + size_vmcoreinfo = size; +} + +void +get_vmcoreinfo(off_t *offset, unsigned long *size) +{ + if (offset) + *offset = offset_vmcoreinfo; + if (size) + *size = size_vmcoreinfo; +} + +int +has_vmcoreinfo_xen(void) +{ + if (offset_vmcoreinfo_xen && size_vmcoreinfo_xen) + return TRUE; + return FALSE; +} + +void +get_vmcoreinfo_xen(off_t *offset, unsigned long *size) +{ + if (offset) + *offset = offset_vmcoreinfo_xen; + if (size) + *size = size_vmcoreinfo_xen; +} + +void +get_xen_crash_info(off_t *offset, unsigned long *size) +{ + if (offset) + *offset = offset_xen_crash_info; + if (size) + *size = size_xen_crash_info; +} + +int +has_eraseinfo(void) +{ + if (offset_eraseinfo && size_eraseinfo) + return TRUE; + return FALSE; +} + +void +get_eraseinfo(off_t *offset, unsigned long *size) +{ + if (offset) + *offset = offset_eraseinfo; + if (size) + *size = size_eraseinfo; +} + +void +set_eraseinfo(off_t offset, unsigned long size) +{ + offset_eraseinfo = offset; + size_eraseinfo = size; +} + diff -Nupr makedumpfile-1.3.5/elf_info.h makedumpfile-1.5.3/elf_info.h --- makedumpfile-1.3.5/elf_info.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/elf_info.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,73 @@ +/* + * elf_info.h + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _ELF_INFO_H +#define _ELF_INFO_H + +#include +#include + +#define ERASEINFO_NOTE_NAME "ERASEINFO" +#define ERASEINFO_NOTE_NAME_BYTES (sizeof(ERASEINFO_NOTE_NAME)) + +#define MAX_SIZE_NHDR MAX(sizeof(Elf64_Nhdr), sizeof(Elf32_Nhdr)) + + +off_t paddr_to_offset(unsigned long long paddr); +off_t paddr_to_offset2(unsigned long long paddr, off_t hint); +unsigned long long vaddr_to_paddr_general(unsigned long long vaddr); +off_t vaddr_to_offset_slow(int fd, char *filename, unsigned long long vaddr); +unsigned long long get_max_paddr(void); + +int get_elf64_ehdr(int fd, char *filename, Elf64_Ehdr *ehdr); +int get_elf32_ehdr(int fd, char *filename, Elf32_Ehdr *ehdr); +int get_elf_info(int fd, char *filename); +void free_elf_info(void); + +int is_elf64_memory(void); +int is_xen_memory(void); + +int get_phnum_memory(void); +int get_phdr_memory(int index, Elf64_Phdr *phdr); +off_t get_offset_pt_load_memory(void); +int get_pt_load(int idx, + unsigned long long *phys_start, + unsigned long long *phys_end, + unsigned long long *virt_start, + unsigned long long *virt_end); +unsigned int get_num_pt_loads(void); + +void set_nr_cpus(int num); +int get_nr_cpus(void); + +int has_pt_note(void); +void set_pt_note(off_t offset, unsigned long size); +void get_pt_note(off_t *offset, unsigned long *size); + +int has_vmcoreinfo(void); +void set_vmcoreinfo(off_t offset, unsigned long size); +void get_vmcoreinfo(off_t *offset, unsigned long *size); + +int has_vmcoreinfo_xen(void); +void get_vmcoreinfo_xen(off_t *offset, unsigned long *size); +void get_xen_crash_info(off_t *offset, unsigned long *size); + +int has_eraseinfo(void); +void get_eraseinfo(off_t *offset, unsigned long *size); +void set_eraseinfo(off_t offset, unsigned long size); + +#endif /* ELF_INFO_H */ + + diff -Nupr makedumpfile-1.3.5/erase_info.c makedumpfile-1.5.3/erase_info.c --- makedumpfile-1.3.5/erase_info.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/erase_info.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,2111 @@ +/* + * erase_info.c + * + * Created by: Mahesh J Salgaonkar + * + * Copyright (C) 2011 IBM Corporation + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "makedumpfile.h" +#include "print_info.h" +#include "dwarf_info.h" +#include "erase_info.h" + +#include + +struct erase_info *erase_info = NULL; +unsigned long num_erase_info = 1; /* Node 0 is unused. */ + +struct call_back eppic_cb = { + &get_domain, + &readmem, + &get_die_attr_type, + &get_die_name, + &get_die_offset, + &get_die_length, + &get_die_member, + &get_die_nfields, + &get_symbol_addr, + &update_filter_info_raw +}; + + +/* + * flags for config_entry.flag + */ +#define FILTER_ENTRY 0x0001 +#define SIZE_ENTRY 0x0002 +#define ITERATION_ENTRY 0x0004 +#define LIST_ENTRY 0x0008 +#define SYMBOL_ENTRY 0x0010 +#define VAR_ENTRY 0x0020 +#define TRAVERSAL_ENTRY 0x0040 +#define ENTRY_RESOLVED 0x8000 + +/* + * flags for get_config() + */ +#define CONFIG_SKIP_SECTION 0x01 +#define CONFIG_NEW_CMD 0x02 + +#define IS_KEYWORD(tkn) \ + (!strcmp(tkn, "erase") || !strcmp(tkn, "size") || \ + !strcmp(tkn, "nullify") || !strcmp(tkn, "for") || \ + !strcmp(tkn, "in") || !strcmp(tkn, "within") || \ + !strcmp(tkn, "endfor")) + +struct module_sym_table { + unsigned int num_modules; + unsigned int current_mod; + struct module_info *modules; +}; + +/* + * Filtering physical address range. + */ +struct filter_info { + unsigned long long vaddr; /* symbol address for debugging */ + unsigned long long paddr; + long size; + + /* direct access to update erase information node */ + int erase_info_idx; /* 0= invalid index */ + int size_idx; + + int erase_ch; + + struct filter_info *next; + unsigned short nullify; +}; + +/* + * Filter config information + */ +struct filter_config { + char *name_filterconfig; + FILE *file_filterconfig; + char *cur_module; + char *saved_token; + char *token; + int new_section; + int line_count; +}; + +struct config_entry { + char *name; + char *type_name; + char *symbol_expr; /* original symbol expression */ + unsigned short flag; + unsigned short nullify; + unsigned long long sym_addr; /* Symbol address */ + unsigned long vaddr; /* Symbol address or + value pointed by sym_addr */ + unsigned long long cmp_addr; /* for LIST_ENTRY */ + unsigned long offset; + unsigned long type_flag; + long array_length; + long index; + long size; + int line; /* Line number in config file. */ + int erase_info_idx; /* 0= invalid index */ + struct config_entry *refer_to; + struct config_entry *next; +}; + +struct config { + char *module_name; + struct config_entry *iter_entry; + struct config_entry *list_entry; + int num_filter_symbols; + struct config_entry **filter_symbol; + struct config_entry **size_symbol; +}; + +static struct module_sym_table mod_st = { 0 }; +static struct filter_info *filter_info = NULL; +static struct filter_config filter_config; +static char config_buf[BUFSIZE_FGETS]; + + +/* + * Internal functions. + */ +static struct module_info * +get_loaded_module(char *mod_name) +{ + unsigned int i; + struct module_info *modules; + + modules = mod_st.modules; + if (strcmp(mod_name, modules[mod_st.current_mod].name)) { + for (i = 0; i < mod_st.num_modules; i++) { + if (!strcmp(mod_name, modules[i].name)) + break; + } + if (i == mod_st.num_modules) + return NULL; + /* set the current_mod for fast lookup next time */ + mod_st.current_mod = i; + } + + return &modules[mod_st.current_mod]; +} + +static int +sym_in_module(char *symname, unsigned long long *symbol_addr) +{ + int i; + char *module_name; + struct module_info *module_ptr; + struct symbol_info *sym_info; + + module_name = get_dwarf_module_name(); + if (!mod_st.num_modules + || !strcmp(module_name, "vmlinux") + || !strcmp(module_name, "xen-syms")) + return FALSE; + + module_ptr = get_loaded_module(module_name); + if (!module_ptr) + return FALSE; + sym_info = module_ptr->sym_info; + if (!sym_info) + return FALSE; + for (i = 1; i < module_ptr->num_syms; i++) { + if (sym_info[i].name && !strcmp(sym_info[i].name, symname)) { + *symbol_addr = sym_info[i].value; + return TRUE; + } + } + return FALSE; +} + +static unsigned int +get_num_modules(unsigned long head, unsigned int *num) +{ + unsigned long cur; + unsigned int num_modules = 0; + + if (!num) + return FALSE; + + if (!readmem(VADDR, head + OFFSET(list_head.next), &cur, sizeof cur)) { + ERRMSG("Can't get next list_head.\n"); + return FALSE; + } + while (cur != head) { + num_modules++; + if (!readmem(VADDR, cur + OFFSET(list_head.next), + &cur, sizeof cur)) { + ERRMSG("Can't get next list_head.\n"); + return FALSE; + } + } + *num = num_modules; + return TRUE; +} + +static void +free_symbol_info(struct module_info *module) +{ + int i; + + if (module->num_syms == 0) + return; + + for (i = 1; i < module->num_syms; i++) + if (module->sym_info[i].name) + free(module->sym_info[i].name); + free(module->sym_info); +} + +static void +clean_module_symbols(void) +{ + int i; + + for (i = 0; i < mod_st.num_modules; i++) + free_symbol_info(&mod_st.modules[i]); + + if (mod_st.num_modules) { + free(mod_st.modules); + mod_st.modules = NULL; + mod_st.num_modules = 0; + } +} + +static int +__load_module_symbol(struct module_info *modules, unsigned long addr_module) +{ + int ret = FALSE; + unsigned int nsym; + unsigned long symtab, strtab; + unsigned long mod_base, mod_init; + unsigned int mod_size, mod_init_size; + unsigned char *module_struct_mem = NULL; + unsigned char *module_core_mem = NULL; + unsigned char *module_init_mem = NULL; + unsigned char *symtab_mem; + char *module_name, *strtab_mem, *nameptr; + unsigned int num_symtab; + + /* Allocate buffer to read struct module data from vmcore. */ + if ((module_struct_mem = calloc(1, SIZE(module))) == NULL) { + ERRMSG("Failed to allocate buffer for module\n"); + return FALSE; + } + if (!readmem(VADDR, addr_module, module_struct_mem, + SIZE(module))) { + ERRMSG("Can't get module info.\n"); + goto out; + } + + module_name = (char *)(module_struct_mem + OFFSET(module.name)); + if (strlen(module_name) < MOD_NAME_LEN) + strcpy(modules->name, module_name); + else + strncpy(modules->name, module_name, MOD_NAME_LEN-1); + + mod_init = ULONG(module_struct_mem + + OFFSET(module.module_init)); + mod_init_size = UINT(module_struct_mem + + OFFSET(module.init_size)); + mod_base = ULONG(module_struct_mem + + OFFSET(module.module_core)); + mod_size = UINT(module_struct_mem + + OFFSET(module.core_size)); + + DEBUG_MSG("Module: %s, Base: 0x%lx, Size: %u\n", + module_name, mod_base, mod_size); + if (mod_init_size > 0) { + module_init_mem = calloc(1, mod_init_size); + if (module_init_mem == NULL) { + ERRMSG("Can't allocate memory for module " + "init\n"); + goto out; + } + if (!readmem(VADDR, mod_init, module_init_mem, + mod_init_size)) { + ERRMSG("Can't access module init in memory.\n"); + goto out; + } + } + + if ((module_core_mem = calloc(1, mod_size)) == NULL) { + ERRMSG("Can't allocate memory for module\n"); + goto out; + } + if (!readmem(VADDR, mod_base, module_core_mem, mod_size)) { + ERRMSG("Can't access module in memory.\n"); + goto out; + } + + num_symtab = UINT(module_struct_mem + + OFFSET(module.num_symtab)); + if (!num_symtab) { + ERRMSG("%s: Symbol info not available\n", module_name); + goto out; + } + modules->num_syms = num_symtab; + DEBUG_MSG("num_sym: %d\n", num_symtab); + + symtab = ULONG(module_struct_mem + OFFSET(module.symtab)); + strtab = ULONG(module_struct_mem + OFFSET(module.strtab)); + + /* check if symtab and strtab are inside the module space. */ + if (!IN_RANGE(symtab, mod_base, mod_size) && + !IN_RANGE(symtab, mod_init, mod_init_size)) { + ERRMSG("%s: module symtab is outseide of module " + "address space\n", module_name); + goto out; + } + if (IN_RANGE(symtab, mod_base, mod_size)) + symtab_mem = module_core_mem + (symtab - mod_base); + else + symtab_mem = module_init_mem + (symtab - mod_init); + + if (!IN_RANGE(strtab, mod_base, mod_size) && + !IN_RANGE(strtab, mod_init, mod_init_size)) { + ERRMSG("%s: module strtab is outseide of module " + "address space\n", module_name); + goto out; + } + if (IN_RANGE(strtab, mod_base, mod_size)) + strtab_mem = (char *)(module_core_mem + + (strtab - mod_base)); + else + strtab_mem = (char *)(module_init_mem + + (strtab - mod_init)); + + modules->sym_info = calloc(num_symtab, sizeof(struct symbol_info)); + if (modules->sym_info == NULL) { + ERRMSG("Can't allocate memory to store sym info\n"); + goto out; + } + + /* symbols starts from 1 */ + for (nsym = 1; nsym < num_symtab; nsym++) { + Elf32_Sym *sym32; + Elf64_Sym *sym64; + /* + * TODO: + * If case of ELF vmcore then the word size can be + * determined using flag_elf64_memory flag. + * But in case of kdump-compressed dump, kdump header + * does not carry word size info. May be in future + * this info will be available in kdump header. + * Until then, in order to make this logic work on both + * situation we depend on pointer_size that is + * extracted from vmlinux dwarf information. + */ + if ((get_pointer_size() * 8) == 64) { + sym64 = (Elf64_Sym *) (symtab_mem + + (nsym * sizeof(Elf64_Sym))); + modules->sym_info[nsym].value = + (unsigned long long) sym64->st_value; + nameptr = strtab_mem + sym64->st_name; + } else { + sym32 = (Elf32_Sym *) (symtab_mem + + (nsym * sizeof(Elf32_Sym))); + modules->sym_info[nsym].value = + (unsigned long long) sym32->st_value; + nameptr = strtab_mem + sym32->st_name; + } + if (strlen(nameptr)) + modules->sym_info[nsym].name = strdup(nameptr); + DEBUG_MSG("\t[%d] %llx %s\n", nsym, + modules->sym_info[nsym].value, nameptr); + } + ret = TRUE; +out: + free(module_struct_mem); + free(module_core_mem); + free(module_init_mem); + + return ret; +} + +static int +load_module_symbols(void) +{ + unsigned long head, cur, cur_module; + struct module_info *modules = NULL; + unsigned int i = 0; + + head = SYMBOL(modules); + if (!get_num_modules(head, &mod_st.num_modules) || + !mod_st.num_modules) { + ERRMSG("Can't get module count\n"); + return FALSE; + } + mod_st.modules = calloc(mod_st.num_modules, + sizeof(struct module_info)); + if (!mod_st.modules) { + ERRMSG("Can't allocate memory for module info\n"); + return FALSE; + } + modules = mod_st.modules; + + if (!readmem(VADDR, head + OFFSET(list_head.next), &cur, sizeof cur)) { + ERRMSG("Can't get next list_head.\n"); + return FALSE; + } + + /* Travese the list and read module symbols */ + while (cur != head) { + cur_module = cur - OFFSET(module.list); + + if (!__load_module_symbol(&modules[i], cur_module)) + return FALSE; + + if (!readmem(VADDR, cur + OFFSET(list_head.next), + &cur, sizeof cur)) { + ERRMSG("Can't get next list_head.\n"); + return FALSE; + } + i++; + } + return TRUE; +} + +static void +free_config_entry(struct config_entry *ce) +{ + struct config_entry *p; + + while(ce) { + p = ce; + ce = p->next; + if (p->name) + free(p->name); + if (p->type_name) + free(p->type_name); + if (p->symbol_expr) + free(p->symbol_expr); + free(p); + } +} + +static void +free_config(struct config *config) +{ + int i; + + if (config == NULL) + return; + + if (config->module_name) + free(config->module_name); + for (i = 0; i < config->num_filter_symbols; i++) { + if (config->filter_symbol[i]) + free_config_entry(config->filter_symbol[i]); + if (config->size_symbol[i]) + free_config_entry(config->size_symbol[i]); + } + if (config->filter_symbol) + free(config->filter_symbol); + if (config->size_symbol) + free(config->size_symbol); + free(config); +} + +static void +print_config_entry(struct config_entry *ce) +{ + while (ce) { + DEBUG_MSG("Name: %s\n", ce->name); + DEBUG_MSG("Type Name: %s, ", ce->type_name); + DEBUG_MSG("flag: %x, ", ce->flag); + DEBUG_MSG("Type flag: %lx, ", ce->type_flag); + DEBUG_MSG("sym_addr: %llx, ", ce->sym_addr); + DEBUG_MSG("vaddr: %lx, ", ce->vaddr); + DEBUG_MSG("offset: %llx, ", (unsigned long long)ce->offset); + DEBUG_MSG("size: %ld\n", ce->size); + + ce = ce->next; + } +} + +/* + * Read the non-terminal's which are in the form of [.member[...]] + */ +static struct config_entry * +create_config_entry(const char *token, unsigned short flag, int line) +{ + struct config_entry *ce = NULL, *ptr, *prev_ce; + char *str, *cur, *next; + long len; + int depth = 0; + + if (!token) + return NULL; + + cur = str = strdup(token); + prev_ce = ptr = NULL; + while (cur != NULL) { + if ((next = strchr(cur, '.')) != NULL) { + *next++ = '\0'; + } + if (!strlen(cur)) { + cur = next; + continue; + } + + if ((ptr = calloc(1, sizeof(struct config_entry))) == NULL) { + ERRMSG("Can't allocate memory for config_entry\n"); + goto err_out; + } + ptr->line = line; + ptr->flag |= flag; + if (depth == 0) { + /* First node is always a symbol name */ + ptr->flag |= SYMBOL_ENTRY; + } + if (flag & ITERATION_ENTRY) { + /* Max depth for iteration entry is 1 */ + if (depth > 0) { + ERRMSG("Config error at %d: Invalid iteration " + "variable entry.\n", line); + goto err_out; + } + ptr->name = strdup(cur); + } + if (flag & (FILTER_ENTRY | LIST_ENTRY)) { + ptr->name = strdup(cur); + } + if (flag & SIZE_ENTRY) { + char ch = '\0'; + int n = 0; + /* See if absolute length is provided */ + if ((depth == 0) && + ((n = sscanf(cur, "%ld%c", &len, &ch)) > 0)) { + if (len < 0) { + ERRMSG("Config error at %d: size " + "value must be positive.\n", + line); + goto err_out; + } + ptr->size = len; + ptr->flag |= ENTRY_RESOLVED; + if (n == 2) { + /* Handle suffix. + * K = Kilobytes + * M = Megabytes + */ + switch (ch) { + case 'M': + case 'm': + ptr->size *= 1024; + case 'K': + case 'k': + ptr->size *= 1024; + break; + } + } + } + else + ptr->name = strdup(cur); + } + if (prev_ce) { + prev_ce->next = ptr; + prev_ce = ptr; + } else + ce = prev_ce = ptr; + + cur = next; + ptr = NULL; + depth++; + } + free(str); + return ce; + +err_out: + if (ce) + free_config_entry(ce); + if (ptr) + free_config_entry(ptr); + free(str); + return NULL; +} + +static int +is_module_loaded(char *mod_name) +{ + if (!strcmp(mod_name, "vmlinux") || get_loaded_module(mod_name)) + return TRUE; + return FALSE; +} + +/* + * read filter config file and return each string token. If the parameter + * expected_token is non-NULL, then return the current token if it matches + * with expected_token otherwise save the current token and return NULL. + * At start of every module section filter_config.new_section is set to 1 and + * subsequent function invocations return NULL untill filter_config.new_section + * is reset to 0 by passing @flag = CONFIG_NEW_CMD (0x02). + * + * Parameters: + * @expected_token INPUT + * Token string to match with currnet token. + * =NULL - return the current available token. + * + * @flag INPUT + * =0x01 - Skip to next module section. + * =0x02 - Treat the next token as next filter command and reset. + * + * @line OUTPUT + * Line number of current token in filter config file. + * + * @cur_mod OUTPUT + * Points to current module section name on non-NULL return value. + * + * @eof OUTPUT + * set to -1 when end of file is reached. + * set to -2 when end of section is reached. + */ +#define NOT_REACH_END (0) +#define REACH_END_OF_FILE (-1) +#define REACH_END_OF_SECTION (-2) + +static char * +get_config_token(char *expected_token, unsigned char flag, int *line, + char **cur_mod, int *eof) +{ + char *p; + struct filter_config *fc = &filter_config; + int skip = flag & CONFIG_SKIP_SECTION; + + if (!fc->file_filterconfig) + return NULL; + + if (eof) + *eof = NOT_REACH_END; + + /* + * set token and saved_token to NULL if skip module section is set + * to 1. + */ + if (skip) { + fc->token = NULL; + fc->saved_token = NULL; + + } else if (fc->saved_token) { + fc->token = fc->saved_token; + fc->saved_token = NULL; + + } else if (fc->token) + fc->token = strtok(NULL, " "); + + /* Read next line if we are done all tokens from previous line */ + while (!fc->token && fgets(config_buf, sizeof(config_buf), + fc->file_filterconfig)) { + if ((p = strchr(config_buf, '\n'))) { + *p = '\0'; + fc->line_count++; + } + if ((p = strchr(config_buf, '#'))) { + *p = '\0'; + } + /* replace all tabs with spaces */ + for (p = config_buf; *p != '\0'; p++) + if (*p == '\t') + *p = ' '; + if (config_buf[0] == '[') { + /* module section entry */ + p = strchr(config_buf, ']'); + if (!p) { + ERRMSG("Config error at %d: Invalid module " + "section entry.\n", fc->line_count); + /* skip to next valid module section */ + skip = 1; + } else { + /* + * Found the valid module section. Reset the + * skip flag. + */ + *p = '\0'; + if (fc->cur_module) + free(fc->cur_module); + fc->cur_module = strdup(&config_buf[1]); + fc->new_section = 1; + skip = 0; + } + continue; + } + /* + * If symbol info for current module is not loaded then + * skip to next module section. + */ + if (skip || + (fc->cur_module && !is_module_loaded(fc->cur_module))) + continue; + + fc->token = strtok(config_buf, " "); + } + if (!fc->token) { + if (eof) + *eof = REACH_END_OF_FILE; + return NULL; + } + if (fc->new_section && !(flag & CONFIG_NEW_CMD)) { + fc->saved_token = fc->token; + if (eof) + *eof = REACH_END_OF_SECTION; + return NULL; + } + + fc->new_section = 0; + + if (cur_mod) + *cur_mod = fc->cur_module; + + if (line) + *line = fc->line_count; + + if (expected_token && strcmp(fc->token, expected_token)) { + fc->saved_token = fc->token; + return NULL; + } + return fc->token; +} + +static int +read_size_entry(struct config *config, int line, int idx) +{ + char *token = get_config_token(NULL, 0, &line, NULL, NULL); + + if (!token || IS_KEYWORD(token)) { + ERRMSG("Config error at %d: expected size symbol after" + " 'size' keyword.\n", line); + return FALSE; + } + config->size_symbol[idx] = create_config_entry(token, SIZE_ENTRY, line); + if (!config->size_symbol[idx]) { + ERRMSG("Error at line %d: Failed to read size symbol\n", + line); + return FALSE; + } + if (config->iter_entry && config->size_symbol[idx]->name && + (!strcmp(config->size_symbol[idx]->name, + config->iter_entry->name))) { + config->size_symbol[idx]->flag &= ~SYMBOL_ENTRY; + config->size_symbol[idx]->flag |= VAR_ENTRY; + config->size_symbol[idx]->refer_to = config->iter_entry; + } + return TRUE; +} + +/* + * Read erase command entry. The erase command syntax is: + * + * erase [.member[...]] [size [K|M]] + * erase [.member[...]] [size ] + * erase [.member[...]] [nullify] + */ +static int +read_erase_cmd_entry(struct config *config, int line) +{ + int size, idx; + char *token = get_config_token(NULL, 0, &line, NULL, NULL); + + if (!token || IS_KEYWORD(token)) { + ERRMSG("Config error at %d: expected kernel symbol after" + " 'erase' command.\n", line); + return FALSE; + } + + idx = config->num_filter_symbols; + config->num_filter_symbols++; + size = config->num_filter_symbols * sizeof(struct config_entry *); + config->filter_symbol = realloc(config->filter_symbol, size); + config->size_symbol = realloc(config->size_symbol, size); + + if (!config->filter_symbol || !config->size_symbol) { + ERRMSG("Can't get memory to read config symbols.\n"); + return FALSE; + } + config->filter_symbol[idx] = NULL; + config->size_symbol[idx] = NULL; + + config->filter_symbol[idx] = + create_config_entry(token, FILTER_ENTRY, line); + if (!config->filter_symbol[idx]) { + ERRMSG("Error at line %d: Failed to read filter symbol\n", + line); + return FALSE; + } + + /* + * Save the symbol expression string for generation of eraseinfo data + * later while writing dumpfile. + */ + config->filter_symbol[idx]->symbol_expr = strdup(token); + + if (config->iter_entry) { + if (strcmp(config->filter_symbol[idx]->name, + config->iter_entry->name)) { + ERRMSG("Config error at %d: unused iteration" + " variable '%s'.\n", line, + config->iter_entry->name); + return FALSE; + } + config->filter_symbol[idx]->flag &= ~SYMBOL_ENTRY; + config->filter_symbol[idx]->flag |= VAR_ENTRY; + config->filter_symbol[idx]->refer_to = config->iter_entry; + } + if (get_config_token("nullify", 0, &line, NULL, NULL)) { + config->filter_symbol[idx]->nullify = 1; + + } else if (get_config_token("size", 0, &line, NULL, NULL)) { + if (!read_size_entry(config, line, idx)) + return FALSE; + } + return TRUE; +} + +static int +add_traversal_entry(struct config_entry *ce, char *member, int line) +{ + if (!ce) + return FALSE; + + while (ce->next) + ce = ce->next; + + ce->next = create_config_entry(member, LIST_ENTRY, line); + if (ce->next == NULL) { + ERRMSG("Error at line %d: Failed to read 'via' member\n", + line); + return FALSE; + } + + ce->next->flag |= TRAVERSAL_ENTRY; + ce->next->flag &= ~SYMBOL_ENTRY; + return TRUE; +} + +static int +read_list_entry(struct config *config, int line) +{ + char *token = get_config_token(NULL, 0, &line, NULL, NULL); + + if (!token || IS_KEYWORD(token)) { + ERRMSG("Config error at %d: expected list symbol after" + " 'in' keyword.\n", line); + return FALSE; + } + config->list_entry = create_config_entry(token, LIST_ENTRY, line); + if (!config->list_entry) { + ERRMSG("Error at line %d: Failed to read list symbol\n", + line); + return FALSE; + } + /* Check if user has provided 'via' or 'within' keyword */ + if (get_config_token("via", 0, &line, NULL, NULL)) { + /* next token is traversal member NextMember */ + token = get_config_token(NULL, 0, &line, NULL, NULL); + if (!token) { + ERRMSG("Config error at %d: expected member name after" + " 'via' keyword.\n", line); + return FALSE; + } + if (!add_traversal_entry(config->list_entry, token, line)) + return FALSE; + } + else if (get_config_token("within", 0, &line, NULL, NULL)) { + char *s_name, *lh_member; + /* next value is StructName:ListHeadMember */ + s_name = get_config_token(NULL, 0, &line, NULL, NULL); + if (!s_name || IS_KEYWORD(s_name)) { + ERRMSG("Config error at %d: expected struct name after" + " 'within' keyword.\n", line); + return FALSE; + } + lh_member = strchr(s_name, ':'); + if (lh_member) { + *lh_member++ = '\0'; + if (!strlen(lh_member)) { + ERRMSG("Config error at %d: expected list_head" + " member after ':'.\n", line); + return FALSE; + } + config->iter_entry->next = + create_config_entry(lh_member, + ITERATION_ENTRY, line); + if (!config->iter_entry->next) + return FALSE; + config->iter_entry->next->flag &= ~SYMBOL_ENTRY; + } + if (!strlen(s_name)) { + ERRMSG("Config error at %d: Invalid token found " + "after 'within' keyword.\n", line); + return FALSE; + } + config->iter_entry->type_name = strdup(s_name); + } + return TRUE; +} + +/* + * Read the iteration entry (LoopConstruct). The syntax is: + * + * for in { | + * via | + * within :} + * erase [.MemberExpression] [size |nullify] + * [erase ...] + * [...] + * endfor + */ +static int +read_iteration_entry(struct config *config, int line) +{ + int eof = NOT_REACH_END; + char *token = get_config_token(NULL, 0, &line, NULL, NULL); + + if (!token || IS_KEYWORD(token)) { + ERRMSG("Config error at %d: expected iteration VAR entry after" + " 'for' keyword.\n", line); + return FALSE; + } + config->iter_entry = + create_config_entry(token, ITERATION_ENTRY, line); + if (!config->iter_entry) { + ERRMSG("Error at line %d: " + "Failed to read iteration VAR entry.\n", line); + return FALSE; + } + if (!get_config_token("in", 0, &line, NULL, NULL)) { + char *token; + token = get_config_token(NULL, 0, &line, NULL, NULL); + if (token) + ERRMSG("Config error at %d: Invalid token '%s'.\n", + line, token); + ERRMSG("Config error at %d: expected token 'in'.\n", line); + return FALSE; + } + if (!read_list_entry(config, line)) + return FALSE; + + while (!get_config_token("endfor", 0, &line, NULL, &eof) && !eof) { + if (get_config_token("erase", 0, &line, NULL, NULL)) { + if (!read_erase_cmd_entry(config, line)) + return FALSE; + } else { + token = get_config_token(NULL, 0, &line, NULL, NULL); + ERRMSG("Config error at %d: " + "Invalid token '%s'.\n", line, token); + return FALSE; + } + } + if (eof != NOT_REACH_END) { + ERRMSG("Config error at %d: No matching 'endfor' found.\n", + line); + return FALSE; + } + return TRUE; +} + +/* + * Configuration file 'makedumpfile.conf' contains filter commands. + * Every individual filter command is considered as a config entry. + * A config entry can be provided on a single line or multiple lines. + */ +static struct config * +get_config(int skip) +{ + struct config *config; + char *token = NULL; + static int line_count = 0; + char *cur_module = NULL; + int eof = NOT_REACH_END; + unsigned char flag = CONFIG_NEW_CMD; + + if (skip) + flag |= CONFIG_SKIP_SECTION; + + if ((config = calloc(1, sizeof(struct config))) == NULL) + return NULL; + + if (get_config_token("erase", flag, &line_count, &cur_module, &eof)) { + if (cur_module) + config->module_name = strdup(cur_module); + + if (!read_erase_cmd_entry(config, line_count)) + goto err_out; + + } else if (get_config_token("for", 0, &line_count, &cur_module, &eof)) { + if (cur_module) + config->module_name = strdup(cur_module); + + if (!read_iteration_entry(config, line_count)) + goto err_out; + } else { + if (eof == NOT_REACH_END) { + token = get_config_token(NULL, 0, &line_count, + NULL, NULL); + ERRMSG("Config error at %d: Invalid token '%s'.\n", + line_count, token); + } + goto err_out; + } + return config; +err_out: + if (config) + free_config(config); + return NULL; +} + +static unsigned long +read_pointer_value(unsigned long long vaddr) +{ + unsigned long val; + + if (!readmem(VADDR, vaddr, &val, sizeof(val))) { + ERRMSG("Can't read pointer value\n"); + return 0; + } + return val; +} + +static long +get_strlen(unsigned long long vaddr) +{ + char buf[BUFSIZE + 1]; + long len = 0; + + /* + * Determine the string length for 'char' pointer. + * BUFSIZE(1024) is the upper limit for string length. + */ + if (readmem(VADDR, vaddr, buf, BUFSIZE)) { + buf[BUFSIZE] = '\0'; + len = strlen(buf); + } + return len; +} + +static int +resolve_config_entry(struct config_entry *ce, unsigned long long base_vaddr, + char *base_struct_name) +{ + unsigned long long symbol; + + if (ce->flag & SYMBOL_ENTRY) { + /* find the symbol info */ + if (!ce->name) + return FALSE; + + /* + * If we are looking for module symbol then traverse through + * mod_st.modules for symbol lookup + */ + if (sym_in_module(ce->name, &symbol)) + ce->sym_addr = symbol; + else + ce->sym_addr = get_symbol_addr(ce->name); + if (!ce->sym_addr) { + ERRMSG("Config error at %d: Can't find symbol '%s'.\n", + ce->line, ce->name); + return FALSE; + } + ce->type_name = get_symbol_type_name(ce->name, + DWARF_INFO_GET_SYMBOL_TYPE, + &ce->size, &ce->type_flag); + if (ce->type_flag & TYPE_ARRAY) { + ce->array_length = get_array_length(ce->name, NULL, + DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH); + if (ce->array_length < 0) + ce->array_length = 0; + } + } else if (ce->flag & VAR_ENTRY) { + /* iteration variable. + * read the value from ce->refer_to + */ + ce->vaddr = ce->refer_to->vaddr; + ce->sym_addr = ce->refer_to->sym_addr; + ce->size = ce->refer_to->size; + ce->type_flag = ce->refer_to->type_flag; + if (!ce->type_name) + ce->type_name = strdup(ce->refer_to->type_name); + + /* This entry has been changed hence next entry needs to + * be resolved accordingly. + */ + if (ce->next) + ce->next->flag &= ~ENTRY_RESOLVED; + return TRUE; + } else { + /* find the member offset */ + ce->offset = get_member_offset(base_struct_name, + ce->name, DWARF_INFO_GET_MEMBER_OFFSET); + ce->sym_addr = base_vaddr + ce->offset; + ce->type_name = get_member_type_name(base_struct_name, + ce->name, DWARF_INFO_GET_MEMBER_TYPE, + &ce->size, &ce->type_flag); + if (ce->type_flag & TYPE_ARRAY) { + ce->array_length = get_array_length(base_struct_name, + ce->name, + DWARF_INFO_GET_MEMBER_ARRAY_LENGTH); + if (ce->array_length < 0) + ce->array_length = 0; + } + } + if (ce->type_name == NULL) { + if (!(ce->flag & SYMBOL_ENTRY)) + ERRMSG("Config error at %d: struct '%s' has no member" + " with name '%s'.\n", + ce->line, base_struct_name, ce->name); + return FALSE; + } + if (!strcmp(ce->type_name, "list_head")) { + ce->type_flag |= TYPE_LIST_HEAD; + /* If this list head expression is a LIST entry then + * mark the next entry as TRAVERSAL_ENTRY, if any. + * Error out if next entry is not a last node. + */ + if ((ce->flag & LIST_ENTRY) && ce->next) { + if (ce->next->next) { + ERRMSG("Config error at %d: Only one traversal" + " entry is allowed for list_head type" + " LIST entry", ce->line); + return FALSE; + } + ce->next->flag |= TRAVERSAL_ENTRY; + } + } + ce->vaddr = ce->sym_addr; + if (ce->size < 0) + ce->size = 0; + if ((ce->flag & LIST_ENTRY) && !ce->next) { + /* This is the last node of LIST entry. + * For the list entry symbol, the allowed data types are: + * Array, Structure Pointer (with 'next' member) and list_head. + * + * If this is a struct or list_head data type then + * create a leaf node entry with 'next' member. + */ + if (((ce->type_flag & (TYPE_BASE | TYPE_ARRAY)) == TYPE_BASE) + && (strcmp(ce->type_name, "void"))) + return FALSE; + + if ((ce->type_flag & TYPE_LIST_HEAD) + || ((ce->type_flag & (TYPE_STRUCT | TYPE_ARRAY)) + == TYPE_STRUCT)) { + if (!(ce->flag & TRAVERSAL_ENTRY)) { + ce->next = create_config_entry("next", + LIST_ENTRY, ce->line); + if (ce->next == NULL) + return FALSE; + + ce->next->flag |= TRAVERSAL_ENTRY; + ce->next->flag &= ~SYMBOL_ENTRY; + } + } + if (ce->flag & TRAVERSAL_ENTRY) { + /* type name of traversal entry should match with + * that of parent node. + */ + if (strcmp(base_struct_name, ce->type_name)) + return FALSE; + } + } + if ((ce->type_flag & (TYPE_ARRAY | TYPE_PTR)) == TYPE_PTR) { + /* If it's a pointer variable (not array) then read the + * pointer value. */ + ce->vaddr = read_pointer_value(ce->sym_addr); + + /* + * if it is a void pointer then reset the size to 0 + * User need to provide a size to filter data referenced + * by 'void *' pointer or nullify option. + */ + if (!strcmp(ce->type_name, "void")) + ce->size = 0; + + } + if ((ce->type_flag & TYPE_BASE) && (ce->type_flag & TYPE_PTR) + && !(ce->type_flag & TYPE_ARRAY)) { + if (!strcmp(ce->type_name, "char")) + ce->size = get_strlen(ce->vaddr); + } + if (!ce->next && (ce->flag & SIZE_ENTRY)) { + void *val; + + /* leaf node of size entry */ + /* If it is size argument then update the size with data + * value of this symbol/member. + * Check if current symbol/member is of base data type. + */ + + if (((ce->type_flag & (TYPE_ARRAY | TYPE_BASE)) != TYPE_BASE) + || (ce->size > sizeof(long))) { + ERRMSG("Config error at %d: size symbol/member '%s' " + "is not of base type.\n", ce->line, ce->name); + return FALSE; + } + if ((val = calloc(1, ce->size)) == NULL) { + ERRMSG("Can't get memory for size parameter\n"); + return FALSE; + } + + if (!readmem(VADDR, ce->vaddr, val, ce->size)) { + ERRMSG("Can't read symbol/member data value\n"); + return FALSE; + } + switch (ce->size) { + case 1: + ce->size = (long)(*((uint8_t *)val)); + break; + case 2: + ce->size = (long)(*((uint16_t *)val)); + break; + case 4: + ce->size = (long)(*((uint32_t *)val)); + break; + case 8: + ce->size = (long)(*((uint64_t *)val)); + break; + } + free(val); + } + ce->flag |= ENTRY_RESOLVED; + if (ce->next) + ce->next->flag &= ~ENTRY_RESOLVED; + return TRUE; +} + +static unsigned long long +get_config_symbol_addr(struct config_entry *ce, + unsigned long long base_vaddr, + char *base_struct_name) +{ + if (!(ce->flag & ENTRY_RESOLVED)) { + if (!resolve_config_entry(ce, base_vaddr, base_struct_name)) + return 0; + } + + if (ce->next && ce->vaddr) { + /* Populate nullify flag down the list */ + ce->next->nullify = ce->nullify; + return get_config_symbol_addr(ce->next, ce->vaddr, + ce->type_name); + } else if (!ce->next && ce->nullify) { + /* nullify is applicable to pointer type */ + if (ce->type_flag & TYPE_PTR) + return ce->sym_addr; + else + return 0; + } else + return ce->vaddr; +} + +static long +get_config_symbol_size(struct config_entry *ce, + unsigned long long base_vaddr, + char *base_struct_name) +{ + if (!(ce->flag & ENTRY_RESOLVED)) { + if (!resolve_config_entry(ce, base_vaddr, base_struct_name)) + return 0; + } + + if (ce->next && ce->vaddr) + return get_config_symbol_size(ce->next, ce->vaddr, + ce->type_name); + else { + if (ce->type_flag & TYPE_ARRAY) { + if (ce->type_flag & TYPE_PTR) + return ce->array_length * get_pointer_size(); + else + return ce->array_length * ce->size; + } + return ce->size; + } +} + +static int +get_next_list_entry(struct config_entry *ce, unsigned long long base_vaddr, + char *base_struct_name, struct config_entry *out_ce) +{ + unsigned long vaddr = 0; + + /* This function only deals with LIST_ENTRY config entry. */ + if (!(ce->flag & LIST_ENTRY)) + return FALSE; + + if (!(ce->flag & ENTRY_RESOLVED)) { + if (!resolve_config_entry(ce, base_vaddr, base_struct_name)) + return FALSE; + } + + if (!ce->next) { + /* leaf node. */ + if (ce->type_flag & TYPE_ARRAY) { + if (ce->index == ce->array_length) + return FALSE; + + if (ce->type_flag & TYPE_PTR) { + /* Array of pointers. + * + * Array may contain NULL pointers at some + * indexes. Hence jump to the next non-null + * address value. + */ + while (ce->index < ce->array_length) { + vaddr = read_pointer_value(ce->vaddr + + (ce->index * get_pointer_size())); + if (vaddr) + break; + ce->index++; + } + if (ce->index == ce->array_length) + return FALSE; + out_ce->sym_addr = ce->vaddr + (ce->index * + get_pointer_size()); + out_ce->vaddr = vaddr; + if (!strcmp(ce->type_name, "char")) + out_ce->size = get_strlen(vaddr); + else + out_ce->size = ce->size; + } else { + out_ce->sym_addr = ce->vaddr + + (ce->index * ce->size); + out_ce->vaddr = out_ce->sym_addr; + out_ce->size = ce->size; + } + ce->index++; + } else { + if (ce->vaddr == ce->cmp_addr) + return FALSE; + + out_ce->vaddr = ce->vaddr; + /* Set the leaf node as unresolved, so that + * it will be resolved every time when + * get_next_list_entry is called untill + * it hits the exit condiftion. + */ + ce->flag &= ~ENTRY_RESOLVED; + } + return TRUE; + + } else if ((ce->next->next == NULL) && + !(ce->next->type_flag & TYPE_ARRAY)) { + /* the next node is leaf node. for non-array element + * Set the sym_addr and addr of this node with that of + * leaf node. + */ + if (!(ce->type_flag & TYPE_LIST_HEAD)) { + if (!ce->vaddr || ce->vaddr == ce->next->cmp_addr) + return FALSE; + + if (!ce->next->cmp_addr) { + /* safeguard against circular + * link-list + */ + ce->next->cmp_addr = ce->vaddr; + } + out_ce->vaddr = ce->vaddr; + out_ce->sym_addr = ce->sym_addr; + out_ce->size = ce->size; + + ce->sym_addr = ce->next->sym_addr; + ce->vaddr = ce->next->vaddr; + + /* Force resolution of traversal node */ + if (ce->vaddr && !resolve_config_entry(ce->next, + ce->vaddr, ce->type_name)) + return FALSE; + + return TRUE; + } else { + ce->sym_addr = ce->next->sym_addr; + ce->vaddr = ce->next->vaddr; + } + } + + if (ce->next && ce->vaddr) + return get_next_list_entry(ce->next, ce->vaddr, + ce->type_name, out_ce); + return FALSE; +} + +static int +resolve_list_entry(struct config_entry *ce, unsigned long long base_vaddr, + char *base_struct_name, char **out_type_name, + unsigned char *out_type_flag) +{ + if (!(ce->flag & ENTRY_RESOLVED)) { + if (!resolve_config_entry(ce, base_vaddr, base_struct_name)) + return FALSE; + } + + if (ce->next && (ce->next->flag & TRAVERSAL_ENTRY) && + (ce->type_flag & TYPE_ARRAY)) { + /* + * We are here because user has provided + * traversal member for ArrayVar using 'via' keyword. + * + * Print warning and continue. + */ + ERRMSG("Warning: line %d: 'via' keyword not required " + "for ArrayVar.\n", ce->next->line); + free_config_entry(ce->next); + ce->next = NULL; + } + if ((ce->type_flag & TYPE_LIST_HEAD) && ce->next && + (ce->next->flag & TRAVERSAL_ENTRY)) { + /* set cmp_addr for list empty condition. */ + ce->next->cmp_addr = ce->sym_addr; + } + if (ce->next && ce->vaddr) { + return resolve_list_entry(ce->next, ce->vaddr, + ce->type_name, out_type_name, out_type_flag); + } + else { + ce->index = 0; + if (out_type_name) + *out_type_name = ce->type_name; + if (out_type_flag) + *out_type_flag = ce->type_flag; + } + return TRUE; +} + +/* + * Insert the filter info node using insertion sort. + * If filter node for a given paddr is aready present then update the size + * and delete the fl_info node passed. + * + * Return 1 on successfull insertion. + * Return 0 if filter node with same paddr is found. + */ +static int +insert_filter_info(struct filter_info *fl_info) +{ + struct filter_info *prev = NULL; + struct filter_info *ptr = filter_info; + + if (!ptr) { + filter_info = fl_info; + return 1; + } + + while (ptr) { + if (fl_info->paddr <= ptr->paddr) + break; + prev = ptr; + ptr = ptr->next; + } + if (ptr && (fl_info->paddr == ptr->paddr)) { + if (fl_info->size > ptr->size) + ptr->size = fl_info->size; + free(fl_info); + return 0; + } + + if (prev) { + fl_info->next = ptr; + prev->next = fl_info; + } + else { + fl_info->next = filter_info; + filter_info = fl_info; + } + return 1; +} + +/* + * Create an erase info node for each erase command. One node per erase + * command even if it is part of loop construct. + * For erase commands that are not part of loop construct, the num_sizes will + * always be 1 + * For erase commands that are part of loop construct, the num_sizes may be + * 1 or >1 depending on number iterations. This function will called multiple + * times depending on iterations. At first invokation create a node and + * increment num_sizes for subsequent invokations. + * + * The valid erase info node starts from index value 1. (index 0 is invalid + * index). + * + * Index 0 1 2 3 + * +------+--------+--------+--------+ + * erase_info->|Unused| | | |...... + * +------+--------+--------+--------+ + * | . . ..... + * V + * +---------+ + * | char* |----> Original erase command string + * +---------+ + * |num_sizes| + * +---------+ +--+--+--+ + * | sizes |----> | | | |... Sizes array of num_sizes + * +---------+ +--+--+--+ + * + * On success, return the index value of erase node for given erase command. + * On failure, return 0. + */ +static int +add_erase_info_node(struct config_entry *filter_symbol) +{ + int idx = filter_symbol->erase_info_idx; + + /* + * Check if node is already created, if yes, increment the num_sizes. + */ + if (idx) { + erase_info[idx].num_sizes++; + return idx; + } + + /* Allocate a new node. */ + DEBUG_MSG("Allocating new erase info node for command \"%s\"\n", + filter_symbol->symbol_expr); + idx = num_erase_info++; + erase_info = realloc(erase_info, + sizeof(struct erase_info) * num_erase_info); + if (!erase_info) { + ERRMSG("Can't get memory to create erase information.\n"); + return 0; + } + + memset(&erase_info[idx], 0, sizeof(struct erase_info)); + erase_info[idx].symbol_expr = filter_symbol->symbol_expr; + erase_info[idx].num_sizes = 1; + + filter_symbol->symbol_expr = NULL; + filter_symbol->erase_info_idx = idx; + + return idx; +} + +/* Return the index value in sizes array for given erase command index. */ +static inline int +get_size_index(int ei_idx) +{ + if (ei_idx) + return erase_info[ei_idx].num_sizes - 1; + return 0; +} + +static int +update_filter_info(struct config_entry *filter_symbol, + struct config_entry *size_symbol) +{ + unsigned long long sym_addr; + long size; + struct filter_info *fl_info; + + sym_addr = get_config_symbol_addr(filter_symbol, 0, NULL); + if (message_level & ML_PRINT_DEBUG_MSG) + print_config_entry(filter_symbol); + if (!sym_addr) + return FALSE; + + if (filter_symbol->nullify) + size = get_pointer_size(); + else if (size_symbol) { + size = get_config_symbol_size(size_symbol, 0, NULL); + if (message_level & ML_PRINT_DEBUG_MSG) + print_config_entry(size_symbol); + } else + size = get_config_symbol_size(filter_symbol, 0, NULL); + + if (size <= 0) + return FALSE; + + if ((fl_info = calloc(1, sizeof(struct filter_info))) == NULL) { + ERRMSG("Can't allocate filter info\n"); + return FALSE; + } + fl_info->vaddr = sym_addr; + fl_info->paddr = vaddr_to_paddr(sym_addr); + fl_info->size = size; + fl_info->nullify = filter_symbol->nullify; + fl_info->erase_ch = 'X'; + + if (insert_filter_info(fl_info)) { + fl_info->erase_info_idx = add_erase_info_node(filter_symbol); + fl_info->size_idx = get_size_index(fl_info->erase_info_idx); + } + return TRUE; +} + +int +update_filter_info_raw(unsigned long long sym_addr, int ch, int len) +{ + struct filter_info *fl_info; + + fl_info = calloc(1, sizeof(struct filter_info)); + if (fl_info == NULL) { + ERRMSG("Can't allocate filter info\n"); + return FALSE; + } + + fl_info->vaddr = sym_addr; + fl_info->paddr = vaddr_to_paddr(sym_addr); + fl_info->size = len; + fl_info->nullify = 0; + fl_info->erase_ch = ch; + + if (insert_filter_info(fl_info)) { + /* TODO + * Add support to update erase information to the + * resulting dump file + */ + fl_info->erase_info_idx = 0; + fl_info->size_idx = 0; + } + return TRUE; +} + +static int +initialize_iteration_entry(struct config_entry *ie, + char *type_name, unsigned char type_flag) +{ + if (!(ie->flag & ITERATION_ENTRY)) + return FALSE; + + if (type_flag & TYPE_LIST_HEAD) { + if (!ie->type_name) { + ERRMSG("Config error at %d: Use 'within' keyword " + "to specify StructName:ListHeadMember.\n", + ie->line); + return FALSE; + } + /* + * If the LIST entry is of list_head type and user has not + * specified the member name where iteration entry is hooked + * on to list_head, then we default to member name 'list'. + */ + if (!ie->next) { + ie->next = create_config_entry("list", ITERATION_ENTRY, + ie->line); + ie->next->flag &= ~SYMBOL_ENTRY; + } + + /* + * For list_head find out the size of the StructName and + * populate ie->size now. For array and link list we get the + * size info from config entry returned by + * get_next_list_entry(). + */ + ie->size = get_structure_size(ie->type_name, 0); + if (ie->size == FAILED_DWARFINFO) { + ERRMSG("Config error at %d: " + "Can't get size for type: %s.\n", + ie->line, ie->type_name); + return FALSE; + + } else if (ie->size == NOT_FOUND_STRUCTURE) { + ERRMSG("Config error at %d: " + "Can't find structure: %s.\n", + ie->line, ie->type_name); + return FALSE; + } + + if (!resolve_config_entry(ie->next, 0, ie->type_name)) + return FALSE; + + if (strcmp(ie->next->type_name, "list_head")) { + ERRMSG("Config error at %d: " + "Member '%s' is not of 'list_head' type.\n", + ie->next->line, ie->next->name); + return FALSE; + } + ie->type_flag = TYPE_STRUCT; + } else { + if (ie->type_name) { + /* looks like user has used 'within' keyword for + * non-list_head VAR. Print the warning and continue. + */ + ERRMSG("Warning: line %d: 'within' keyword not " + "required for ArrayVar/StructVar.\n", ie->line); + free(ie->type_name); + + /* remove the next list_head member from iteration + * entry that would have added as part of 'within' + * keyword processing. + */ + if (ie->next) { + free_config_entry(ie->next); + ie->next = NULL; + } + } + /* + * Set type flag for iteration entry. The iteration entry holds + * individual element from array/list, hence strip off the + * array type flag bit. + */ + ie->type_name = strdup(type_name); + ie->type_flag = type_flag; + ie->type_flag &= ~TYPE_ARRAY; + } + return TRUE; +} + +static int +list_entry_empty(struct config_entry *le, struct config_entry *ie) +{ + struct config_entry ce; + + /* Error out if arguments are not correct */ + if (!(le->flag & LIST_ENTRY) || !(ie->flag & ITERATION_ENTRY)) { + ERRMSG("Invalid arguments\n"); + return TRUE; + } + + memset(&ce, 0, sizeof(struct config_entry)); + /* get next available entry from LIST entry. */ + if (!get_next_list_entry(le, 0, NULL, &ce)) + return TRUE; + + if (ie->next) { + /* we are dealing with list_head */ + ie->next->vaddr = ce.vaddr; + ie->vaddr = ce.vaddr - ie->next->offset; + } else { + ie->vaddr = ce.vaddr; + ie->sym_addr = ce.sym_addr; + ie->size = ce.size; + } + return FALSE; +} + +/* + * Process the config entry that has been read by get_config. + * return TRUE on success + */ +static int +process_config(struct config *config) +{ + int i; + unsigned char type_flag; + char *type_name = NULL; + + if (config->list_entry) { + /* + * We are dealing with 'for' command. + * - First resolve list entry. + * - Initialize iteration entry for iteration. + * - Populate iteration entry untill list entry empty. + */ + if (!resolve_list_entry(config->list_entry, 0, NULL, + &type_name, &type_flag)) { + return FALSE; + } + if (!initialize_iteration_entry(config->iter_entry, + type_name, type_flag)) { + return FALSE; + } + + while (!list_entry_empty(config->list_entry, + config->iter_entry)) { + for (i = 0; i < config->num_filter_symbols; i++) + update_filter_info(config->filter_symbol[i], + config->size_symbol[i]); + } + } else + update_filter_info(config->filter_symbol[0], + config->size_symbol[0]); + + return TRUE; +} + +static void +print_filter_info() +{ + struct filter_info *fl_info = filter_info; + + DEBUG_MSG("\n"); + while (fl_info) { + DEBUG_MSG("filter address: paddr (%llx), sym_addr (%llx)," + " Size (%ld)\n", + fl_info->paddr, fl_info->vaddr, fl_info->size); + fl_info = fl_info->next; + } +} + +static void +init_filter_config() +{ + filter_config.name_filterconfig = info->name_filterconfig; + filter_config.file_filterconfig = info->file_filterconfig; + filter_config.saved_token = NULL; + filter_config.token = NULL; + filter_config.cur_module = NULL; + filter_config.new_section = 0; + filter_config.line_count = 0; +} + +/* + * Read and process each config entry (filter commands) from filter config + * file. If no module debuginfo found for specified module section then skip + * to next module section. + */ +static int +process_config_file(const char *name_config) +{ + struct config *config; + int skip_section = 0; + + if (!name_config) + return FALSE; + + if ((info->file_filterconfig = fopen(name_config, "r")) == NULL) { + ERRMSG("Can't open config file(%s). %s\n", + name_config, strerror(errno)); + return FALSE; + } + + init_filter_config(); + + while((config = get_config(skip_section)) != NULL) { + skip_section = 0; + if (config->module_name && + strcmp(config->module_name, "vmlinux")) { + /* + * if Module debuginfo is not available, then skip to + * next module section. + */ + if (!set_dwarf_debuginfo(config->module_name, + info->system_utsname.release, NULL, -1)) { + ERRMSG("Skipping to next Module section\n"); + skip_section = 1; + free_config(config); + continue; + } + } else { + set_dwarf_debuginfo("vmlinux", NULL, + info->name_vmlinux, info->fd_vmlinux); + } + process_config(config); + free_config(config); + } + + fclose(info->file_filterconfig); + print_filter_info(); + return TRUE; +} + + +/* Process the eppic macro using eppic library */ +static int +process_eppic_file(char *name_config) +{ + void *handle; + void (*eppic_load)(char *), (*eppic_unload)(char *); + int (*eppic_init)(); + + /* + * Dynamically load the eppic_makedumpfile.so library. + */ + handle = dlopen("eppic_makedumpfile.so", RTLD_LAZY); + if (!handle) { + ERRMSG("dlopen failed: %s\n", dlerror()); + return FALSE; + } + + /* TODO + * Support specifying eppic macros in makedumpfile.conf file + */ + + eppic_init = dlsym(handle, "eppic_init"); + if (!eppic_init) { + ERRMSG("Could not find eppic_init function\n"); + return FALSE; + } + + eppic_load = dlsym(handle, "eppic_load"); + if (!eppic_load) { + ERRMSG("Could not find eppic_load function\n"); + return FALSE; + } + + eppic_unload = dlsym(handle, "eppic_unload"); + if (!eppic_unload) + ERRMSG("Could not find eppic_unload function\n"); + + if (eppic_init(&eppic_cb)) { + ERRMSG("Init failed \n"); + return FALSE; + } + + /* Load/compile, execute and unload the eppic macro */ + eppic_load(name_config); + eppic_unload(name_config); + + if (dlclose(handle)) + ERRMSG("dlclose failed: %s\n", dlerror()); + + return TRUE; +} + +static void +split_filter_info(struct filter_info *prev, unsigned long long next_paddr, + size_t size) +{ + struct filter_info *new; + + if ((new = calloc(1, sizeof(struct filter_info))) == NULL) { + ERRMSG("Can't allocate memory to split filter info\n"); + return; + } + new->nullify = prev->nullify; + new->erase_info_idx = prev->erase_info_idx; + new->size_idx = prev->size_idx; + new->paddr = next_paddr; + new->size = size; + new->next = prev->next; + prev->next = new; +} + +static void +update_erase_info(struct filter_info *fi) +{ + struct erase_info *ei; + + if (!fi->erase_info_idx) + return; + + ei = &erase_info[fi->erase_info_idx]; + + if (!ei->sizes) { + /* First time, allocate sizes array */ + ei->sizes = calloc(ei->num_sizes, sizeof(long)); + if (!ei->sizes) { + ERRMSG("Can't allocate memory for erase info sizes\n"); + return; + } + } + ei->erased = 1; + if (!fi->nullify) + ei->sizes[fi->size_idx] += fi->size; + else + ei->sizes[fi->size_idx] = -1; +} + +static int +extract_filter_info(unsigned long long start_paddr, + unsigned long long end_paddr, + struct filter_info *fl_info) +{ + struct filter_info *fi = filter_info; + struct filter_info *prev = NULL; + size_t size1, size2; + + if (!fl_info) + return FALSE; + + while (fi) { + if ((fi->paddr >= start_paddr) && (fi->paddr < end_paddr)) { + size1 = end_paddr - fi->paddr; + if (fi->size <= size1) + break; + size2 = fi->size - size1; + fi->size = size1; + split_filter_info(fi, fi->paddr + size1, size2); + break; + } + prev = fi; + fi = fi->next; + } + if (!fi) + return FALSE; + + *fl_info = *fi; + fl_info->next = NULL; + + /* Delete this node */ + if (!prev) + filter_info = fi->next; + else + prev->next = fi->next; + update_erase_info(fi); + free(fi); + + return TRUE; +} + + +/* + * External functions. + */ +int +gather_filter_info(void) +{ + int ret = TRUE; + + /* + * Before processing filter config file, load the symbol data of + * loaded modules from vmcore. + */ + set_dwarf_debuginfo("vmlinux", NULL, + info->name_vmlinux, info->fd_vmlinux); + if (!load_module_symbols()) + return FALSE; + + /* + * XXX: We support specifying both makedumpfile.conf and + * eppic macro at the same time. Whether to retain or discard the + * functionality provided by makedumpfile.conf is open for + * discussion + */ + if (info->name_filterconfig) + ret = process_config_file(info->name_filterconfig); + + if (info->name_eppic_config) + ret &= process_eppic_file(info->name_eppic_config); + + /* + * Remove modules symbol information, we dont need now. + * Reset the dwarf debuginfo to vmlinux to close open file + * descripter of module debuginfo file, if any. + */ + clean_module_symbols(); + set_dwarf_debuginfo("vmlinux", NULL, + info->name_vmlinux, info->fd_vmlinux); + return ret; +} + +void +clear_filter_info(void) +{ + struct filter_info *prev, *fi = filter_info; + int i; + + /* Delete filter_info nodes that are left out. */ + while (fi) { + prev = fi; + fi = fi->next; + free(prev); + } + filter_info = NULL; + + if (erase_info == NULL) + return; + + for (i = 1; i < num_erase_info; i++) { + free(erase_info[i].symbol_expr); + free(erase_info[i].sizes); + } + free(erase_info); + erase_info = NULL; +} + +/* + * Filter buffer if the physical address is in filter_info. + */ +void +filter_data_buffer(unsigned char *buf, unsigned long long paddr, + size_t size) +{ + struct filter_info fl_info; + unsigned char *buf_ptr; + + while (extract_filter_info(paddr, paddr + size, &fl_info)) { + buf_ptr = buf + (fl_info.paddr - paddr); + if (fl_info.nullify) + memset(buf_ptr, 0, fl_info.size); + else + memset(buf_ptr, fl_info.erase_ch, fl_info.size); + } +} + +unsigned long +get_size_eraseinfo(void) +{ + unsigned long size_eraseinfo = 0; + char size_str[MAX_SIZE_STR_LEN]; + struct erase_info *ei; + struct filter_info *fl_info = filter_info; + + while (fl_info) { + + if (!fl_info->erase_info_idx) + continue; + ei = &erase_info[fl_info->erase_info_idx]; + if (fl_info->nullify) + sprintf(size_str, "nullify\n"); + else + sprintf(size_str, "size %ld\n", fl_info->size); + + size_eraseinfo += strlen("erase ") + + strlen(ei->symbol_expr) + 1 + + strlen(size_str); + fl_info = fl_info->next; + } + + return size_eraseinfo; +} + diff -Nupr makedumpfile-1.3.5/erase_info.h makedumpfile-1.5.3/erase_info.h --- makedumpfile-1.3.5/erase_info.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/erase_info.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,60 @@ +/* + * erase_info.h + * + * Created by: Mahesh J Salgaonkar + * + * Copyright (C) 2011 IBM Corporation + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _ERASE_INFO_H +#define _ERASE_INFO_H + +#define MAX_SIZE_STR_LEN (26) + +/* + * Erase information, original symbol expressions. + */ +struct erase_info { + char *symbol_expr; + int num_sizes; + long *sizes; + int erased; /* 1= erased, 0= Not erased */ +}; + +struct call_back { + long (*get_domain)(char *, int, unsigned long long *); + int (*readmem)(int type_addr, unsigned long long addr, void *bufptr, + size_t size); + int (*get_die_attr_type)(unsigned long long die_off, int *type_flag, + unsigned long long *die_attr_off); + char * (*get_die_name)(unsigned long long die_off); + unsigned long long (*get_die_offset)(char *sysname); + int (*get_die_length)(unsigned long long die_off, int flag); + int (*get_die_member)(unsigned long long die_off, int index, long *offset, + char **name, int *nbits, int *fbits, unsigned long long *m_die); + int (*get_die_nfields)(unsigned long long die_off); + unsigned long long (*get_symbol_addr)(char *symname); + int (*update_filter_info_raw)(unsigned long long, int, int); +}; + +extern struct erase_info *erase_info; +extern unsigned long num_erase_info; + +int gather_filter_info(void); +void clear_filter_info(void); +void filter_data_buffer(unsigned char *buf, unsigned long long paddr, size_t size); +unsigned long get_size_eraseinfo(void); +int update_filter_info_raw(unsigned long long, int, int); + +#endif /* _ERASE_INFO_H */ + diff -Nupr makedumpfile-1.3.5/extension_eppic.c makedumpfile-1.5.3/extension_eppic.c --- makedumpfile-1.3.5/extension_eppic.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/extension_eppic.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,452 @@ +/* + * extension_eppic.c + * + * Created by: Aravinda Prasad + * + * Copyright (C) 2012, 2013 IBM Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include + +#include "makedumpfile.h" +#include "extension_eppic.h" + +/* + * Most of the functions included in this file performs similar + * functionality as in the applications/crash/eppic.c file part of + * eppic, but uses DWARF instead of gdb. Few of the functions are + * reused directly which are acknowledged in the comment before the + * function. + */ + +/* + * This is the call back function called when a new eppic macro is + * loaded. This will execute the loaded eppic macro. + * + * "fname" is considered as the entry point of an eppic macro only if + * the following functions are defined: + * + * fname_help() + * fname_usage() + * + * These functions have no relevance in makedumpfile context as + * makedumpfile automatically executes the eppic macro by calling the + * entry point and user will not have any option to execute the usage + * or help functions. However they are required to identify the entry + * points in the eppic macro. + */ +void +reg_callback(char *name, int load) +{ + char fname[MAX_SYMNAMELEN]; + + /* Nothing to process for unload request */ + if (!load) + return; + + snprintf(fname, sizeof(fname), "%s_help", name); + if (eppic_chkfname(fname, 0)) { + snprintf(fname, sizeof(fname), "%s_usage", name); + if (eppic_chkfname(fname, 0)) + eppic_cmd(name, NULL, 0); + } + return; +} + +/* + * This function is a copy of eppic_setupidx() function in + * applications/crash/eppic.c file from eppic source code + * repository. + * + * set idx value to actual array indexes from specified size + */ +static void +eppic_setupidx(TYPE_S *t, int ref, int nidx, int *idxlst) +{ + /* put the idxlst in index size format */ + if (nidx) { + int i; + for (i = 0; i < nidx - 1; i++) { + /* kludge for array dimensions of [1] */ + if (idxlst[i + 1] == 0) + idxlst[i + 1] = 1; + idxlst[i] = idxlst[i] / idxlst[i + 1]; + } + + /* divide by element size for last element bound */ + if (ref) + idxlst[i] /= eppic_defbsize(); + else + idxlst[i] /= eppic_type_getsize(t); + eppic_type_setidxlst(t, idxlst); + } +} + +/* + * Call back functions for eppic to query the dump image + */ + +static int +apigetmem(ull iaddr, void *p, int nbytes) +{ + return READMEM(VADDR, iaddr, p, nbytes); +} + +static int +apiputmem(ull iaddr, void *p, int nbytes) +{ + return 1; +} + +/* + * Drill down the type of the member and update eppic with information + * about the member + */ +static char * +drilldown(ull offset, type_t *t) +{ + int type_flag, len = 0, t_len = 0, nidx = 0; + int fctflg = 0, ref = 0, *idxlst = 0; + ull die_off = offset, t_die_off; + char *tstr = NULL; + + while (GET_DIE_ATTR_TYPE(die_off, &type_flag, &t_die_off)) { + switch (type_flag) { + /* typedef inserts a level of reference to the actual type */ + case DW_TAG_pointer_type: + ref++; + die_off = t_die_off; + /* + * This could be a void *, in which case the drill + * down stops here + */ + if (!GET_DIE_ATTR_TYPE(die_off, &type_flag, + &t_die_off)) { + /* make it a char* */ + eppic_parsetype("char", t, ref); + return eppic_strdup(""); + } + break; + /* Handle pointer to function */ + case DW_TAG_subroutine_type: + fctflg = 1; + die_off = t_die_off; + break; + /* Handle arrays */ + case DW_TAG_array_type: + if (!idxlst) { + idxlst = eppic_calloc(sizeof(int) * \ + (MAX_ARRAY_DIMENSION + 1)); + if (!idxlst) { + ERRMSG("Out of memory\n"); + return NULL; + } + } + if (nidx >= MAX_ARRAY_DIMENSION) { + ERRMSG("Too many array indexes. Max=%d\n", + MAX_ARRAY_DIMENSION); + return NULL; + } + + /* handle multi-dimensional array */ + len = GET_DIE_LENGTH(die_off, FALSE); + t_len = GET_DIE_LENGTH(t_die_off, FALSE); + if (len > 0 && t_len > 0) + idxlst[nidx++] = len / t_len; + die_off = t_die_off; + break; + /* Handle typedef */ + case DW_TAG_typedef: + die_off = t_die_off; + break; + case DW_TAG_base_type: + eppic_parsetype(tstr = GET_DIE_NAME(t_die_off), t, 0); + goto out; + case DW_TAG_union_type: + eppic_type_mkunion(t); + goto label; + case DW_TAG_enumeration_type: + eppic_type_mkenum(t); + goto label; + case DW_TAG_structure_type: + eppic_type_mkstruct(t); + goto label; + /* Unknown TAG ? */ + default: + die_off = t_die_off; + break; + } + } + +label: + eppic_type_setsize(t, GET_DIE_LENGTH(t_die_off, TRUE)); + eppic_type_setidx(t, (ull)t_die_off); + tstr = GET_DIE_NAME(t_die_off); + +out: + eppic_setupidx(t, ref, nidx, idxlst); + if (fctflg) + eppic_type_setfct(t, 1); + eppic_pushref(t, ref + (nidx ? 1 : 0)); + if (tstr) + return eppic_strdup(tstr); + return eppic_strdup(""); +} + +/* + * Get the type, size and position information for a member of a structure. + */ +static char * +apimember(char *mname, ull idx, type_t *tm, member_t *m, ull *last_index) +{ + int index, nfields = -1, size; + int nbits = 0, fbits = 0; + long offset; + ull m_die, die_off = idx; + char *name; + + nfields = GET_DIE_NFIELDS(die_off); + /* + * GET_DIE_NFIELDS() returns < 0 if the die is not structure type + * or union type + */ + if (nfields <= 0) + return NULL; + + /* if we're being asked the next member in a getfirst/getnext + * sequence + */ + if (mname && !mname[0] && last_index && (*last_index)) + index = *last_index; + else + index = 0; + + while (index < nfields) { + size = GET_DIE_MEMBER(die_off, index, &offset, &name, &nbits, + &fbits, &m_die); + + if (size < 0) + return NULL; + + if (!mname || !mname[0] || !strcmp(mname, name)) { + eppic_member_ssize(m, size); + if (name) + eppic_member_sname(m, name); + else + eppic_member_sname(m, ""); + eppic_member_soffset(m, offset); + eppic_member_snbits(m, nbits); + eppic_member_sfbit(m, fbits); + *last_index = index + 1; + return drilldown(m_die, tm); + } + index++; + } + return NULL; +} + +static int +apigetctype(int ctype, char *name, type_t *tout) +{ + long size = 0; + unsigned long long die = 0; + + switch (ctype) { + case V_TYPEDEF: + size = GET_DOMAIN(name, DWARF_INFO_GET_DOMAIN_TYPEDEF, &die); + break; + case V_STRUCT: + size = GET_DOMAIN(name, DWARF_INFO_GET_DOMAIN_STRUCT, &die); + break; + case V_UNION: + size = GET_DOMAIN(name, DWARF_INFO_GET_DOMAIN_UNION, &die); + break; + /* TODO + * Implement for all the domains + */ + } + + if (size <= 0 || !die) + return 0; + + /* populate */ + eppic_type_settype(tout, ctype); + eppic_type_setsize(tout, size); + eppic_type_setidx(tout, (ull)(unsigned long)die); + eppic_pushref(tout, 0); + return 1; +} + +static char * +apigetrtype(ull idx, type_t *t) +{ + return drilldown(idx, t); +} + +static int +apialignment(ull idx) +{ + return 0; +} + +int +apigetval(char *name, ull *val, VALUE_S *value) +{ + ull ptr = 0; + + ptr = GET_SYMBOL_ADDR(name); + if (!ptr) + return 0; + + *val = ptr; + + if (!value) + return 1; + + /* Support for fully typed symbol access */ + ull type; + TYPE_S *stype; + + type = GET_DIE_OFFSET(name); + stype = eppic_gettype(value); + + apigetrtype(type, stype); + + eppic_pushref(stype, 1); + eppic_setmemaddr(value, *val); + eppic_do_deref(1, value, value); + + *val = eppic_getval(value); + + if (!eppic_typeislocal(stype) && eppic_type_getidx(stype) > 100) { + char *tname = GET_DIE_NAME(eppic_type_getidx(stype)); + if (tname) + eppic_chktype(stype, tname); + } + return 1; +} + +static enum_t * +apigetenum(char *name) +{ + return 0; +} + +static def_t * +apigetdefs(void) +{ + return 0; +} + +static uint8_t +apigetuint8(void *ptr) +{ + uint8_t val; + if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val))) + return (uint8_t) -1; + return val; +} + +static uint16_t +apigetuint16(void *ptr) +{ + uint16_t val; + if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val))) + return (uint16_t) -1; + return val; +} + +static uint32_t +apigetuint32(void *ptr) +{ + uint32_t val; + if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val))) + return (uint32_t) -1; + return val; +} + +static uint64_t +apigetuint64(void *ptr) +{ + uint64_t val; + if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val))) + return (uint64_t) -1; + return val; +} + +static char * +apifindsym(char *p) +{ + return NULL; +} + +apiops icops = { + apigetmem, + apiputmem, + apimember, + apigetctype, + apigetrtype, + apialignment, + apigetval, + apigetenum, + apigetdefs, + apigetuint8, + apigetuint16, + apigetuint32, + apigetuint64, + apifindsym +}; + +/* Extensions to built-in functions */ +VALUE_S * +eppic_memset(VALUE_S *vaddr, VALUE_S *vch, VALUE_S *vlen) +{ + ull addr = eppic_getval(vaddr); + int len = eppic_getval(vlen); + int ch = eppic_getval(vch); + + /* + * Set the value at address from iaddr till iaddr + nbytes + * to the value specified in variable ch + */ + UPDATE_FILTER_INFO_RAW(addr, ch, len); + return eppic_makebtype(1); +} + + +/* Initialize eppic */ +int +eppic_init(void *fun_ptr) +{ + cb = (struct call_back *)fun_ptr; + + if (eppic_open() >= 0) { + + /* Register call back functions */ + eppic_apiset(&icops, 3, sizeof(long), 0); + + /* set the new function callback */ + eppic_setcallback(reg_callback); + + /* Extend built-in functions to include memset */ + eppic_builtin("int memset(char *, int, int)", + (bf_t *)eppic_memset); + + return 0; + } + return 1; +} + diff -Nupr makedumpfile-1.3.5/extension_eppic.h makedumpfile-1.5.3/extension_eppic.h --- makedumpfile-1.3.5/extension_eppic.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/extension_eppic.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,95 @@ +/* + * extension_eppic.h + * + * Created by: Aravinda Prasad + * + * Copyright (C) 2012, 2013 IBM Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _EXTENSION_EPPIC_H +#define _EXTENSION_EPPIC_H + +#include "eppic_api.h" +#include "erase_info.h" + +/* + * MEMBER_S, ENUM_S, DEF_S and TYPE_S are extracts from eppic header + * file eppic.h. The reason for not including the eppic.h header file + * in this file is because, lot of things in eppic.h are not required + * for makedumpfile extension. + */ + +#define MAX_ARRAY_DIMENSION 16 + +/* member information */ +typedef MEMBER_S { + + char *name; + int offset; /* offset from top of structure */ + int size; /* size in bytes of the member or of the bit array */ + int fbit; /* fist bit (-1) is not a bit field */ + int nbits; /* number of bits for this member */ + int value; /* for a enum member, the corresponding value_t */ + +} member_t; + +/* list to hold enum constant information */ +typedef ENUM_S { + struct enum_s *next; + char *name; + int value; + +} enum_t; + +/* list of macro symbols and there corresponding value_ts */ +typedef DEF_S { + struct def_s *next; + char *name; + char *val; + +} def_t; + + +typedef TYPE_S { + int type; /* type_t of type_t */ + ull idx; /* index to basetype_t or ctype_t */ + int size; /* size of this item */ + /* ... next fields are use internally */ + int typattr; /* base type_t qualifiers */ + int ref; /* level of reference */ + int fct; /* 1 if function pointer */ + int *idxlst; /* points to list of indexes if array */ + ull rtype; /* type_t a reference refers too */ +} type_t; + +#define ERRMSG(x...) \ +do { \ + fprintf(stderr, __FUNCTION__); \ + fprintf(stderr, ": "); \ + fprintf(stderr, x); \ +} while (0) + + +struct call_back *cb; + +#define GET_DOMAIN cb->get_domain +#define READMEM cb->readmem +#define GET_DIE_ATTR_TYPE cb->get_die_attr_type +#define GET_DIE_NAME cb->get_die_name +#define GET_DIE_OFFSET cb->get_die_offset +#define GET_DIE_LENGTH cb->get_die_length +#define GET_DIE_MEMBER cb->get_die_member +#define GET_DIE_NFIELDS cb->get_die_nfields +#define GET_SYMBOL_ADDR cb->get_symbol_addr +#define UPDATE_FILTER_INFO_RAW cb->update_filter_info_raw + +#endif /* _EXTENSION_EPPIC_H */ diff -Nupr makedumpfile-1.3.5/ia64.c makedumpfile-1.5.3/ia64.c --- makedumpfile-1.3.5/ia64.c 2009-10-09 09:51:18.000000000 +0800 +++ makedumpfile-1.5.3/ia64.c 1970-01-01 08:00:00.000000000 +0800 @@ -1,376 +0,0 @@ -/* - * ia64.c - * - * Copyright (C) 2006, 2007, 2008 NEC Corporation - * - * 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 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifdef __ia64__ - -#include "makedumpfile.h" - - -/* - * vmalloc() starting address is either the traditional 0xa000000000000000 or - * bumped up in 2.6 to 0xa000000200000000. - */ -int -is_vmalloc_addr_ia64(unsigned long vaddr) -{ - return ((vaddr >= info->vmalloc_start) && - (vaddr < (unsigned long)KERNEL_UNCACHED_BASE)); -} - -int -get_phys_base_ia64(void) -{ - int i; - struct pt_load_segment *pls; - - /* - * Default to 64MB. - */ - info->phys_base = DEFAULT_PHYS_START; - - for (i = 0; i < info->num_load_memory; i++) { - pls = &info->pt_load_segments[i]; - if (VADDR_REGION(pls->virt_start) == KERNEL_VMALLOC_REGION) { - - info->phys_base = pls->phys_start; - break; - } - } - return TRUE; -} - -int -get_machdep_info_ia64(void) -{ - /* - * Get kernel_start and vmalloc_start. - */ - if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) - return FALSE; - - info->kernel_start = SYMBOL(_stext); - - if (VADDR_REGION(info->kernel_start) == KERNEL_VMALLOC_REGION) - info->vmalloc_start = info->kernel_start + 4*1024UL*1024UL*1024UL; - else - info->vmalloc_start = KERNEL_VMALLOC_BASE; - - /* - * Check the pgtable (3 Levels or 4 Levels). - */ - if ((vt.mem_flags & MEMORY_PAGETABLE_4L) - || !strncmp(SRCFILE(pud_t), STR_PUD_T_4L, strlen(STR_PUD_T_4L))) { - vt.mem_flags |= MEMORY_PAGETABLE_4L; - DEBUG_MSG("PAGETABLE_4L : ON\n"); - } else if ((vt.mem_flags & MEMORY_PAGETABLE_3L) - || !strncmp(SRCFILE(pud_t), STR_PUD_T_3L, strlen(STR_PUD_T_3L))) { - vt.mem_flags |= MEMORY_PAGETABLE_3L; - DEBUG_MSG("PAGETABLE_3L : ON\n"); - } else { - MSG("Can't distinguish the pgtable.\n"); - } - - info->section_size_bits = _SECTION_SIZE_BITS; - info->max_physmem_bits = _MAX_PHYSMEM_BITS; - - return TRUE; -} - -/* - * Translate a virtual address to a physical address by using 3 levels paging. - */ -unsigned long long -vtop3_ia64(unsigned long vaddr) -{ - unsigned long long paddr, temp, page_dir, pgd_pte, page_middle, pmd_pte; - unsigned long long page_table, pte; - - if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); - return NOT_PADDR; - } - - /* - * Get PGD - */ - temp = vaddr & MASK_PGD_3L; - temp = temp >> (PGDIR_SHIFT_3L - 3); - page_dir = SYMBOL(swapper_pg_dir) + temp; - if (!readmem(VADDR, page_dir, &pgd_pte, sizeof pgd_pte)) { - ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PGD : %16llx => %16llx\n", page_dir, pgd_pte); - - /* - * Get PMD - */ - temp = vaddr & MASK_PMD; - temp = temp >> (PMD_SHIFT - 3); - page_middle = pgd_pte + temp; - if (!readmem(PADDR, page_middle, &pmd_pte, sizeof pmd_pte)) { - ERRMSG("Can't get pmd_pte (page_middle:%llx).\n", page_middle); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PMD : %16llx => %16llx\n", page_middle, pmd_pte); - - /* - * Get PTE - */ - temp = vaddr & MASK_PTE; - temp = temp >> (PAGESHIFT() - 3); - page_table = pmd_pte + temp; - if (!readmem(PADDR, page_table, &pte, sizeof pte)) { - ERRMSG("Can't get pte (page_table:%llx).\n", page_table); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PTE : %16llx => %16llx\n", page_table, pte); - - /* - * Get physical address - */ - temp = vaddr & MASK_POFFSET; - paddr = (pte & _PAGE_PPN_MASK) + temp; - - return paddr; -} - -/* - * Translate a virtual address to a physical address by using 4 levels paging. - */ -unsigned long long -vtop4_ia64(unsigned long vaddr) -{ - unsigned long long paddr, temp, page_dir, pgd_pte, page_upper, pud_pte; - unsigned long long page_middle, pmd_pte, page_table, pte; - - if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); - return NOT_PADDR; - } - - /* - * Get PGD - */ - temp = vaddr & MASK_PGD_4L; - temp = temp >> (PGDIR_SHIFT_4L - 3); - page_dir = SYMBOL(swapper_pg_dir) + temp; - if (!readmem(VADDR, page_dir, &pgd_pte, sizeof pgd_pte)) { - ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PGD : %16llx => %16llx\n", page_dir, pgd_pte); - - /* - * Get PUD - */ - temp = vaddr & MASK_PUD; - temp = temp >> (PUD_SHIFT - 3); - page_upper = pgd_pte + temp; - if (!readmem(PADDR, page_upper, &pud_pte, sizeof pud_pte)) { - ERRMSG("Can't get pud_pte (page_upper:%llx).\n", page_upper); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PUD : %16llx => %16llx\n", page_upper, pud_pte); - - /* - * Get PMD - */ - temp = vaddr & MASK_PMD; - temp = temp >> (PMD_SHIFT - 3); - page_middle = pud_pte + temp; - if (!readmem(PADDR, page_middle, &pmd_pte, sizeof pmd_pte)) { - ERRMSG("Can't get pmd_pte (page_middle:%llx).\n", page_middle); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PMD : %16llx => %16llx\n", page_middle, pmd_pte); - - /* - * Get PTE - */ - temp = vaddr & MASK_PTE; - temp = temp >> (PAGESHIFT() - 3); - page_table = pmd_pte + temp; - if (!readmem(PADDR, page_table, &pte, sizeof pte)) { - ERRMSG("Can't get pte (page_table:%llx).\n", page_table); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PTE : %16llx => %16llx\n", page_table, pte); - - /* - * Get physical address - */ - temp = vaddr & MASK_POFFSET; - paddr = (pte & _PAGE_PPN_MASK) + temp; - - return paddr; -} - -unsigned long long -vtop_ia64(unsigned long vaddr) -{ - unsigned long long paddr; - - if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) { - ERRMSG("vaddr(%lx) is not KERNEL_VMALLOC_REGION.\n", vaddr); - return NOT_PADDR; - } - paddr = vaddr_to_paddr_general(vaddr); - if (paddr != NOT_PADDR) - return paddr; - - if (!is_vmalloc_addr_ia64(vaddr)) { - paddr = vaddr - info->kernel_start + - (info->phys_base & KERNEL_TR_PAGE_MASK); - return paddr; - } - - if (vt.mem_flags & MEMORY_PAGETABLE_4L) - return vtop4_ia64(vaddr); - else - return vtop3_ia64(vaddr); -} - -/* - * Translate a virtual address to physical address. - */ -unsigned long long -vaddr_to_paddr_ia64(unsigned long vaddr) -{ - unsigned long long paddr; - - switch (VADDR_REGION(vaddr)) { - case KERNEL_CACHED_REGION: - paddr = vaddr - (ulong)(KERNEL_CACHED_BASE); - break; - - case KERNEL_UNCACHED_REGION: - paddr = vaddr - (ulong)(KERNEL_UNCACHED_BASE); - break; - - case KERNEL_VMALLOC_REGION: - paddr = vtop_ia64(vaddr); - break; - - default: - ERRMSG("Unknown region (%ld)\n", VADDR_REGION(vaddr)); - return 0x0; - } - return paddr; -} - -/* - * for Xen extraction - */ -unsigned long long -kvtop_xen_ia64(unsigned long kvaddr) -{ - unsigned long long addr, dirp, entry; - - if (!is_xen_vaddr(kvaddr)) - return NOT_PADDR; - - if (is_direct(kvaddr)) - return (unsigned long)kvaddr - DIRECTMAP_VIRT_START; - - if (!is_frame_table_vaddr(kvaddr)) - return NOT_PADDR; - - addr = kvaddr - VIRT_FRAME_TABLE_ADDR; - - dirp = SYMBOL(frametable_pg_dir) - DIRECTMAP_VIRT_START; - dirp += ((addr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - dirp = entry & _PFN_MASK; - if (!dirp) - return NOT_PADDR; - - dirp += ((addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - dirp = entry & _PFN_MASK; - if (!dirp) - return NOT_PADDR; - - dirp += ((addr >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_P)) - return NOT_PADDR; - - entry = (entry & _PFN_MASK) + (addr & ((1UL << PAGESHIFT()) - 1)); - - return entry; -} - -int -get_xen_info_ia64(void) -{ - unsigned long xen_start, xen_end, xen_heap_start; - int i; - - info->frame_table_vaddr = VIRT_FRAME_TABLE_ADDR; /* "frame_table" is same value */ - - if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of xenheap_phys_end.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end, - sizeof(xen_end))) { - ERRMSG("Can't get the value of xenheap_phys_end.\n"); - return FALSE; - } - if (SYMBOL(xen_pstart) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of xen_pstart.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(xen_pstart), &xen_start, - sizeof(xen_start))) { - ERRMSG("Can't get the value of xen_pstart.\n"); - return FALSE; - } - info->xen_heap_start = paddr_to_pfn(xen_start); - info->xen_heap_end = paddr_to_pfn(xen_end); - - if (SYMBOL(xen_heap_start) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of xen_heap_start.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(xen_heap_start), &xen_heap_start, - sizeof(xen_heap_start))) { - ERRMSG("Can't get the value of xen_heap_start.\n"); - return FALSE; - } - for (i = 0; i < info->num_domain; i++) { - info->domain_list[i].pickled_id = (unsigned int) - (info->domain_list[i].domain_addr - xen_heap_start); - } - - return TRUE; -} - -#endif /* ia64 */ - diff -Nupr makedumpfile-1.3.5/IMPLEMENTATION makedumpfile-1.5.3/IMPLEMENTATION --- makedumpfile-1.3.5/IMPLEMENTATION 2013-07-03 15:18:37.822089017 +0800 +++ makedumpfile-1.5.3/IMPLEMENTATION 2013-02-18 16:47:26.000000000 +0800 @@ -60,7 +60,7 @@ }; - sub header - The sub header of the kdump compressed format is orignal. This header + The sub header of the kdump compressed format is original. This header has the member phys_base and dump_level. The member phys_base is for an x86_64 relocatable kernel, and the member dump_level has '-d' option's value of makedumpfile command. @@ -68,10 +68,10 @@ struct kdump_sub_header { unsigned long phys_base; int dump_level; /* header_version 1 and later */ - int split; /* header_version 2 and later */ - unsigned long start_pfn; /* header_version 2 and later */ - unsigned long end_pfn; /* header_version 2 and later */ - off_t offset_vmcoreinfo;/* header_version 3 and later */ + int split; /* header_version 2 and later */ + unsigned long start_pfn; /* header_version 2 and later */ + unsigned long end_pfn; /* header_version 2 and later */ + off_t offset_vmcoreinfo;/* header_version 3 and later */ unsigned long size_vmcoreinfo; /* header_version 3 and later */ off_t offset_note; /* header_version 4 and later */ unsigned long size_note; /* header_version 4 and later */ diff -Nupr makedumpfile-1.3.5/makedumpfile.8 makedumpfile-1.5.3/makedumpfile.8 --- makedumpfile-1.3.5/makedumpfile.8 2013-07-03 15:18:37.896089017 +0800 +++ makedumpfile-1.5.3/makedumpfile.8 2013-07-03 16:53:12.876085585 +0800 @@ -6,7 +6,7 @@ makedumpfile \- make a small dumpfile of .br \fBmakedumpfile\fR \-F [\fIOPTION\fR] [\-x \fIVMLINUX\fR|\-i \fIVMCOREINFO\fR] \fIVMCORE\fR .br -\fBmakedumpfile\fR [\fIOPTION\fR] \-x \fIVMLINUX\fR \-\-config \fIFILTERCONFIGFILE\fR \fIVMCORE\fR \fIDUMPFILE\fR +\fBmakedumpfile\fR [\fIOPTION\fR] \-x \fIVMLINUX\fR [\-\-config \fIFILTERCONFIGFILE\fR] [\-\-eppic \fIEPPICMACRO\fR] \fIVMCORE\fR \fIDUMPFILE\fR .br \fBmakedumpfile\fR \-R \fIDUMPFILE\fR .br @@ -45,7 +45,9 @@ be excluded. .br .B \- Pages filled with zero .br -.B \- Cache pages +.B \- Cache pages without private pages +.br +.B \- All cache pages with private pages .br .B \- User process data pages .br @@ -66,7 +68,16 @@ filtered out through the erase command s config and builds the list of memory addresses and its sizes after processing filter commands. The memory locations that require to be filtered out are then poisoned with character 'X' (58 in Hex). Refer to -\fBmakedumpfile.conf(8)\fR for file format. +\fBmakedumpfile.conf(5)\fR for file format. +.PP +Eppic macros can also be used to specify kernel symbols and its members that +need to be filtered. Eppic provides C semantics including language constructs +such as conditional statements, logical and arithmetic operators, functions, +nested loops to traverse and erase kernel data. --eppic requires +\fBeppic_makedumpfile.so\fR and eppic library. \fBeppic_makedumpfile.so\fR +can be built from makedumpfile source. Refer to +\fBhttp://code.google.com/p/eppic/\fR to build eppic library \fBlibeppic.a\fR +and for more information on writing eppic macros. .PP To analyze the first kernel's memory usage, makedumpfile can refer to \fIVMCOREINFO\fR instead of \fIVMLINUX\fR. \fIVMCOREINFO\fR contains the first @@ -87,9 +98,9 @@ a user needs to transport the dump data data by SSH, makedumpfile outputs the dump data in the intermediate format (the flattened format) to the standard output. By piping the output data to SSH, a user can transport the dump data to a remote host. Note that analysis tools -cannot read the flattened format directly, so on a remote host the received -data in the flattened format needs to be rearranged to a readable -\fIDUMPFILE\fR format by makedumpfile (or makedumpfile\-R.pl). +(crash utility before version 5.1.2 or GDB) cannot read the flattened format +directly, so on a remote host the received data in the flattened format needs +to be rearranged to a readable \fIDUMPFILE\fR format by makedumpfile (or makedumpfile\-R.pl). .PP makedumpfile can read a \fIDUMPFILE\fR in the kdump-compressed format instead of \fIVMCORE\fR and re-filter it. This feature is useful in situation that @@ -119,8 +130,10 @@ configuration, you need to use --diskset .SH OPTIONS .TP -\fB\-c\fR -Compress dump data by each page. +\fB\-c,\-l,\-p\fR +Compress dump data by each page using zlib for -c option, lzo for -l +option or snappy for -p option. +(-l option needs USELZO=on and -p option needs USESNAPPY=on when building) .br A user cannot specify this option with \-E option, because the ELF format does not support compressed data. @@ -151,50 +164,51 @@ by dump_level 11, makedumpfile retries i .br # makedumpfile \-d 11,31 \-x vmlinux /proc/vmcore dumpfile - dump | zero | cache|cache | user | free - level | page | page |private| data | page -.br -\-\-\-\-\-\-\-+\-\-\-\-\-\-+\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-+\-\-\-\-\-\- - 0 | | | | | - 1 | X | | | | - 2 | | X | | | - 3 | X | X | | | - 4 | | X | X | | - 5 | X | X | X | | - 6 | | X | X | | - 7 | X | X | X | | - 8 | | | | X | - 9 | X | | | X | - 10 | | X | | X | - 11 | X | X | | X | - 12 | | X | X | X | - 13 | X | X | X | X | - 14 | | X | X | X | - 15 | X | X | X | X | - 16 | | | | | X - 17 | X | | | | X - 18 | | X | | | X - 19 | X | X | | | X - 20 | | X | X | | X - 21 | X | X | X | | X - 22 | | X | X | | X - 23 | X | X | X | | X - 24 | | | | X | X - 25 | X | | | X | X - 26 | | X | | X | X - 27 | X | X | | X | X - 28 | | X | X | X | X - 29 | X | X | X | X | X - 30 | | X | X | X | X - 31 | X | X | X | X | X + | |cache |cache | | + dump | zero |without|with | user | free + level | page |private|private| data | page +.br +\-\-\-\-\-\-\-+\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-+\-\-\-\-\-\- + 0 | | | | | + 1 | X | | | | + 2 | | X | | | + 3 | X | X | | | + 4 | | X | X | | + 5 | X | X | X | | + 6 | | X | X | | + 7 | X | X | X | | + 8 | | | | X | + 9 | X | | | X | + 10 | | X | | X | + 11 | X | X | | X | + 12 | | X | X | X | + 13 | X | X | X | X | + 14 | | X | X | X | + 15 | X | X | X | X | + 16 | | | | | X + 17 | X | | | | X + 18 | | X | | | X + 19 | X | X | | | X + 20 | | X | X | | X + 21 | X | X | X | | X + 22 | | X | X | | X + 23 | X | X | X | | X + 24 | | | | X | X + 25 | X | | | X | X + 26 | | X | | X | X + 27 | X | X | | X | X + 28 | | X | X | X | X + 29 | X | X | X | X | X + 30 | | X | X | X | X + 31 | X | X | X | X | X .TP \fB\-E\fR Create \fIDUMPFILE\fR in the ELF format. .br -This option cannot be specified with \-c option, because the ELF format does not -support compressed data. +This option cannot be specified with either of \-c option or \-l option, because +the ELF format does not support compressed data. .br .B Example: .br @@ -257,17 +271,25 @@ specified. Used in conjunction with \-x \fIVMLINUX\fR option, to specify the filter config file \fIFILTERCONFIGFILE\fR that contains erase commands to filter out desired kernel data from vmcore while creating \fIDUMPFILE\fR. For filter -command syntax please refer to \fBmakedumpfile.conf(8)\fR. +command syntax please refer to \fBmakedumpfile.conf(5)\fR. + +.TP +\fB\-\-eppic\fR \fIEPPICMACRO\fR +Used in conjunction with \-x \fIVMLINUX\fR option, to specify the eppic macro +file that contains filter rules or directory that contains eppic macro +files to filter out desired kernel data from vmcore while creating \fIDUMPFILE\fR. +When directory is specified, all the eppic macros in the directory are processed. .TP \fB\-F\fR Output the dump data in the flattened format to the standard output for transporting the dump data by SSH. .br -Analysis tools cannot read the flattened format directly. For analysis, the -dump data in the flattened format should be rearranged to a normal -\fIDUMPFILE\fR (readable with analysis tools) by \-R option. By which option is -specified with \-F option, the format of the rearranged \fIDUMPFILE\fR is fixed. +Analysis tools (crash utility before version 5.1.2 or GDB) cannot read the +flattened format directly. For analysis, the dump data in the flattened format +should be rearranged to a normal \fIDUMPFILE\fR (readable with analysis tools) +by \-R option. By which option is specified with \-F option, the format of the +rearranged \fIDUMPFILE\fR is fixed. In other words, it is impossible to specify the \fIDUMPFILE\fR format when the dump data is rearranged with \-R option. If specifying \-E option with \-F option, the format of the rearranged \fIDUMPFILE\fR is the ELF format. Otherwise, it @@ -342,6 +364,32 @@ on the following example. # makedumpfile \-\-reassemble dumpfile1 dumpfile2 dumpfile .TP +\fB\-\-cyclic\-buffer\fR \fIbuffer_size\fR +Specify the buffer size in kilo bytes for analysis in the cyclic mode. +Actually, the double of \fIbuffer_size\fR kilo bytes will be allocated in memory. +In the cyclic mode, the number of cycles is represented as: + + num_of_cycles = system_memory / (\fIbuffer_size\fR * 1024 * bit_per_bytes * page_size ) + +The lesser number of cycles, the faster working speed is expected. +By default, \fIbuffer_size\fR will be calculated automatically depending on system memory +size, so ordinary users don't need to specify this option. + +.br +.B Example: +.br +# makedumpfile \-\-cyclic\-buffer 1024 \-d 31 \-x vmlinux /proc/vmcore dumpfile + +.TP +\fB\-\-non\-cyclic\fR +Running in the non-cyclic mode, this mode uses the old filtering logic same as v1.4.4 or before. +If you feel the cyclic mode is too slow, please try this mode. +.br +.B Example: +.br +# makedumpfile \-\-non\-cyclic \-d 31 \-x vmlinux /proc/vmcore dumpfile + +.TP \fB\-\-xen-syms\fR \fIXEN-SYMS\fR Specify the \fIXEN-SYMS\fR with debug information to analyze the xen's memory usage. This option extracts the part of xen and domain-0. @@ -486,17 +534,25 @@ order from left to right. \fIVMCORE\fRs Print debugging message. .TP -\fB-b \fR -cache 2^order pages in ram when generating vmcore info before writing to output - -.TP \fB\-h\fR -Show help message. +Show help message and LZO/snappy support status (enabled/disabled). .TP \fB\-v\fR Show the version of makedumpfile. +.SH ENVIRONMENT VARIABLES + +.TP 8 +.B TMPDIR +This environment variable is for a temporary memory bitmap file only in the non-cyclic mode. +If your machine has a lots of memory and you use tmpfs on /tmp, makedumpfile +can fail for a little memory in the 2nd kernel because makedumpfile makes a +very large temporary memory bitmap file in this case. To avoid this failure, +you can set a TMPDIR environment variable. If you do not set a TMPDIR +environment variable, makedumpfile uses /tmp directory for a temporary +bitmap file as a default. + .SH DIAGNOSTICS makedumpfile exits with the following value. .TP @@ -514,5 +570,5 @@ Written by Masaki Tachibana, and Ken'ich .SH SEE ALSO .PP -crash(8), gdb(1), kexec(8), makedumpfile.conf(8) +crash(8), gdb(1), kexec(8), makedumpfile.conf(5) diff -Nupr makedumpfile-1.3.5/makedumpfile.c makedumpfile-1.5.3/makedumpfile.c --- makedumpfile-1.3.5/makedumpfile.c 2013-07-03 15:18:37.899089017 +0800 +++ makedumpfile-1.5.3/makedumpfile.c 2013-02-18 16:47:26.000000000 +0800 @@ -1,7 +1,7 @@ /* * makedumpfile.c * - * Copyright (C) 2006, 2007, 2008, 2009 NEC Corporation + * Copyright (C) 2006, 2007, 2008, 2009, 2011 NEC Corporation * * 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 @@ -14,8 +14,15 @@ * GNU General Public License for more details. */ #include "makedumpfile.h" +#include "print_info.h" +#include "dwarf_info.h" +#include "elf_info.h" +#include "erase_info.h" #include "sadump_info.h" +#include "cache.h" #include +#include +#include struct symbol_table symbol_table; struct size_table size_table; @@ -24,37 +31,10 @@ struct array_table array_table; struct number_table number_table; struct srcfile_table srcfile_table; -struct dwarf_info dwarf_info; struct vm_table vt = { 0 }; struct DumpInfo *info = NULL; -struct module_sym_table mod_st = { 0 }; -struct filter_info *filter_info = NULL; -struct filter_config filter_config; -struct erase_info *erase_info = NULL; -unsigned long num_erase_info = 1; /* Node 0 is unused. */ char filename_stdout[] = FILENAME_STDOUT; -int message_level; -int flag_ignore_r_char; /* 0: '\r' is effective. 1: not effective. */ -char config_buf[BUFSIZE_FGETS]; - -/* - * Forward declarations - */ -void print_progress(const char *msg, - unsigned long current, - unsigned long end); - -/* - * Message texts - */ -#define PROGRESS_COPY "Copying data" -#define PROGRESS_HOLES "Checking for memory holes" -#define PROGRESS_UNN_PAGES "Excluding unnecessary pages" -#define PROGRESS_FREE_PAGES "Excluding free pages" -#define PROGRESS_ZERO_PAGES "Excluding zero pages" -#define PROGRESS_XEN_DOMAIN "Excluding xen user domain" -#define PROGRESS_MAXLEN "35" /* * The numbers of the excluded pages @@ -65,15 +45,11 @@ unsigned long long pfn_cache; unsigned long long pfn_cache_private; unsigned long long pfn_user; unsigned long long pfn_free; +unsigned long long pfn_hwpoison; -int retcd = FAILED; /* return code */ +unsigned long long num_dumped; -void -show_version(void) -{ - MSG("makedumpfile: version " VERSION " (released on " RELEASE_DATE ")\n"); - MSG("\n"); -} +int retcd = FAILED; /* return code */ #define INITIALIZE_LONG_TABLE(table, value) \ do { \ @@ -84,6 +60,9 @@ do { \ *ptr_long_table = value; \ } while (0) +static void check_cyclic_buffer_overrun(void); +static void setup_page_is_buddy(void); + void initialize_tables(void) { @@ -109,109 +88,6 @@ initialize_tables(void) } /* - * Convert Physical Address to File Offset. - * If this function returns 0x0, File Offset isn't found. - * The File Offset 0x0 is in the ELF header. - * It is not in the memory image. - */ -off_t -paddr_to_offset(unsigned long long paddr) -{ - int i; - off_t offset; - struct pt_load_segment *pls; - - for (i = offset = 0; i < info->num_load_memory; i++) { - pls = &info->pt_load_segments[i]; - if ((paddr >= pls->phys_start) - && (paddr < pls->phys_end)) { - offset = (off_t)(paddr - pls->phys_start) + - pls->file_offset; - break; - } - } - return offset; -} - -unsigned long long -vaddr_to_paddr_general(unsigned long long vaddr) -{ - int i; - unsigned long long paddr = NOT_PADDR; - struct pt_load_segment *pls; - - if (info->flag_refiltering) - return NOT_PADDR; - - for (i = 0; i < info->num_load_memory; i++) { - pls = &info->pt_load_segments[i]; - if ((vaddr >= pls->virt_start) - && (vaddr < pls->virt_end)) { - paddr = (off_t)(vaddr - pls->virt_start) + - pls->phys_start; - break; - } - } - return paddr; -} - -/* - * This function is slow because it doesn't use the memory. - * It is useful at few calls like get_str_osrelease_from_vmlinux(). - */ -off_t -vaddr_to_offset_slow(int fd, char *filename, unsigned long long vaddr) -{ - off_t offset = 0; - int i, phnum, num_load, flag_elf64, elf_format; - Elf64_Phdr load64; - Elf32_Phdr load32; - - elf_format = check_elf_format(fd, filename, &phnum, &num_load); - - if (elf_format == ELF64) - flag_elf64 = TRUE; - else if (elf_format == ELF32) - flag_elf64 = FALSE; - else - return 0; - - for (i = 0; i < phnum; i++) { - if (flag_elf64) { /* ELF64 */ - if (!get_elf64_phdr(fd, filename, i, &load64)) { - ERRMSG("Can't find Phdr %d.\n", i); - return 0; - } - if (load64.p_type != PT_LOAD) - continue; - - if ((vaddr < load64.p_vaddr) - || (load64.p_vaddr + load64.p_filesz <= vaddr)) - continue; - - offset = load64.p_offset + (vaddr - load64.p_vaddr); - break; - } else { /* ELF32 */ - if (!get_elf32_phdr(fd, filename, i, &load32)) { - ERRMSG("Can't find Phdr %d.\n", i); - return 0; - } - if (load32.p_type != PT_LOAD) - continue; - - if ((vaddr < load32.p_vaddr) - || (load32.p_vaddr + load32.p_filesz <= vaddr)) - continue; - - offset = load32.p_offset + (vaddr - load32.p_vaddr); - break; - } - } - - return offset; -} - -/* * Translate a domain-0's physical address to machine address. */ unsigned long long @@ -246,9 +122,7 @@ ptom_xen(unsigned long long paddr) int get_max_mapnr(void) { - int i; unsigned long long max_paddr; - struct pt_load_segment *pls; if (info->flag_refiltering) { info->max_mapnr = info->dh_memory->max_mapnr; @@ -260,11 +134,7 @@ get_max_mapnr(void) return TRUE; } - for (i = 0, max_paddr = 0; i < info->num_load_memory; i++) { - pls = &info->pt_load_segments[i]; - if (max_paddr < pls->phys_end) - max_paddr = pls->phys_end; - } + max_paddr = get_max_paddr(); info->max_mapnr = paddr_to_pfn(max_paddr); DEBUG_MSG("\n"); @@ -281,13 +151,15 @@ get_dom0_mapnr() { unsigned long max_pfn; - if (SYMBOL(max_pfn) == NOT_FOUND_SYMBOL) - return FALSE; - - if (!readmem(VADDR, SYMBOL(max_pfn), &max_pfn, sizeof max_pfn)) - return FALSE; + if (SYMBOL(max_pfn) != NOT_FOUND_SYMBOL) { + if (!readmem(VADDR, SYMBOL(max_pfn), &max_pfn, sizeof max_pfn)) { + ERRMSG("Can't read domain-0 max_pfn.\n"); + return FALSE; + } - info->dom0_mapnr = max_pfn; + info->dom0_mapnr = max_pfn; + DEBUG_MSG("domain-0 pfn : %llx\n", info->dom0_mapnr); + } return TRUE; } @@ -303,6 +175,7 @@ is_in_same_page(unsigned long vaddr1, un #define BITMAP_SECT_LEN 4096 static inline int is_dumpable(struct dump_bitmap *, unsigned long long); +static inline int is_dumpable_cyclic(char *bitmap, unsigned long long); unsigned long pfn_to_pos(unsigned long long pfn) { @@ -358,70 +231,118 @@ read_page_desc(unsigned long long paddr, return TRUE; } -int -readpmem_kdump_compressed(unsigned long long paddr, void *bufptr, size_t size) +static int +readpage_elf(unsigned long long paddr, void *bufptr) +{ + const off_t failed = (off_t)-1; + off_t offset = 0; + + if (!(offset = paddr_to_offset(paddr))) { + ERRMSG("Can't convert a physical address(%llx) to offset.\n", + paddr); + return FALSE; + } + + if (lseek(info->fd_memory, offset, SEEK_SET) == failed) { + ERRMSG("Can't seek the dump memory(%s). (offset: %llx) %s\n", + info->name_memory, (unsigned long long)offset, strerror(errno)); + return FALSE; + } + + if (read(info->fd_memory, bufptr, info->page_size) != info->page_size) { + ERRMSG("Can't read the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + return FALSE; + } + + return TRUE; +} + +static int +readpage_kdump_compressed(unsigned long long paddr, void *bufptr) { page_desc_t pd; - char buf[info->page_size]; - char buf2[info->page_size]; + char buf[info->page_size], *rdbuf; int ret; - unsigned long retlen, page_offset; - - page_offset = paddr % info->page_size; + unsigned long retlen; if (!is_dumpable(info->bitmap_memory, paddr_to_pfn(paddr))) { ERRMSG("pfn(%llx) is excluded from %s.\n", paddr_to_pfn(paddr), info->name_memory); - goto error; + return FALSE; } if (!read_page_desc(paddr, &pd)) { ERRMSG("Can't read page_desc: %llx\n", paddr); - goto error; + return FALSE; } if (lseek(info->fd_memory, pd.offset, SEEK_SET) < 0) { ERRMSG("Can't seek %s. %s\n", info->name_memory, strerror(errno)); - goto error; + return FALSE; } /* * Read page data */ - if (read(info->fd_memory, buf, pd.size) != pd.size) { + rdbuf = pd.flags & (DUMP_DH_COMPRESSED_ZLIB | DUMP_DH_COMPRESSED_LZO | + DUMP_DH_COMPRESSED_SNAPPY) ? buf : bufptr; + if (read(info->fd_memory, rdbuf, pd.size) != pd.size) { ERRMSG("Can't read %s. %s\n", info->name_memory, strerror(errno)); - goto error; + return FALSE; } - if (pd.flags & DUMP_DH_COMPRESSED) { + if (pd.flags & DUMP_DH_COMPRESSED_ZLIB) { retlen = info->page_size; - ret = uncompress((unsigned char *)buf2, &retlen, + ret = uncompress((unsigned char *)bufptr, &retlen, (unsigned char *)buf, pd.size); if ((ret != Z_OK) || (retlen != info->page_size)) { ERRMSG("Uncompress failed: %d\n", ret); - goto error; + return FALSE; } - memcpy(bufptr, buf2 + page_offset, size); - } else - memcpy(bufptr, buf + page_offset, size); +#ifdef USELZO + } else if (info->flag_lzo_support + && (pd.flags & DUMP_DH_COMPRESSED_LZO)) { + retlen = info->page_size; + ret = lzo1x_decompress_safe((unsigned char *)buf, pd.size, + (unsigned char *)bufptr, &retlen, + LZO1X_MEM_DECOMPRESS); + if ((ret != LZO_E_OK) || (retlen != info->page_size)) { + ERRMSG("Uncompress failed: %d\n", ret); + return FALSE; + } +#endif +#ifdef USESNAPPY + } else if ((pd.flags & DUMP_DH_COMPRESSED_SNAPPY)) { - return size; -error: - ERRMSG("type_addr: %d, addr:%llx, size:%zd\n", PADDR, paddr, size); - return FALSE; + ret = snappy_uncompressed_length(buf, pd.size, &retlen); + if (ret != SNAPPY_OK) { + ERRMSG("Uncompress failed: %d\n", ret); + return FALSE; + } + + ret = snappy_uncompress(buf, pd.size, bufptr, &retlen); + if ((ret != SNAPPY_OK) || (retlen != info->page_size)) { + ERRMSG("Uncompress failed: %d\n", ret); + return FALSE; + } +#endif + } + + return TRUE; } int readmem(int type_addr, unsigned long long addr, void *bufptr, size_t size) { size_t read_size, next_size; - off_t offset = 0; unsigned long long next_addr; unsigned long long paddr, maddr = NOT_PADDR; + unsigned long long pgaddr; + void *pgbuf; char *next_ptr; - const off_t failed = (off_t)-1; switch (type_addr) { case VADDR: @@ -430,7 +351,7 @@ readmem(int type_addr, unsigned long lon addr); goto error; } - if (vt.mem_flags & MEMORY_XEN) { + if (is_xen_memory()) { if ((maddr = ptom_xen(paddr)) == NOT_PADDR) { ERRMSG("Can't convert a physical address(%llx) to machine address.\n", paddr); @@ -441,7 +362,7 @@ readmem(int type_addr, unsigned long lon break; case PADDR: paddr = addr; - if (vt.mem_flags & MEMORY_XEN) { + if (is_xen_memory()) { if ((maddr = ptom_xen(paddr)) == NOT_PADDR) { ERRMSG("Can't convert a physical address(%llx) to machine address.\n", paddr); @@ -481,31 +402,29 @@ readmem(int type_addr, unsigned long lon goto error; } - if (info->flag_refiltering) - return readpmem_kdump_compressed(paddr, bufptr, read_size); - - if (info->flag_sadump) - return readpmem_sadump(paddr, bufptr, read_size); - - if (!(offset = paddr_to_offset(paddr))) { - ERRMSG("Can't convert a physical address(%llx) to offset.\n", - paddr); - goto error; - } - - if (lseek(info->fd_memory, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - goto error; - } + pgaddr = PAGEBASE(paddr); + pgbuf = cache_search(pgaddr); + if (!pgbuf) { + pgbuf = cache_alloc(pgaddr); + if (!pgbuf) + goto error; - if (read(info->fd_memory, bufptr, read_size) != read_size) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - goto error; + if (info->flag_refiltering) { + if (!readpage_kdump_compressed(pgaddr, pgbuf)) + goto error; + } else if (info->flag_sadump) { + if (!readpage_sadump(pgaddr, pgbuf)) + goto error; + } else { + if (!readpage_elf(pgaddr, pgbuf)) + goto error; + } + cache_add(pgaddr); } + memcpy(bufptr, pgbuf + PAGEOFFSET(paddr), read_size); return size; + error: ERRMSG("type_addr: %d, addr:%llx, size:%zd\n", type_addr, addr, size); return FALSE; @@ -625,210 +544,6 @@ check_release(void) return TRUE; } -void -print_usage(void) -{ - MSG("\n"); - MSG("Usage:\n"); - MSG(" Creating DUMPFILE:\n"); - MSG(" # makedumpfile [-c|-E] [-d DL] [-x VMLINUX|-i VMCOREINFO] VMCORE DUMPFILE\n"); - MSG("\n"); - MSG(" Creating DUMPFILE with filtered kernel data specified through filter config\n"); - MSG(" file:\n"); - MSG(" # makedumpfile [-c|-E] [-d DL] -x VMLINUX --config FILTERCONFIGFILE VMCORE\n"); - MSG(" DUMPFILE\n"); - MSG("\n"); - MSG(" Outputting the dump data in the flattened format to the standard output:\n"); - MSG(" # makedumpfile -F [-c|-E] [-d DL] [-x VMLINUX|-i VMCOREINFO] VMCORE\n"); - MSG("\n"); - MSG(" Rearranging the dump data in the flattened format to a readable DUMPFILE:\n"); - MSG(" # makedumpfile -R DUMPFILE\n"); - MSG("\n"); - MSG(" Generating VMCOREINFO:\n"); - MSG(" # makedumpfile -g VMCOREINFO -x VMLINUX\n"); - MSG("\n"); - MSG("\n"); - MSG(" Creating DUMPFILE of Xen:\n"); - MSG(" # makedumpfile -E [--xen-syms XEN-SYMS|--xen-vmcoreinfo VMCOREINFO] VMCORE DUMPFILE\n"); - MSG("\n"); - MSG(" Generating VMCOREINFO of Xen:\n"); - MSG(" # makedumpfile -g VMCOREINFO --xen-syms XEN-SYMS\n"); - MSG("\n"); - MSG("\n"); - MSG(" Creating DUMPFILE from multiple VMCOREs generated on sadump diskset configuration:\n"); - MSG(" # makedumpfile [-c] [-d DL] -x VMLINUX --diskset=VMCORE1 --diskset=VMCORE2\n"); - MSG(" [--diskset=VMCORE3 ..] DUMPFILE\n"); - MSG("\n"); - MSG("\n"); - MSG("Available options:\n"); - MSG(" [-c]:\n"); - MSG(" Compress dump data by each page.\n"); - MSG(" A user cannot specify this option with -E option, because the ELF format\n"); - MSG(" does not support compressed data.\n"); - MSG(" THIS IS ONLY FOR THE CRASH UTILITY.\n"); - MSG("\n"); - MSG(" [-d DL]:\n"); - MSG(" Specify the type of unnecessary page for analysis.\n"); - MSG(" Pages of the specified type are not copied to DUMPFILE. The page type\n"); - MSG(" marked in the following table is excluded. A user can specify multiple\n"); - MSG(" page types by setting the sum of each page type for Dump_Level (DL).\n"); - MSG(" The maximum of Dump_Level is 31.\n"); - MSG(" Note that Dump_Level for Xen dump filtering is 0 or 1.\n"); - MSG("\n"); - MSG(" Dump | zero cache cache user free\n"); - MSG(" Level | page page private data page\n"); - MSG(" -------+---------------------------------------\n"); - MSG(" 0 |\n"); - MSG(" 1 | X\n"); - MSG(" 2 | X\n"); - MSG(" 4 | X X\n"); - MSG(" 8 | X\n"); - MSG(" 16 | X\n"); - MSG(" 31 | X X X X X\n"); - MSG("\n"); - MSG(" [-E]:\n"); - MSG(" Create DUMPFILE in the ELF format.\n"); - MSG(" This option cannot be specified with -c option, because the ELF\n"); - MSG(" format does not support compressed data.\n"); - MSG("\n"); - MSG(" [-x VMLINUX]:\n"); - MSG(" Specify the first kernel's VMLINUX to analyze the first kernel's\n"); - MSG(" memory usage.\n"); - MSG(" The page size of the first kernel and the second kernel should match.\n"); - MSG("\n"); - MSG(" [-i VMCOREINFO]:\n"); - MSG(" Specify VMCOREINFO instead of VMLINUX for analyzing the first kernel's\n"); - MSG(" memory usage.\n"); - MSG(" VMCOREINFO should be made beforehand by makedumpfile with -g option,\n"); - MSG(" and it contains the first kernel's information. If Dump_Level is 2 or\n"); - MSG(" more and [-x VMLINUX] is not specified, this option is necessary.\n"); - MSG("\n"); - MSG(" [-g VMCOREINFO]:\n"); - MSG(" Generate VMCOREINFO from the first kernel's VMLINUX.\n"); - MSG(" VMCOREINFO must be generated on the system that is running the first\n"); - MSG(" kernel. With -i option, a user can specify VMCOREINFO generated on the\n"); - MSG(" other system that is running the same first kernel. [-x VMLINUX] must\n"); - MSG(" be specified.\n"); - MSG("\n"); - MSG(" [--config FILTERCONFIGFILE]:\n"); - MSG(" Used in conjunction with -x VMLINUX option, to specify the filter config\n"); - MSG(" file that contains filter commands to filter out desired kernel data\n"); - MSG(" from vmcore while creating DUMPFILE.\n"); - MSG("\n"); - MSG(" [-F]:\n"); - MSG(" Output the dump data in the flattened format to the standard output\n"); - MSG(" for transporting the dump data by SSH.\n"); - MSG(" Analysis tools cannot read the flattened format directly. For analysis,\n"); - MSG(" the dump data in the flattened format should be rearranged to a readable\n"); - MSG(" DUMPFILE by -R option.\n"); - MSG("\n"); - MSG(" [-R]:\n"); - MSG(" Rearrange the dump data in the flattened format from the standard input\n"); - MSG(" to a readable DUMPFILE.\n"); - MSG("\n"); - MSG(" [--split]:\n"); - MSG(" Split the dump data to multiple DUMPFILEs in parallel. If specifying DUMPFILEs\n"); - MSG(" on different storage devices, a device can share I/O load with other devices\n"); - MSG(" and it reduces time for saving the dump data. The file size of each DUMPFILE is\n"); - MSG(" smaller than the system memory size which is divided by the number of DUMPFILEs.\n"); - MSG(" This feature supports only the kdump-compressed format.\n"); - MSG("\n"); - MSG(" [--reassemble]:\n"); - MSG(" Reassemble multiple DUMPFILEs, which are created by --split option, into one\n"); - MSG(" DUMPFILE. dumpfile1 and dumpfile2 are reassembled into dumpfile on the following\n"); - MSG(" example.\n"); - MSG("\n"); - MSG(" [--xen-syms XEN-SYMS]:\n"); - MSG(" Specify the XEN-SYMS to analyze Xen's memory usage.\n"); - MSG("\n"); - MSG(" [--xen-vmcoreinfo VMCOREINFO]:\n"); - MSG(" Specify the VMCOREINFO of Xen to analyze Xen's memory usage.\n"); - MSG("\n"); - MSG(" [--xen_phys_start XEN_PHYS_START_ADDRESS]:\n"); - MSG(" This option is only for x86_64.\n"); - MSG(" Specify the XEN_PHYS_START_ADDRESS, if the xen code/data is relocatable\n"); - MSG(" and VMCORE does not contain XEN_PHYS_START_ADDRESS in the CRASHINFO.\n"); - MSG("\n"); - MSG(" [-X]:\n"); - MSG(" Exclude all the user domain pages from Xen kdump's VMCORE, and extract\n"); - MSG(" the part of Xen and domain-0.\n"); - MSG("\n"); - MSG(" [--diskset=VMCORE]:\n"); - MSG(" Specify multiple VMCOREs created on sadump diskset configuration the same\n"); - MSG(" number of times as the number of VMCOREs in increasing order from left to\n"); - MSG(" right.\n"); - MSG("\n"); - MSG(" [--message-level ML]:\n"); - MSG(" Specify the message types.\n"); - MSG(" Users can restrict output printed by specifying Message_Level (ML) with\n"); - MSG(" this option. The message type marked with an X in the following table is\n"); - MSG(" printed. For example, according to the table, specifying 7 as ML means\n"); - MSG(" progress indicator, common message, and error message are printed, and\n"); - MSG(" this is a default value.\n"); - MSG(" Note that the maximum value of message_level is 31.\n"); - MSG("\n"); - MSG(" Message | progress common error debug report\n"); - MSG(" Level | indicator message message message message\n"); - MSG(" ---------+------------------------------------------------------\n"); - MSG(" 0 |\n"); - MSG(" 1 | X\n"); - MSG(" 2 | X\n"); - MSG(" 4 | X\n"); - MSG(" * 7 | X X X\n"); - MSG(" 8 | X\n"); - MSG(" 16 | X\n"); - MSG(" 31 | X X X X X\n"); - MSG("\n"); - MSG(" [--vtop VIRTUAL_ADDRESS]:\n"); - MSG(" This option is useful, when user debugs the translation problem\n"); - MSG(" of virtual address. If specifing the VIRTUAL_ADDRESS, its physical\n"); - MSG(" address is printed.\n"); - MSG("\n"); - MSG(" [--dump-dmesg]:\n"); - MSG(" This option overrides the normal behavior of makedumpfile. Instead of\n"); - MSG(" compressing and filtering a VMCORE to make it smaller, it simply\n"); - MSG(" extracts the dmesg log from a VMCORE and writes it to the specified\n"); - MSG(" LOGFILE. If a VMCORE does not contain VMCOREINFO for dmesg, it is\n"); - MSG(" necessary to specfiy [-x VMLINUX] or [-i VMCOREINFO].\n"); - MSG("\n"); - MSG(" [-D]:\n"); - MSG(" Print debugging message.\n"); - MSG("\n"); - MSG(" [-b ]:\n"); - MSG(" Specify the block write size of makedumpfile. 2^order pages are cached on each write\n"); - MSG("\n"); - MSG(" [-f]:\n"); - MSG(" Overwrite DUMPFILE even if it already exists.\n"); - MSG("\n"); - MSG(" [-h]:\n"); - MSG(" Show help message.\n"); - MSG("\n"); - MSG(" [-b ]\n"); - MSG(" cache 2^order pages in ram when generating vmcore info before writing to\n"); - MSG(" output\n"); - MSG("\n"); - MSG(" [-v]:\n"); - MSG(" Show the version of makedumpfile.\n"); - MSG("\n"); - MSG(" VMLINUX:\n"); - MSG(" This is a pathname to the first kernel's vmlinux.\n"); - MSG(" This file must have the debug information of the first kernel to analyze\n"); - MSG(" the first kernel's memory usage.\n"); - MSG("\n"); - MSG(" VMCORE:\n"); - MSG(" This is a pathname to the first kernel's memory core image.\n"); - MSG(" This argument is generally /proc/vmcore.\n"); - MSG("\n"); - MSG(" DUMPFILE:\n"); - MSG(" This is a pathname to a file created by this command.\n"); - MSG("\n"); - MSG(" XEN-SYMS:\n"); - MSG(" This is a pathname to the xen-syms.\n"); - MSG(" This file must have the debug information of Xen to analyze\n"); - MSG(" Xen's memory usage.\n"); - MSG("\n"); -} - int open_vmcoreinfo(char *mode) { @@ -933,22 +648,28 @@ get_kdump_compressed_header_info(char *f goto error; } memcpy(info->kh_memory, &kh, sizeof(kh)); - info->nr_cpus = dh.nr_cpus; + set_nr_cpus(dh.nr_cpus); if (dh.header_version >= 3) { /* A dumpfile contains vmcoreinfo data. */ - info->offset_vmcoreinfo = kh.offset_vmcoreinfo; - info->size_vmcoreinfo = kh.size_vmcoreinfo; + set_vmcoreinfo(kh.offset_vmcoreinfo, kh.size_vmcoreinfo); + DEBUG_MSG(" offset_vmcoreinfo: 0x%llx\n", + (unsigned long long)kh.offset_vmcoreinfo); + DEBUG_MSG(" size_vmcoreinfo : 0x%ld\n", kh.size_vmcoreinfo); } if (dh.header_version >= 4) { /* A dumpfile contains ELF note section. */ - info->offset_note = kh.offset_note; - info->size_note = kh.size_note; + set_pt_note(kh.offset_note, kh.size_note); + DEBUG_MSG(" offset_note : 0x%llx\n", + (unsigned long long)kh.offset_note); + DEBUG_MSG(" size_note : 0x%ld\n", kh.size_note); } if (dh.header_version >= 5) { /* A dumpfile contains erased information. */ - info->offset_eraseinfo = kh.offset_eraseinfo; - info->size_eraseinfo = kh.size_eraseinfo; + set_eraseinfo(kh.offset_eraseinfo, kh.size_eraseinfo); + DEBUG_MSG(" offset_eraseinfo : 0x%llx\n", + (unsigned long long)kh.offset_eraseinfo); + DEBUG_MSG(" size_eraseinfo : 0x%ld\n", kh.size_eraseinfo); } return TRUE; error: @@ -1088,7 +809,6 @@ open_files_for_rearranging_dumpdata(void /* * Open the following files when it creates the dump file. * - dump mem - * - dump file * - bit map * if it reads the vmcoreinfo file * - vmcoreinfo file @@ -1115,2956 +835,1398 @@ open_files_for_creating_dumpfile(void) } int -dump_Elf_load(Elf64_Phdr *prog, int num_load) -{ - struct pt_load_segment *pls; - - if (prog->p_type != PT_LOAD) { - ERRMSG("%s isn't the dump memory.\n", info->name_memory); - return FALSE; - } - - pls = &info->pt_load_segments[num_load]; - pls->phys_start = prog->p_paddr; - pls->phys_end = pls->phys_start + prog->p_filesz; - pls->virt_start = prog->p_vaddr; - pls->virt_end = pls->virt_start + prog->p_filesz; - pls->file_offset = prog->p_offset; - - DEBUG_MSG("LOAD (%d)\n", num_load); - 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_elf64_ehdr(Elf64_Ehdr *ehdr) -{ - const off_t failed = (off_t)-1; - - if (lseek(info->fd_memory, 0, SEEK_SET) == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (read(info->fd_memory, ehdr, sizeof(Elf64_Ehdr)) - != sizeof(Elf64_Ehdr)) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) { - ERRMSG("Can't get valid e_ident.\n"); - return FALSE; - } - return TRUE; -} - -int -get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr) +is_kvaddr(unsigned long long addr) { - off_t offset; - const off_t failed = (off_t)-1; - - offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * index; - - if (lseek(fd, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); - return FALSE; - } - if (read(fd, phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) { - ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); - return FALSE; - } - return TRUE; + return (addr >= (unsigned long long)(KVBASE)); } int -get_elf32_ehdr(Elf32_Ehdr *ehdr) +get_symbol_info(void) { - const off_t failed = (off_t)-1; - - if (lseek(info->fd_memory, 0, SEEK_SET) == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (read(info->fd_memory, ehdr, sizeof(Elf32_Ehdr)) - != sizeof(Elf32_Ehdr)) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { - ERRMSG("Can't get valid e_ident.\n"); - return FALSE; - } - return TRUE; -} - -int -get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr) -{ - off_t offset; - const off_t failed = (off_t)-1; + /* + * Get symbol info. + */ + SYMBOL_INIT(mem_map, "mem_map"); + SYMBOL_INIT(vmem_map, "vmem_map"); + SYMBOL_INIT(mem_section, "mem_section"); + SYMBOL_INIT(pkmap_count, "pkmap_count"); + SYMBOL_INIT_NEXT(pkmap_count_next, "pkmap_count"); + SYMBOL_INIT(system_utsname, "system_utsname"); + SYMBOL_INIT(init_uts_ns, "init_uts_ns"); + SYMBOL_INIT(_stext, "_stext"); + SYMBOL_INIT(swapper_pg_dir, "swapper_pg_dir"); + SYMBOL_INIT(init_level4_pgt, "init_level4_pgt"); + SYMBOL_INIT(vmlist, "vmlist"); + SYMBOL_INIT(phys_base, "phys_base"); + SYMBOL_INIT(node_online_map, "node_online_map"); + SYMBOL_INIT(node_states, "node_states"); + SYMBOL_INIT(node_memblk, "node_memblk"); + SYMBOL_INIT(node_data, "node_data"); + SYMBOL_INIT(pgdat_list, "pgdat_list"); + SYMBOL_INIT(contig_page_data, "contig_page_data"); + SYMBOL_INIT(log_buf, "log_buf"); + SYMBOL_INIT(log_buf_len, "log_buf_len"); + SYMBOL_INIT(log_end, "log_end"); + SYMBOL_INIT(log_first_idx, "log_first_idx"); + SYMBOL_INIT(log_next_idx, "log_next_idx"); + SYMBOL_INIT(max_pfn, "max_pfn"); + SYMBOL_INIT(modules, "modules"); + SYMBOL_INIT(high_memory, "high_memory"); + SYMBOL_INIT(linux_banner, "linux_banner"); + SYMBOL_INIT(bios_cpu_apicid, "bios_cpu_apicid"); + SYMBOL_INIT(x86_bios_cpu_apicid, "x86_bios_cpu_apicid"); + if (SYMBOL(x86_bios_cpu_apicid) == NOT_FOUND_SYMBOL) + SYMBOL_INIT(x86_bios_cpu_apicid, + "per_cpu__x86_bios_cpu_apicid"); + SYMBOL_INIT(x86_bios_cpu_apicid_early_ptr, + "x86_bios_cpu_apicid_early_ptr"); + SYMBOL_INIT(x86_bios_cpu_apicid_early_map, + "x86_bios_cpu_apicid_early_map"); + SYMBOL_INIT(crash_notes, "crash_notes"); + SYMBOL_INIT(__per_cpu_load, "__per_cpu_load"); + SYMBOL_INIT(__per_cpu_offset, "__per_cpu_offset"); + SYMBOL_INIT(cpu_online_mask, "cpu_online_mask"); + if (SYMBOL(cpu_online_mask) == NOT_FOUND_SYMBOL) + SYMBOL_INIT(cpu_online_mask, "cpu_online_map"); + SYMBOL_INIT(kexec_crash_image, "kexec_crash_image"); + SYMBOL_INIT(node_remap_start_vaddr, "node_remap_start_vaddr"); + SYMBOL_INIT(node_remap_end_vaddr, "node_remap_end_vaddr"); + SYMBOL_INIT(node_remap_start_pfn, "node_remap_start_pfn"); - offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * index; + if (SYMBOL(node_data) != NOT_FOUND_SYMBOL) + SYMBOL_ARRAY_TYPE_INIT(node_data, "node_data"); + if (SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) + SYMBOL_ARRAY_LENGTH_INIT(pgdat_list, "pgdat_list"); + if (SYMBOL(mem_section) != NOT_FOUND_SYMBOL) + SYMBOL_ARRAY_LENGTH_INIT(mem_section, "mem_section"); + if (SYMBOL(node_memblk) != NOT_FOUND_SYMBOL) + SYMBOL_ARRAY_LENGTH_INIT(node_memblk, "node_memblk"); + if (SYMBOL(__per_cpu_offset) != NOT_FOUND_SYMBOL) + SYMBOL_ARRAY_LENGTH_INIT(__per_cpu_offset, "__per_cpu_offset"); + if (SYMBOL(node_remap_start_pfn) != NOT_FOUND_SYMBOL) + SYMBOL_ARRAY_LENGTH_INIT(node_remap_start_pfn, + "node_remap_start_pfn"); - if (lseek(fd, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); - return FALSE; - } - if (read(fd, phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)) { - ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); - return FALSE; - } return TRUE; } int -get_elf_phdr_memory(int index, Elf64_Phdr *phdr) +get_structure_info(void) { - Elf32_Phdr phdr32; + /* + * Get offsets of the page_discriptor's members. + */ + SIZE_INIT(page, "page"); + OFFSET_INIT(page.flags, "page", "flags"); + OFFSET_INIT(page._count, "page", "_count"); + OFFSET_INIT(page.mapping, "page", "mapping"); + OFFSET_INIT(page._mapcount, "page", "_mapcount"); + OFFSET_INIT(page.private, "page", "private"); - if (info->flag_elf64_memory) { /* ELF64 */ - if (!get_elf64_phdr(info->fd_memory, info->name_memory, - index, phdr)) { - ERRMSG("Can't find Phdr %d.\n", index); - return FALSE; - } - } else { - if (!get_elf32_phdr(info->fd_memory, info->name_memory, - index, &phdr32)) { - ERRMSG("Can't find Phdr %d.\n", index); + /* + * Some vmlinux(s) don't have debugging information about + * page.mapping. Then, makedumpfile assumes that there is + * "mapping" next to "private(unsigned long)" in the first + * union. + */ + if (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE) { + OFFSET(page.mapping) = get_member_offset("page", NULL, + DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION); + if (OFFSET(page.mapping) == FAILED_DWARFINFO) return FALSE; - } - memset(phdr, 0, sizeof(Elf64_Phdr)); - phdr->p_type = phdr32.p_type; - phdr->p_flags = phdr32.p_flags; - phdr->p_offset = phdr32.p_offset; - phdr->p_vaddr = phdr32.p_vaddr; - phdr->p_paddr = phdr32.p_paddr; - phdr->p_filesz = phdr32.p_filesz; - phdr->p_memsz = phdr32.p_memsz; - phdr->p_align = phdr32.p_align; - } - return TRUE; -} - -int -check_elf_format(int fd, char *filename, int *phnum, int *num_load) -{ - int i; - Elf64_Ehdr ehdr64; - Elf64_Phdr load64; - Elf32_Ehdr ehdr32; - Elf32_Phdr load32; - const off_t failed = (off_t)-1; - - if (lseek(fd, 0, SEEK_SET) == failed) { - ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); - return FALSE; - } - if (read(fd, &ehdr64, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) { - ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); - return FALSE; - } - if (lseek(fd, 0, SEEK_SET) == failed) { - ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); - return FALSE; - } - if (read(fd, &ehdr32, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)) { - ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); - return FALSE; - } - (*num_load) = 0; - if ((ehdr64.e_ident[EI_CLASS] == ELFCLASS64) - && (ehdr32.e_ident[EI_CLASS] != ELFCLASS32)) { - (*phnum) = ehdr64.e_phnum; - for (i = 0; i < ehdr64.e_phnum; i++) { - if (!get_elf64_phdr(fd, filename, i, &load64)) { - ERRMSG("Can't find Phdr %d.\n", i); - return FALSE; - } - if (load64.p_type == PT_LOAD) - (*num_load)++; - } - return ELF64; - - } else if ((ehdr64.e_ident[EI_CLASS] != ELFCLASS64) - && (ehdr32.e_ident[EI_CLASS] == ELFCLASS32)) { - (*phnum) = ehdr32.e_phnum; - for (i = 0; i < ehdr32.e_phnum; i++) { - if (!get_elf32_phdr(fd, filename, i, &load32)) { - ERRMSG("Can't find Phdr %d.\n", i); - return FALSE; - } - if (load32.p_type == PT_LOAD) - (*num_load)++; - } - return ELF32; + if (OFFSET(page.mapping) != NOT_FOUND_STRUCTURE) + OFFSET(page.mapping) += sizeof(unsigned long); } - ERRMSG("Can't get valid ehdr.\n"); - return FALSE; -} -int -get_elf_info(void) -{ - int i, j, phnum, num_load, elf_format; - Elf64_Phdr phdr; + OFFSET_INIT(page.lru, "page", "lru"); /* - * Check ELF64 or ELF32. + * Get offsets of the mem_section's members. */ - elf_format = check_elf_format(info->fd_memory, info->name_memory, - &phnum, &num_load); - - if (elf_format == ELF64) - info->flag_elf64_memory = TRUE; - else if (elf_format == ELF32) - info->flag_elf64_memory = FALSE; - else - return FALSE; - - info->num_load_memory = num_load; - - if (!info->num_load_memory) { - ERRMSG("Can't get the number of PT_LOAD.\n"); - return FALSE; - } - if ((info->pt_load_segments = (struct pt_load_segment *) - calloc(1, sizeof(struct pt_load_segment) * - info->num_load_memory)) == NULL) { - ERRMSG("Can't allocate memory for the PT_LOAD. %s\n", - strerror(errno)); - return FALSE; - } - info->offset_note = 0; - info->size_note = 0; - for (i = 0, j = 0; i < phnum; i++) { - if (!get_elf_phdr_memory(i, &phdr)) - return FALSE; + SIZE_INIT(mem_section, "mem_section"); + OFFSET_INIT(mem_section.section_mem_map, "mem_section", + "section_mem_map"); - if (phdr.p_type == PT_NOTE) { - info->offset_note = phdr.p_offset; - info->size_note = phdr.p_filesz; - } - if (phdr.p_type != PT_LOAD) - continue; + /* + * Get offsets of the pglist_data's members. + */ + SIZE_INIT(pglist_data, "pglist_data"); + OFFSET_INIT(pglist_data.node_zones, "pglist_data", "node_zones"); + OFFSET_INIT(pglist_data.nr_zones, "pglist_data", "nr_zones"); + OFFSET_INIT(pglist_data.node_mem_map, "pglist_data", "node_mem_map"); + OFFSET_INIT(pglist_data.node_start_pfn, "pglist_data","node_start_pfn"); + OFFSET_INIT(pglist_data.node_spanned_pages, "pglist_data", + "node_spanned_pages"); + OFFSET_INIT(pglist_data.pgdat_next, "pglist_data", "pgdat_next"); - if (j == 0) { - info->offset_load_memory = phdr.p_offset; - if (!info->offset_load_memory) { - ERRMSG("Can't get the offset of page data.\n"); - return FALSE; - } - } - if (j >= info->num_load_memory) - return FALSE; - if(!dump_Elf_load(&phdr, j)) - return FALSE; - j++; - } - if (info->offset_note == 0 || info->size_note == 0) { - ERRMSG("Can't find PT_NOTE Phdr.\n"); - return FALSE; - } - if (!get_pt_note_info(info->offset_note, info->size_note)) { - ERRMSG("Can't get PT_NOTE information.\n"); - return FALSE; - } + /* + * Get offsets of the zone's members. + */ + SIZE_INIT(zone, "zone"); + OFFSET_INIT(zone.free_pages, "zone", "free_pages"); + OFFSET_INIT(zone.free_area, "zone", "free_area"); + OFFSET_INIT(zone.vm_stat, "zone", "vm_stat"); + OFFSET_INIT(zone.spanned_pages, "zone", "spanned_pages"); + MEMBER_ARRAY_LENGTH_INIT(zone.free_area, "zone", "free_area"); - return TRUE; -} + /* + * Get offsets of the free_area's members. + */ + SIZE_INIT(free_area, "free_area"); + OFFSET_INIT(free_area.free_list, "free_area", "free_list"); + MEMBER_ARRAY_LENGTH_INIT(free_area.free_list, "free_area", "free_list"); -static int -process_module (Dwfl_Module *dwflmod, - void **userdata __attribute__ ((unused)), - const char *name __attribute__ ((unused)), - Dwarf_Addr base __attribute__ ((unused)), - void *arg) -{ - const char *fname, *mod_name, *debugfile; - Dwarf_Addr dwbias; + /* + * Get offsets of the list_head's members. + */ + SIZE_INIT(list_head, "list_head"); + OFFSET_INIT(list_head.next, "list_head", "next"); + OFFSET_INIT(list_head.prev, "list_head", "prev"); - /* get a debug context descriptor.*/ - dwarf_info.dwarfd = dwfl_module_getdwarf (dwflmod, &dwbias); - dwarf_info.elfd = dwarf_getelf(dwarf_info.dwarfd); + /* + * Get offsets of the node_memblk_s's members. + */ + SIZE_INIT(node_memblk_s, "node_memblk_s"); + OFFSET_INIT(node_memblk_s.start_paddr, "node_memblk_s", "start_paddr"); + OFFSET_INIT(node_memblk_s.size, "node_memblk_s", "size"); + OFFSET_INIT(node_memblk_s.nid, "node_memblk_s", "nid"); - mod_name = dwfl_module_info(dwflmod, NULL, NULL, NULL, NULL, NULL, - &fname, &debugfile); + OFFSET_INIT(vm_struct.addr, "vm_struct", "addr"); - if (!strcmp(dwarf_info.module_name, mod_name) && - !dwarf_info.name_debuginfo && debugfile) { - /* - * Store the debuginfo filename. Next time we will - * open debuginfo file direclty instead of searching - * for it again. - */ - dwarf_info.name_debuginfo = strdup(debugfile); - } + /* + * Get offset of the module members. + */ + SIZE_INIT(module, "module"); + OFFSET_INIT(module.strtab, "module", "strtab"); + OFFSET_INIT(module.symtab, "module", "symtab"); + OFFSET_INIT(module.num_symtab, "module", "num_symtab"); + OFFSET_INIT(module.list, "module", "list"); + OFFSET_INIT(module.name, "module", "name"); + OFFSET_INIT(module.module_core, "module", "module_core"); + OFFSET_INIT(module.core_size, "module", "core_size"); + OFFSET_INIT(module.module_init, "module", "module_init"); + OFFSET_INIT(module.init_size, "module", "init_size"); - return DWARF_CB_OK; -} + ENUM_NUMBER_INIT(NR_FREE_PAGES, "NR_FREE_PAGES"); + ENUM_NUMBER_INIT(N_ONLINE, "N_ONLINE"); -static int -dwfl_report_module_p(const char *modname, const char *filename) -{ - if (filename && !strcmp(modname, dwarf_info.module_name)) - return 1; - return 0; -} + ENUM_NUMBER_INIT(PG_lru, "PG_lru"); + ENUM_NUMBER_INIT(PG_private, "PG_private"); + ENUM_NUMBER_INIT(PG_swapcache, "PG_swapcache"); + ENUM_NUMBER_INIT(PG_buddy, "PG_buddy"); + ENUM_NUMBER_INIT(PG_slab, "PG_slab"); + ENUM_NUMBER_INIT(PG_hwpoison, "PG_hwpoison"); -static void -clean_dwfl_info(void) -{ - if (dwarf_info.dwfl) - dwfl_end(dwarf_info.dwfl); + ENUM_TYPE_SIZE_INIT(pageflags, "pageflags"); - dwarf_info.dwfl = NULL; - dwarf_info.dwarfd = NULL; - dwarf_info.elfd = NULL; -} + TYPEDEF_SIZE_INIT(nodemask_t, "nodemask_t"); -/* - * Search module debuginfo. - * This function searches for module debuginfo in default debuginfo path for - * a given module in dwarf_info.module_name. - * - * On success, dwarf_info.name_debuginfo is set to absolute path of - * module debuginfo. - */ -static int -search_module_debuginfo(void) -{ - Dwfl *dwfl = NULL; - static char *debuginfo_path = DEFAULT_DEBUGINFO_PATH; - static const Dwfl_Callbacks callbacks = { - .section_address = dwfl_offline_section_address, - .find_debuginfo = dwfl_standard_find_debuginfo, - .debuginfo_path = &debuginfo_path, - }; + SIZE_INIT(percpu_data, "percpu_data"); /* - * Check if We already have debuginfo file name with us. If yes, - * then we don't need to proceed with search method. + * Get offset of the elf_prstatus members. */ - if (dwarf_info.name_debuginfo) - return TRUE; - - if ((dwfl = dwfl_begin(&callbacks)) == NULL) { - ERRMSG("Can't create a handle for a new dwfl session.\n"); - return FALSE; - } - - /* Search for module debuginfo file. */ - if (dwfl_linux_kernel_report_offline(dwfl, - info->system_utsname.release, - &dwfl_report_module_p)) { - ERRMSG("Can't get Module debuginfo for module '%s'\n", - dwarf_info.module_name); - dwfl_end(dwfl); - return FALSE; - } - dwfl_report_end(dwfl, NULL, NULL); - dwfl_getmodules(dwfl, &process_module, NULL, 0); - - dwfl_end(dwfl); - clean_dwfl_info(); - - /* Return success if module debuginfo is found. */ - if (dwarf_info.name_debuginfo) - return TRUE; + SIZE_INIT(elf_prstatus, "elf_prstatus"); + OFFSET_INIT(elf_prstatus.pr_reg, "elf_prstatus", "pr_reg"); - return FALSE; -} + /* + * Get size of cpumask and cpumask_t. + */ + SIZE_INIT(cpumask, "cpumask"); -/* - * Initialize the dwarf info. - * Linux kernel module debuginfo are of ET_REL (relocatable) type. - * This function uses dwfl API's to apply relocation before reading the - * dwarf information from module debuginfo. - * On success, this function sets the dwarf_info.elfd and dwarf_info.dwarfd - * after applying relocation to module debuginfo. - */ -static int -init_dwarf_info(void) -{ - Dwfl *dwfl = NULL; - int dwfl_fd = -1; - static const Dwfl_Callbacks callbacks = { - .section_address = dwfl_offline_section_address, - }; + TYPEDEF_SIZE_INIT(cpumask_t, "cpumask_t"); - dwarf_info.elfd = NULL; - dwarf_info.dwarfd = NULL; + /* + * Get offset of the user_regs_struct members. + */ + SIZE_INIT(user_regs_struct, "user_regs_struct"); - /* - * We already know the absolute path of debuginfo file. Fail if we - * still don't have one. Ideally we should never be in this situation. - */ - if (!dwarf_info.name_debuginfo) { - ERRMSG("Can't find absolute path to debuginfo file.\n"); - return FALSE; - } +#ifdef __x86__ + if (SIZE(user_regs_struct) != NOT_FOUND_STRUCTURE) { + OFFSET_INIT(user_regs_struct.bx, "user_regs_struct", "bx"); + OFFSET_INIT(user_regs_struct.cx, "user_regs_struct", "cx"); + OFFSET_INIT(user_regs_struct.dx, "user_regs_struct", "dx"); + OFFSET_INIT(user_regs_struct.si, "user_regs_struct", "si"); + OFFSET_INIT(user_regs_struct.di, "user_regs_struct", "di"); + OFFSET_INIT(user_regs_struct.bp, "user_regs_struct", "bp"); + OFFSET_INIT(user_regs_struct.ax, "user_regs_struct", "ax"); + OFFSET_INIT(user_regs_struct.ds, "user_regs_struct", "ds"); + OFFSET_INIT(user_regs_struct.es, "user_regs_struct", "es"); + OFFSET_INIT(user_regs_struct.fs, "user_regs_struct", "fs"); + OFFSET_INIT(user_regs_struct.gs, "user_regs_struct", "gs"); + OFFSET_INIT(user_regs_struct.orig_ax, "user_regs_struct", + "orig_ax"); + OFFSET_INIT(user_regs_struct.ip, "user_regs_struct", "ip"); + OFFSET_INIT(user_regs_struct.cs, "user_regs_struct", "cs"); + OFFSET_INIT(user_regs_struct.flags, "user_regs_struct", + "flags"); + OFFSET_INIT(user_regs_struct.sp, "user_regs_struct", "sp"); + OFFSET_INIT(user_regs_struct.ss, "user_regs_struct", "ss"); - if ((dwfl = dwfl_begin(&callbacks)) == NULL) { - ERRMSG("Can't create a handle for a new dwfl session.\n"); - return FALSE; + if (OFFSET(user_regs_struct.bx) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.bx, "user_regs_struct", "ebx"); + if (OFFSET(user_regs_struct.cx) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.cx, "user_regs_struct", "ecx"); + if (OFFSET(user_regs_struct.dx) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.dx, "user_regs_struct", "edx"); + if (OFFSET(user_regs_struct.si) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.si, "user_regs_struct", "esi"); + if (OFFSET(user_regs_struct.di) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.di, "user_regs_struct", "edi"); + if (OFFSET(user_regs_struct.bp) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.bp, "user_regs_struct", "ebp"); + if (OFFSET(user_regs_struct.ax) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.ax, "user_regs_struct", "eax"); + if (OFFSET(user_regs_struct.orig_ax) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.orig_ax, "user_regs_struct", "orig_eax"); + if (OFFSET(user_regs_struct.ip) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.ip, "user_regs_struct", "eip"); + if (OFFSET(user_regs_struct.flags) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.flags, "user_regs_struct", "eflags"); + if (OFFSET(user_regs_struct.sp) == NOT_FOUND_STRUCTURE) + OFFSET_INIT(user_regs_struct.sp, "user_regs_struct", "esp"); + } else { + /* + * Note: Sometimes kernel debuginfo doesn't contain + * user_regs_struct structure information. Instead, we + * take offsets from actual datatype. + */ + OFFSET(user_regs_struct.bx) = offsetof(struct user_regs_struct, bx); + OFFSET(user_regs_struct.cx) = offsetof(struct user_regs_struct, cx); + OFFSET(user_regs_struct.dx) = offsetof(struct user_regs_struct, dx); + OFFSET(user_regs_struct.si) = offsetof(struct user_regs_struct, si); + OFFSET(user_regs_struct.di) = offsetof(struct user_regs_struct, di); + OFFSET(user_regs_struct.bp) = offsetof(struct user_regs_struct, bp); + OFFSET(user_regs_struct.ax) = offsetof(struct user_regs_struct, ax); + OFFSET(user_regs_struct.ds) = offsetof(struct user_regs_struct, ds); + OFFSET(user_regs_struct.es) = offsetof(struct user_regs_struct, es); + OFFSET(user_regs_struct.fs) = offsetof(struct user_regs_struct, fs); + OFFSET(user_regs_struct.gs) = offsetof(struct user_regs_struct, gs); + OFFSET(user_regs_struct.orig_ax) = offsetof(struct user_regs_struct, orig_ax); + OFFSET(user_regs_struct.ip) = offsetof(struct user_regs_struct, ip); + OFFSET(user_regs_struct.cs) = offsetof(struct user_regs_struct, cs); + OFFSET(user_regs_struct.flags) = offsetof(struct user_regs_struct, flags); + OFFSET(user_regs_struct.sp) = offsetof(struct user_regs_struct, sp); + OFFSET(user_regs_struct.ss) = offsetof(struct user_regs_struct, ss); } +#endif /* __x86__ */ - /* Open the debuginfo file if it is not already open. */ - if (dwarf_info.fd_debuginfo < 0) - dwarf_info.fd_debuginfo = - open(dwarf_info.name_debuginfo, O_RDONLY); - - dwfl_fd = dup(dwarf_info.fd_debuginfo); - if (dwfl_fd < 0) { - ERRMSG("Failed to get a duplicate handle for" - " debuginfo.\n"); - goto err_out; - } - /* Apply relocations. */ - if (dwfl_report_offline(dwfl, dwarf_info.module_name, - dwarf_info.name_debuginfo, dwfl_fd) == NULL) { - ERRMSG("Failed reading %s: %s\n", - dwarf_info.name_debuginfo, dwfl_errmsg (-1)); - /* dwfl_fd is consumed on success, not on failure */ - close(dwfl_fd); - goto err_out; +#ifdef __x86_64__ + if (SIZE(user_regs_struct) != NOT_FOUND_STRUCTURE) { + OFFSET_INIT(user_regs_struct.r15, "user_regs_struct", "r15"); + OFFSET_INIT(user_regs_struct.r14, "user_regs_struct", "r14"); + OFFSET_INIT(user_regs_struct.r13, "user_regs_struct", "r13"); + OFFSET_INIT(user_regs_struct.r12, "user_regs_struct", "r12"); + OFFSET_INIT(user_regs_struct.bp, "user_regs_struct", "bp"); + OFFSET_INIT(user_regs_struct.bx, "user_regs_struct", "bx"); + OFFSET_INIT(user_regs_struct.r11, "user_regs_struct", "r11"); + OFFSET_INIT(user_regs_struct.r10, "user_regs_struct", "r10"); + OFFSET_INIT(user_regs_struct.r9, "user_regs_struct", "r9"); + OFFSET_INIT(user_regs_struct.r8, "user_regs_struct", "r8"); + OFFSET_INIT(user_regs_struct.ax, "user_regs_struct", "ax"); + OFFSET_INIT(user_regs_struct.cx, "user_regs_struct", "cx"); + OFFSET_INIT(user_regs_struct.dx, "user_regs_struct", "dx"); + OFFSET_INIT(user_regs_struct.si, "user_regs_struct", "si"); + OFFSET_INIT(user_regs_struct.di, "user_regs_struct", "di"); + OFFSET_INIT(user_regs_struct.orig_ax, "user_regs_struct", + "orig_ax"); + OFFSET_INIT(user_regs_struct.ip, "user_regs_struct", "ip"); + OFFSET_INIT(user_regs_struct.cs, "user_regs_struct", "cs"); + OFFSET_INIT(user_regs_struct.flags, "user_regs_struct", + "flags"); + OFFSET_INIT(user_regs_struct.sp, "user_regs_struct", "sp"); + OFFSET_INIT(user_regs_struct.ss, "user_regs_struct", "ss"); + OFFSET_INIT(user_regs_struct.fs_base, "user_regs_struct", + "fs_base"); + OFFSET_INIT(user_regs_struct.gs_base, "user_regs_struct", + "gs_base"); + OFFSET_INIT(user_regs_struct.ds, "user_regs_struct", "ds"); + OFFSET_INIT(user_regs_struct.es, "user_regs_struct", "es"); + OFFSET_INIT(user_regs_struct.fs, "user_regs_struct", "fs"); + OFFSET_INIT(user_regs_struct.gs, "user_regs_struct", "gs"); + } else { + /* + * Note: Sometimes kernel debuginfo doesn't contain + * user_regs_struct structure information. Instead, we + * take offsets from actual datatype. + */ + OFFSET(user_regs_struct.r15) = offsetof(struct user_regs_struct, r15); + OFFSET(user_regs_struct.r14) = offsetof(struct user_regs_struct, r14); + OFFSET(user_regs_struct.r13) = offsetof(struct user_regs_struct, r13); + OFFSET(user_regs_struct.r12) = offsetof(struct user_regs_struct, r12); + OFFSET(user_regs_struct.bp) = offsetof(struct user_regs_struct, bp); + OFFSET(user_regs_struct.bx) = offsetof(struct user_regs_struct, bx); + OFFSET(user_regs_struct.r11) = offsetof(struct user_regs_struct, r11); + OFFSET(user_regs_struct.r10) = offsetof(struct user_regs_struct, r10); + OFFSET(user_regs_struct.r9) = offsetof(struct user_regs_struct, r9); + OFFSET(user_regs_struct.r8) = offsetof(struct user_regs_struct, r8); + OFFSET(user_regs_struct.ax) = offsetof(struct user_regs_struct, ax); + OFFSET(user_regs_struct.cx) = offsetof(struct user_regs_struct, cx); + OFFSET(user_regs_struct.dx) = offsetof(struct user_regs_struct, dx); + OFFSET(user_regs_struct.si) = offsetof(struct user_regs_struct, si); + OFFSET(user_regs_struct.di) = offsetof(struct user_regs_struct, di); + OFFSET(user_regs_struct.orig_ax) = offsetof(struct user_regs_struct, orig_ax); + OFFSET(user_regs_struct.ip) = offsetof(struct user_regs_struct, ip); + OFFSET(user_regs_struct.cs) = offsetof(struct user_regs_struct, cs); + OFFSET(user_regs_struct.flags) = offsetof(struct user_regs_struct, flags); + OFFSET(user_regs_struct.sp) = offsetof(struct user_regs_struct, sp); + OFFSET(user_regs_struct.ss) = offsetof(struct user_regs_struct, ss); + OFFSET(user_regs_struct.fs_base) = offsetof(struct user_regs_struct, fs_base); + OFFSET(user_regs_struct.gs_base) = offsetof(struct user_regs_struct, gs_base); + OFFSET(user_regs_struct.ds) = offsetof(struct user_regs_struct, ds); + OFFSET(user_regs_struct.es) = offsetof(struct user_regs_struct, es); + OFFSET(user_regs_struct.fs) = offsetof(struct user_regs_struct, fs); + OFFSET(user_regs_struct.gs) = offsetof(struct user_regs_struct, gs); } - dwfl_report_end(dwfl, NULL, NULL); +#endif /* __x86_64__ */ - dwfl_getmodules(dwfl, &process_module, NULL, 0); + OFFSET_INIT(kimage.segment, "kimage", "segment"); - if (dwarf_info.elfd == NULL) { - ERRMSG("Can't get first elf header of %s.\n", - dwarf_info.name_debuginfo); - goto err_out; - } + MEMBER_ARRAY_LENGTH_INIT(kimage.segment, "kimage", "segment"); - if (dwarf_info.dwarfd == NULL) { - ERRMSG("Can't get debug context descriptor for %s.\n", - dwarf_info.name_debuginfo); - goto err_out; - } - dwarf_info.dwfl = dwfl; - return TRUE; -err_out: - if (dwfl) - dwfl_end(dwfl); + SIZE_INIT(kexec_segment, "kexec_segment"); + OFFSET_INIT(kexec_segment.mem, "kexec_segment", "mem"); - return FALSE; -} + OFFSET_INIT(elf64_hdr.e_phnum, "elf64_hdr", "e_phnum"); + OFFSET_INIT(elf64_hdr.e_phentsize, "elf64_hdr", "e_phentsize"); + OFFSET_INIT(elf64_hdr.e_phoff, "elf64_hdr", "e_phoff"); -static struct module_info * -get_loaded_module(char *mod_name) -{ - unsigned int i; - struct module_info *modules; + SIZE_INIT(elf64_hdr, "elf64_hdr"); + OFFSET_INIT(elf64_phdr.p_type, "elf64_phdr", "p_type"); + OFFSET_INIT(elf64_phdr.p_offset, "elf64_phdr", "p_offset"); + OFFSET_INIT(elf64_phdr.p_paddr, "elf64_phdr", "p_paddr"); + OFFSET_INIT(elf64_phdr.p_memsz, "elf64_phdr", "p_memsz"); - modules = mod_st.modules; - if (strcmp(mod_name, modules[mod_st.current_mod].name)) { - for (i = 0; i < mod_st.num_modules; i++) { - if (!strcmp(mod_name, modules[i].name)) - break; - } - if (i == mod_st.num_modules) - return NULL; - /* set the current_mod for fast lookup next time */ - mod_st.current_mod = i; - } + SIZE_INIT(log, "log"); + OFFSET_INIT(log.ts_nsec, "log", "ts_nsec"); + OFFSET_INIT(log.len, "log", "len"); + OFFSET_INIT(log.text_len, "log", "text_len"); - return &modules[mod_st.current_mod]; + return TRUE; } int -sym_in_module(char *symname, unsigned long long *symbol_addr) +get_srcfile_info(void) { - int i; - struct module_info *module_ptr; - struct symbol_info *sym_info; + TYPEDEF_SRCFILE_INIT(pud_t, "pud_t"); - if (!mod_st.num_modules - || !strcmp(dwarf_info.module_name, "vmlinux") - || !strcmp(dwarf_info.module_name, "xen-syms")) - return FALSE; + return TRUE; +} - module_ptr = get_loaded_module(dwarf_info.module_name); - if (!module_ptr) - return FALSE; - sym_info = module_ptr->sym_info; - if (!sym_info) - return FALSE; - for (i = 1; i < module_ptr->num_syms; i++) { - if (sym_info[i].name && !strcmp(sym_info[i].name, symname)) { - *symbol_addr = sym_info[i].value; - return TRUE; - } +int +get_value_for_old_linux(void) +{ + if (NUMBER(PG_lru) == NOT_FOUND_NUMBER) + NUMBER(PG_lru) = PG_lru_ORIGINAL; + if (NUMBER(PG_private) == NOT_FOUND_NUMBER) + NUMBER(PG_private) = PG_private_ORIGINAL; + if (NUMBER(PG_swapcache) == NOT_FOUND_NUMBER) + NUMBER(PG_swapcache) = PG_swapcache_ORIGINAL; + if (NUMBER(PG_slab) == NOT_FOUND_NUMBER) + NUMBER(PG_slab) = PG_slab_ORIGINAL; + /* + * The values from here are for free page filtering based on + * mem_map array. These are minimum effort to cover old + * kernels. + * + * The logic also needs offset values for some members of page + * structure. But it much depends on kernel versions. We avoid + * to hard code the values. + */ + if (NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE) == NOT_FOUND_NUMBER) { + if (info->kernel_version == KERNEL_VERSION(2, 6, 38)) + NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE) = + PAGE_BUDDY_MAPCOUNT_VALUE_v2_6_38; + if (info->kernel_version >= KERNEL_VERSION(2, 6, 39)) + NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE) = + PAGE_BUDDY_MAPCOUNT_VALUE_v2_6_39_to_latest_version; + } + if (SIZE(pageflags) == NOT_FOUND_STRUCTURE) { + if (info->kernel_version >= KERNEL_VERSION(2, 6, 27)) + SIZE(pageflags) = + PAGE_FLAGS_SIZE_v2_6_27_to_latest_version; } - return FALSE; + return TRUE; } -unsigned long long -get_symbol_addr(char *symname) +int +get_str_osrelease_from_vmlinux(void) { - int i; - unsigned long long symbol = NOT_FOUND_SYMBOL; - Elf *elfd = NULL; - GElf_Shdr shdr; - GElf_Sym sym; - Elf_Data *data = NULL; - Elf_Scn *scn = NULL; - char *sym_name = NULL; + int fd; + char *name; + struct utsname system_utsname; + unsigned long long utsname; + off_t offset; + const off_t failed = (off_t)-1; /* - * If we are looking for module symbol then traverse through - * mod_st.modules for symbol lookup + * Get the kernel version. */ - if (sym_in_module(symname, &symbol)) - return symbol; - - if (!init_dwarf_info()) - return NOT_FOUND_SYMBOL; - - elfd = dwarf_info.elfd; + if (SYMBOL(system_utsname) != NOT_FOUND_SYMBOL) { + utsname = SYMBOL(system_utsname); + } else if (SYMBOL(init_uts_ns) != NOT_FOUND_SYMBOL) { + utsname = SYMBOL(init_uts_ns) + sizeof(int); + } else { + ERRMSG("Can't get the symbol of system_utsname.\n"); + return FALSE; + } + get_fileinfo_of_debuginfo(&fd, &name); - while ((scn = elf_nextscn(elfd, scn)) != NULL) { - if (gelf_getshdr(scn, &shdr) == NULL) { - ERRMSG("Can't get section header.\n"); - goto out; - } - if (shdr.sh_type == SHT_SYMTAB) - break; + offset = vaddr_to_offset_slow(fd, name, utsname); + if (!offset) { + ERRMSG("Can't convert vaddr (%llx) of utsname to an offset.\n", + utsname); + return FALSE; } - if (!scn) { - ERRMSG("Can't find symbol table.\n"); - goto out; + if (lseek(fd, offset, SEEK_SET) == failed) { + ERRMSG("Can't seek %s. %s\n", name, strerror(errno)); + return FALSE; } - - data = elf_getdata(scn, data); - - if ((!data) || (data->d_size == 0)) { - ERRMSG("No data in symbol table.\n"); - goto out; + if (read(fd, &system_utsname, sizeof system_utsname) + != sizeof system_utsname) { + ERRMSG("Can't read %s. %s\n", name, strerror(errno)); + return FALSE; } - - for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) { - if (gelf_getsym(data, i, &sym) == NULL) { - ERRMSG("Can't get symbol at index %d.\n", i); - goto out; - } - sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name); - - if (sym_name == NULL) - continue; - - if (!strcmp(sym_name, symname)) { - symbol = sym.st_value; - break; - } + if (!strncpy(info->release, system_utsname.release, STRLEN_OSRELEASE)){ + ERRMSG("Can't do strncpy for osrelease."); + return FALSE; } -out: - clean_dwfl_info(); - - return symbol; + return TRUE; } -unsigned long -get_next_symbol_addr(char *symname) +int +is_sparsemem_extreme(void) { - int i; - unsigned long symbol = NOT_FOUND_SYMBOL; - unsigned long next_symbol = NOT_FOUND_SYMBOL; - Elf *elfd = NULL; - GElf_Shdr shdr; - GElf_Sym sym; - Elf_Data *data = NULL; - Elf_Scn *scn = NULL; - char *sym_name = NULL; - - if (!init_dwarf_info()) - return NOT_FOUND_SYMBOL; + if (ARRAY_LENGTH(mem_section) + == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT_EXTREME())) + return TRUE; + else + return FALSE; +} - elfd = dwarf_info.elfd; +int +get_mem_type(void) +{ + int ret; - while ((scn = elf_nextscn(elfd, scn)) != NULL) { - if (gelf_getshdr(scn, &shdr) == NULL) { - ERRMSG("Can't get section header.\n"); - goto out; - } - if (shdr.sh_type == SHT_SYMTAB) - break; - } - if (!scn) { - ERRMSG("Can't find symbol table.\n"); - goto out; - } - - data = elf_getdata(scn, data); - - if ((!data) || (data->d_size == 0)) { - ERRMSG("No data in symbol table.\n"); - goto out; - } - - for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) { - if (gelf_getsym(data, i, &sym) == NULL) { - ERRMSG("Can't get symbol at index %d.\n", i); - goto out; - } - sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name); - - if (sym_name == NULL) - continue; - - if (!strcmp(sym_name, symname)) { - symbol = sym.st_value; - break; - } + if ((SIZE(page) == NOT_FOUND_STRUCTURE) + || (OFFSET(page.flags) == NOT_FOUND_STRUCTURE) + || (OFFSET(page._count) == NOT_FOUND_STRUCTURE) + || (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE)) { + ret = NOT_FOUND_MEMTYPE; + } else if ((((SYMBOL(node_data) != NOT_FOUND_SYMBOL) + && (ARRAY_LENGTH(node_data) != NOT_FOUND_STRUCTURE)) + || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) + && (OFFSET(pglist_data.pgdat_next) != NOT_FOUND_STRUCTURE)) + || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) + && (ARRAY_LENGTH(pgdat_list) != NOT_FOUND_STRUCTURE))) + && (SIZE(pglist_data) != NOT_FOUND_STRUCTURE) + && (OFFSET(pglist_data.node_mem_map) != NOT_FOUND_STRUCTURE) + && (OFFSET(pglist_data.node_start_pfn) != NOT_FOUND_STRUCTURE) + && (OFFSET(pglist_data.node_spanned_pages) !=NOT_FOUND_STRUCTURE)){ + ret = DISCONTIGMEM; + } else if ((SYMBOL(mem_section) != NOT_FOUND_SYMBOL) + && (SIZE(mem_section) != NOT_FOUND_STRUCTURE) + && (OFFSET(mem_section.section_mem_map) != NOT_FOUND_STRUCTURE) + && (ARRAY_LENGTH(mem_section) != NOT_FOUND_STRUCTURE)) { + if (is_sparsemem_extreme()) + ret = SPARSEMEM_EX; + else + ret = SPARSEMEM; + } else if (SYMBOL(mem_map) != NOT_FOUND_SYMBOL) { + ret = FLATMEM; + } else { + ret = NOT_FOUND_MEMTYPE; } - if (symbol == NOT_FOUND_SYMBOL) - goto out; + return ret; +} +void +write_vmcoreinfo_data(void) +{ /* - * Search for next symbol. + * write 1st kernel's OSRELEASE */ - for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) { - if (gelf_getsym(data, i, &sym) == NULL) { - ERRMSG("Can't get symbol at index %d.\n", i); - goto out; - } - sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name); + fprintf(info->file_vmcoreinfo, "%s%s\n", STR_OSRELEASE, + info->release); - if (sym_name == NULL) - continue; + /* + * write 1st kernel's PAGESIZE + */ + fprintf(info->file_vmcoreinfo, "%s%ld\n", STR_PAGESIZE, + info->page_size); - if (symbol < sym.st_value) { - if (next_symbol == NOT_FOUND_SYMBOL) - next_symbol = sym.st_value; + /* + * write the symbol of 1st kernel + */ + WRITE_SYMBOL("mem_map", mem_map); + WRITE_SYMBOL("vmem_map", vmem_map); + WRITE_SYMBOL("mem_section", mem_section); + WRITE_SYMBOL("pkmap_count", pkmap_count); + WRITE_SYMBOL("pkmap_count_next", pkmap_count_next); + WRITE_SYMBOL("system_utsname", system_utsname); + WRITE_SYMBOL("init_uts_ns", init_uts_ns); + WRITE_SYMBOL("_stext", _stext); + WRITE_SYMBOL("swapper_pg_dir", swapper_pg_dir); + WRITE_SYMBOL("init_level4_pgt", init_level4_pgt); + WRITE_SYMBOL("vmlist", vmlist); + WRITE_SYMBOL("phys_base", phys_base); + WRITE_SYMBOL("node_online_map", node_online_map); + WRITE_SYMBOL("node_states", node_states); + WRITE_SYMBOL("node_data", node_data); + WRITE_SYMBOL("pgdat_list", pgdat_list); + WRITE_SYMBOL("contig_page_data", contig_page_data); + WRITE_SYMBOL("log_buf", log_buf); + WRITE_SYMBOL("log_buf_len", log_buf_len); + WRITE_SYMBOL("log_end", log_end); + WRITE_SYMBOL("log_first_idx", log_first_idx); + WRITE_SYMBOL("log_next_idx", log_next_idx); + WRITE_SYMBOL("max_pfn", max_pfn); + WRITE_SYMBOL("high_memory", high_memory); + WRITE_SYMBOL("node_remap_start_vaddr", node_remap_start_vaddr); + WRITE_SYMBOL("node_remap_end_vaddr", node_remap_end_vaddr); + WRITE_SYMBOL("node_remap_start_pfn", node_remap_start_pfn); - else if (sym.st_value < next_symbol) - next_symbol = sym.st_value; - } - } -out: - clean_dwfl_info(); + /* + * write the structure size of 1st kernel + */ + WRITE_STRUCTURE_SIZE("page", page); + WRITE_STRUCTURE_SIZE("mem_section", mem_section); + WRITE_STRUCTURE_SIZE("pglist_data", pglist_data); + WRITE_STRUCTURE_SIZE("zone", zone); + WRITE_STRUCTURE_SIZE("free_area", free_area); + WRITE_STRUCTURE_SIZE("list_head", list_head); + WRITE_STRUCTURE_SIZE("node_memblk_s", node_memblk_s); + WRITE_STRUCTURE_SIZE("nodemask_t", nodemask_t); + WRITE_STRUCTURE_SIZE("pageflags", pageflags); + WRITE_STRUCTURE_SIZE("log", log); - return next_symbol; -} + /* + * write the member offset of 1st kernel + */ + WRITE_MEMBER_OFFSET("page.flags", page.flags); + WRITE_MEMBER_OFFSET("page._count", page._count); + WRITE_MEMBER_OFFSET("page.mapping", page.mapping); + WRITE_MEMBER_OFFSET("page.lru", page.lru); + WRITE_MEMBER_OFFSET("page._mapcount", page._mapcount); + WRITE_MEMBER_OFFSET("page.private", page.private); + WRITE_MEMBER_OFFSET("mem_section.section_mem_map", + mem_section.section_mem_map); + WRITE_MEMBER_OFFSET("pglist_data.node_zones", pglist_data.node_zones); + WRITE_MEMBER_OFFSET("pglist_data.nr_zones", pglist_data.nr_zones); + WRITE_MEMBER_OFFSET("pglist_data.node_mem_map", + pglist_data.node_mem_map); + WRITE_MEMBER_OFFSET("pglist_data.node_start_pfn", + pglist_data.node_start_pfn); + WRITE_MEMBER_OFFSET("pglist_data.node_spanned_pages", + pglist_data.node_spanned_pages); + WRITE_MEMBER_OFFSET("pglist_data.pgdat_next", pglist_data.pgdat_next); + WRITE_MEMBER_OFFSET("zone.free_pages", zone.free_pages); + WRITE_MEMBER_OFFSET("zone.free_area", zone.free_area); + WRITE_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat); + WRITE_MEMBER_OFFSET("zone.spanned_pages", zone.spanned_pages); + WRITE_MEMBER_OFFSET("free_area.free_list", free_area.free_list); + WRITE_MEMBER_OFFSET("list_head.next", list_head.next); + WRITE_MEMBER_OFFSET("list_head.prev", list_head.prev); + WRITE_MEMBER_OFFSET("node_memblk_s.start_paddr", node_memblk_s.start_paddr); + WRITE_MEMBER_OFFSET("node_memblk_s.size", node_memblk_s.size); + WRITE_MEMBER_OFFSET("node_memblk_s.nid", node_memblk_s.nid); + WRITE_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr); + WRITE_MEMBER_OFFSET("log.ts_nsec", log.ts_nsec); + WRITE_MEMBER_OFFSET("log.len", log.len); + WRITE_MEMBER_OFFSET("log.text_len", log.text_len); -int -is_kvaddr(unsigned long long addr) -{ - return (addr >= (unsigned long long)(KVBASE)); -} + if (SYMBOL(node_data) != NOT_FOUND_SYMBOL) + WRITE_ARRAY_LENGTH("node_data", node_data); + if (SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) + WRITE_ARRAY_LENGTH("pgdat_list", pgdat_list); + if (SYMBOL(mem_section) != NOT_FOUND_SYMBOL) + WRITE_ARRAY_LENGTH("mem_section", mem_section); + if (SYMBOL(node_memblk) != NOT_FOUND_SYMBOL) + WRITE_ARRAY_LENGTH("node_memblk", node_memblk); + if (SYMBOL(node_remap_start_pfn) != NOT_FOUND_SYMBOL) + WRITE_ARRAY_LENGTH("node_remap_start_pfn", + node_remap_start_pfn); -static int -get_data_member_location(Dwarf_Die *die, long *offset) -{ - size_t expcnt; - Dwarf_Attribute attr; - Dwarf_Op *expr; + WRITE_ARRAY_LENGTH("zone.free_area", zone.free_area); + WRITE_ARRAY_LENGTH("free_area.free_list", free_area.free_list); - if (dwarf_attr(die, DW_AT_data_member_location, &attr) == NULL) - return FALSE; + WRITE_NUMBER("NR_FREE_PAGES", NR_FREE_PAGES); + WRITE_NUMBER("N_ONLINE", N_ONLINE); - if (dwarf_getlocation(&attr, &expr, &expcnt) < 0) - return FALSE; + WRITE_NUMBER("PG_lru", PG_lru); + WRITE_NUMBER("PG_private", PG_private); + WRITE_NUMBER("PG_swapcache", PG_swapcache); + WRITE_NUMBER("PG_buddy", PG_buddy); + WRITE_NUMBER("PG_slab", PG_slab); + WRITE_NUMBER("PG_hwpoison", PG_hwpoison); - (*offset) = expr[0].number; + WRITE_NUMBER("PAGE_BUDDY_MAPCOUNT_VALUE", PAGE_BUDDY_MAPCOUNT_VALUE); - return TRUE; + /* + * write the source file of 1st kernel + */ + WRITE_SRCFILE("pud_t", pud_t); } -static int -get_die_type(Dwarf *dwarfd, Dwarf_Die *die, Dwarf_Die *die_type) +int +generate_vmcoreinfo(void) { - Dwarf_Attribute attr; - Dwarf_Off offset_type, offset_cu; + if (!set_page_size(sysconf(_SC_PAGE_SIZE))) + return FALSE; - offset_cu = dwarf_dieoffset(die) - dwarf_cuoffset(die); + set_dwarf_debuginfo("vmlinux", NULL, + info->name_vmlinux, info->fd_vmlinux); - /* - * Get the offset of DW_AT_type. - */ - if (dwarf_attr(die, DW_AT_type, &attr) == NULL) + if (!get_symbol_info()) return FALSE; - if (dwarf_formref(&attr, &offset_type) < 0) + if (!get_structure_info()) return FALSE; - if (dwarf_offdie(dwarfd, offset_type + offset_cu, die_type) == NULL) { - ERRMSG("Can't get CU die.\n"); + if (!get_srcfile_info()) return FALSE; - } - return TRUE; -} -static int -get_data_array_length(Dwarf *dwarfd, Dwarf_Die *die) -{ - int tag; - Dwarf_Attribute attr; - Dwarf_Die die_type; - Dwarf_Word upper_bound; - - if (!get_die_type(dwarfd, die, &die_type)) { - ERRMSG("Can't get CU die of DW_AT_type.\n"); + if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL) + && (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) { + ERRMSG("Can't get the symbol of system_utsname.\n"); return FALSE; } - tag = dwarf_tag(&die_type); - if (tag == DW_TAG_const_type) { - /* This array is of const type. Get the die type again */ - if (!get_die_type(dwarfd, &die_type, &die_type)) { - ERRMSG("Can't get CU die of DW_AT_type.\n"); - return FALSE; - } - tag = dwarf_tag(&die_type); - } - if (tag != DW_TAG_array_type) { - /* - * This kernel doesn't have the member of array. - */ - return TRUE; - } - - /* - * Get the demanded array length. - */ - dwarf_child(&die_type, &die_type); - do { - tag = dwarf_tag(&die_type); - if (tag == DW_TAG_subrange_type) - break; - } while (dwarf_siblingof(&die_type, &die_type)); - - if (tag != DW_TAG_subrange_type) - return FALSE; - - if (dwarf_attr(&die_type, DW_AT_upper_bound, &attr) == NULL) + if (!get_str_osrelease_from_vmlinux()) return FALSE; - if (dwarf_formudata(&attr, &upper_bound) < 0) + if (!(info->kernel_version = get_kernel_version(info->release))) return FALSE; - if (upper_bound < 0) + if (get_mem_type() == NOT_FOUND_MEMTYPE) { + ERRMSG("Can't find the memory type.\n"); return FALSE; + } - dwarf_info.array_length = upper_bound + 1; + write_vmcoreinfo_data(); return TRUE; } -static int -check_array_type(Dwarf *dwarfd, Dwarf_Die *die) +int +read_vmcoreinfo_basic_info(void) { - int tag; - Dwarf_Die die_type; + time_t tv_sec = 0; + long page_size = FALSE; + char buf[BUFSIZE_FGETS], *endp; + unsigned int get_release = FALSE, i; - if (!get_die_type(dwarfd, die, &die_type)) { - ERRMSG("Can't get CU die of DW_AT_type.\n"); + if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); return FALSE; } - tag = dwarf_tag(&die_type); - if (tag == DW_TAG_array_type) - dwarf_info.array_length = FOUND_ARRAY_TYPE; - - return TRUE; -} -static int -get_dwarf_base_type(Dwarf *dwarfd, Dwarf_Die *die) -{ - int tag; - const char *name; - - while (get_die_type(dwarfd, die, die)) { - tag = dwarf_tag(die); - switch (tag) { - case DW_TAG_array_type: - dwarf_info.type_flag |= TYPE_ARRAY; - break; - case DW_TAG_pointer_type: - dwarf_info.type_flag |= TYPE_PTR; - break; - case DW_TAG_structure_type: - dwarf_info.type_flag |= TYPE_STRUCT; - break; - case DW_TAG_base_type: - dwarf_info.type_flag |= TYPE_BASE; + while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { + i = strlen(buf); + if (!i) break; + if (buf[i - 1] == '\n') + buf[i - 1] = '\0'; + if (strncmp(buf, STR_OSRELEASE, strlen(STR_OSRELEASE)) == 0) { + get_release = TRUE; + /* if the release have been stored, skip this time. */ + if (strlen(info->release)) + continue; + strcpy(info->release, buf + strlen(STR_OSRELEASE)); } - } + if (strncmp(buf, STR_PAGESIZE, strlen(STR_PAGESIZE)) == 0) { + page_size = strtol(buf+strlen(STR_PAGESIZE),&endp,10); + if ((!page_size || page_size == LONG_MAX) + || strlen(endp) != 0) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); + return FALSE; + } + if (!set_page_size(page_size)) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); + return FALSE; + } + } + if (strncmp(buf, STR_CRASHTIME, strlen(STR_CRASHTIME)) == 0) { + tv_sec = strtol(buf+strlen(STR_CRASHTIME),&endp,10); + if ((!tv_sec || tv_sec == LONG_MAX) + || strlen(endp) != 0) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); + return FALSE; + } + info->timestamp.tv_sec = tv_sec; + } + if (strncmp(buf, STR_CONFIG_X86_PAE, + strlen(STR_CONFIG_X86_PAE)) == 0) + vt.mem_flags |= MEMORY_X86_PAE; - name = dwarf_diename(die); - if (name) - dwarf_info.type_name = strdup(name); - else if (dwarf_info.type_flag == TYPE_PTR) - dwarf_info.type_name = strdup("void"); - - dwarf_info.struct_size = dwarf_bytesize(die); + if (strncmp(buf, STR_CONFIG_PGTABLE_3, + strlen(STR_CONFIG_PGTABLE_3)) == 0) + vt.mem_flags |= MEMORY_PAGETABLE_3L; + if (strncmp(buf, STR_CONFIG_PGTABLE_4, + strlen(STR_CONFIG_PGTABLE_4)) == 0) + vt.mem_flags |= MEMORY_PAGETABLE_4L; + } + if (!get_release || !info->page_size) { + ERRMSG("Invalid format in %s", info->name_vmcoreinfo); + return FALSE; + } return TRUE; } -/* - * Function for searching struct page.union.struct.mapping. - */ -int -__search_mapping(Dwarf *dwarfd, Dwarf_Die *die, long *offset) +unsigned long +read_vmcoreinfo_symbol(char *str_symbol) { - int tag; - const char *name; - Dwarf_Die child, *walker; + unsigned long symbol = NOT_FOUND_SYMBOL; + char buf[BUFSIZE_FGETS], *endp; + unsigned int i; - if (dwarf_child(die, &child) != 0) - return FALSE; + if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); + return INVALID_SYMBOL_DATA; + } - walker = &child; - do { - tag = dwarf_tag(walker); - name = dwarf_diename(walker); + while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { + i = strlen(buf); + if (!i) + break; + if (buf[i - 1] == '\n') + buf[i - 1] = '\0'; + if (strncmp(buf, str_symbol, strlen(str_symbol)) == 0) { + symbol = strtoul(buf + strlen(str_symbol), &endp, 16); + if ((!symbol || symbol == ULONG_MAX) + || strlen(endp) != 0) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); + return INVALID_SYMBOL_DATA; + } + break; + } + } + return symbol; +} - if (tag != DW_TAG_member) - continue; - if ((!name) || strcmp(name, dwarf_info.member_name)) - continue; - if (!get_data_member_location(walker, offset)) - continue; - return TRUE; +long +read_vmcoreinfo_long(char *str_structure) +{ + long data = NOT_FOUND_LONG_VALUE; + char buf[BUFSIZE_FGETS], *endp; + unsigned int i; - } while (!dwarf_siblingof(walker, walker)); + if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); + return INVALID_STRUCTURE_DATA; + } - return FALSE; + while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { + i = strlen(buf); + if (!i) + break; + if (buf[i - 1] == '\n') + buf[i - 1] = '\0'; + if (strncmp(buf, str_structure, strlen(str_structure)) == 0) { + data = strtol(buf + strlen(str_structure), &endp, 10); + if ((data == LONG_MAX) || strlen(endp) != 0) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); + return INVALID_STRUCTURE_DATA; + } + break; + } + } + return data; } -/* - * Function for searching struct page.union.struct. - */ int -search_mapping(Dwarf *dwarfd, Dwarf_Die *die, long *offset) +read_vmcoreinfo_string(char *str_in, char *str_out) { - Dwarf_Die child, *walker; - Dwarf_Die die_struct; + char buf[BUFSIZE_FGETS]; + unsigned int i; - if (dwarf_child(die, &child) != 0) + if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); return FALSE; + } - walker = &child; - - do { - if (dwarf_tag(walker) != DW_TAG_member) - continue; - if (!get_die_type(dwarfd, walker, &die_struct)) - continue; - if (dwarf_tag(&die_struct) != DW_TAG_structure_type) - continue; - if (__search_mapping(dwarfd, &die_struct, offset)) - return TRUE; - } while (!dwarf_siblingof(walker, walker)); - - return FALSE; + while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { + i = strlen(buf); + if (!i) + break; + if (buf[i - 1] == '\n') + buf[i - 1] = '\0'; + if (strncmp(buf, str_in, strlen(str_in)) == 0) { + strncpy(str_out, buf + strlen(str_in), LEN_SRCFILE - strlen(str_in)); + break; + } + } + return TRUE; } -static void -search_member(Dwarf *dwarfd, Dwarf_Die *die) +int +read_vmcoreinfo(void) { - int tag; - long offset, offset_union; - const char *name; - Dwarf_Die child, *walker, die_union; + if (!read_vmcoreinfo_basic_info()) + return FALSE; - if (dwarf_child(die, &child) != 0) - return; + READ_SYMBOL("mem_map", mem_map); + READ_SYMBOL("vmem_map", vmem_map); + READ_SYMBOL("mem_section", mem_section); + READ_SYMBOL("pkmap_count", pkmap_count); + READ_SYMBOL("pkmap_count_next", pkmap_count_next); + READ_SYMBOL("system_utsname", system_utsname); + READ_SYMBOL("init_uts_ns", init_uts_ns); + READ_SYMBOL("_stext", _stext); + READ_SYMBOL("swapper_pg_dir", swapper_pg_dir); + READ_SYMBOL("init_level4_pgt", init_level4_pgt); + READ_SYMBOL("vmlist", vmlist); + READ_SYMBOL("phys_base", phys_base); + READ_SYMBOL("node_online_map", node_online_map); + READ_SYMBOL("node_states", node_states); + READ_SYMBOL("node_data", node_data); + READ_SYMBOL("pgdat_list", pgdat_list); + READ_SYMBOL("contig_page_data", contig_page_data); + READ_SYMBOL("log_buf", log_buf); + READ_SYMBOL("log_buf_len", log_buf_len); + READ_SYMBOL("log_end", log_end); + READ_SYMBOL("log_first_idx", log_first_idx); + READ_SYMBOL("log_next_idx", log_next_idx); + READ_SYMBOL("max_pfn", max_pfn); + READ_SYMBOL("high_memory", high_memory); + READ_SYMBOL("node_remap_start_vaddr", node_remap_start_vaddr); + READ_SYMBOL("node_remap_end_vaddr", node_remap_end_vaddr); + READ_SYMBOL("node_remap_start_pfn", node_remap_start_pfn); - walker = &child; + READ_STRUCTURE_SIZE("page", page); + READ_STRUCTURE_SIZE("mem_section", mem_section); + READ_STRUCTURE_SIZE("pglist_data", pglist_data); + READ_STRUCTURE_SIZE("zone", zone); + READ_STRUCTURE_SIZE("free_area", free_area); + READ_STRUCTURE_SIZE("list_head", list_head); + READ_STRUCTURE_SIZE("node_memblk_s", node_memblk_s); + READ_STRUCTURE_SIZE("nodemask_t", nodemask_t); + READ_STRUCTURE_SIZE("pageflags", pageflags); + READ_STRUCTURE_SIZE("log", log); - do { - tag = dwarf_tag(walker); - name = dwarf_diename(walker); + READ_MEMBER_OFFSET("page.flags", page.flags); + READ_MEMBER_OFFSET("page._count", page._count); + READ_MEMBER_OFFSET("page.mapping", page.mapping); + READ_MEMBER_OFFSET("page.lru", page.lru); + READ_MEMBER_OFFSET("page._mapcount", page._mapcount); + READ_MEMBER_OFFSET("page.private", page.private); + READ_MEMBER_OFFSET("mem_section.section_mem_map", + mem_section.section_mem_map); + READ_MEMBER_OFFSET("pglist_data.node_zones", pglist_data.node_zones); + READ_MEMBER_OFFSET("pglist_data.nr_zones", pglist_data.nr_zones); + READ_MEMBER_OFFSET("pglist_data.node_mem_map",pglist_data.node_mem_map); + READ_MEMBER_OFFSET("pglist_data.node_start_pfn", + pglist_data.node_start_pfn); + READ_MEMBER_OFFSET("pglist_data.node_spanned_pages", + pglist_data.node_spanned_pages); + READ_MEMBER_OFFSET("pglist_data.pgdat_next", pglist_data.pgdat_next); + READ_MEMBER_OFFSET("zone.free_pages", zone.free_pages); + READ_MEMBER_OFFSET("zone.free_area", zone.free_area); + READ_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat); + READ_MEMBER_OFFSET("zone.spanned_pages", zone.spanned_pages); + READ_MEMBER_OFFSET("free_area.free_list", free_area.free_list); + READ_MEMBER_OFFSET("list_head.next", list_head.next); + READ_MEMBER_OFFSET("list_head.prev", list_head.prev); + READ_MEMBER_OFFSET("node_memblk_s.start_paddr", node_memblk_s.start_paddr); + READ_MEMBER_OFFSET("node_memblk_s.size", node_memblk_s.size); + READ_MEMBER_OFFSET("node_memblk_s.nid", node_memblk_s.nid); + READ_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr); + READ_MEMBER_OFFSET("log.ts_nsec", log.ts_nsec); + READ_MEMBER_OFFSET("log.len", log.len); + READ_MEMBER_OFFSET("log.text_len", log.text_len); - if (tag != DW_TAG_member) - continue; + READ_ARRAY_LENGTH("node_data", node_data); + READ_ARRAY_LENGTH("pgdat_list", pgdat_list); + READ_ARRAY_LENGTH("mem_section", mem_section); + READ_ARRAY_LENGTH("node_memblk", node_memblk); + READ_ARRAY_LENGTH("zone.free_area", zone.free_area); + READ_ARRAY_LENGTH("free_area.free_list", free_area.free_list); + READ_ARRAY_LENGTH("node_remap_start_pfn", node_remap_start_pfn); - switch (dwarf_info.cmd) { - case DWARF_INFO_GET_MEMBER_TYPE: - if ((!name) || strcmp(name, dwarf_info.member_name)) - continue; - /* - * Get the member offset. - */ - if (!get_dwarf_base_type(dwarfd, walker)) - continue; - return; - case DWARF_INFO_GET_MEMBER_OFFSET: - if ((!name) || strcmp(name, dwarf_info.member_name)) - continue; - /* - * Get the member offset. - */ - if (!get_data_member_location(walker, &offset)) - continue; - dwarf_info.member_offset = offset; - return; - case DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION: - if (!get_die_type(dwarfd, walker, &die_union)) - continue; - if (dwarf_tag(&die_union) != DW_TAG_union_type) - continue; - /* - * Search page.mapping in union. - */ - if (!search_mapping(dwarfd, &die_union, &offset_union)) - continue; - /* - * Get the member offset. - */ - if (!get_data_member_location(walker, &offset)) - continue; - dwarf_info.member_offset = offset + offset_union; - return; - case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION: - if (!get_die_type(dwarfd, walker, &die_union)) - continue; - if (dwarf_tag(&die_union) != DW_TAG_union_type) - continue; - /* - * Get the member offset. - */ - if (!get_data_member_location(walker, &offset)) - continue; - dwarf_info.member_offset = offset; - return; - case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: - if ((!name) || strcmp(name, dwarf_info.member_name)) - continue; - /* - * Get the member length. - */ - if (!get_data_array_length(dwarfd, walker)) - continue; - return; - } - } while (!dwarf_siblingof(walker, walker)); + READ_NUMBER("NR_FREE_PAGES", NR_FREE_PAGES); + READ_NUMBER("N_ONLINE", N_ONLINE); - /* - * Return even if not found. - */ - return; -} + READ_NUMBER("PG_lru", PG_lru); + READ_NUMBER("PG_private", PG_private); + READ_NUMBER("PG_swapcache", PG_swapcache); + READ_NUMBER("PG_slab", PG_slab); + READ_NUMBER("PG_buddy", PG_buddy); + READ_NUMBER("PG_hwpoison", PG_hwpoison); -int -is_search_structure(int cmd) -{ - if ((cmd == DWARF_INFO_GET_STRUCT_SIZE) - || (cmd == DWARF_INFO_GET_MEMBER_OFFSET) - || (cmd == DWARF_INFO_GET_MEMBER_TYPE) - || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION) - || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION) - || (cmd == DWARF_INFO_GET_MEMBER_ARRAY_LENGTH)) - return TRUE; - else - return FALSE; -} + READ_SRCFILE("pud_t", pud_t); -int -is_search_number(int cmd) -{ - if (cmd == DWARF_INFO_GET_ENUM_NUMBER) - return TRUE; - else - return FALSE; -} + READ_NUMBER("PAGE_BUDDY_MAPCOUNT_VALUE", PAGE_BUDDY_MAPCOUNT_VALUE); -int -is_search_symbol(int cmd) -{ - if ((cmd == DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH) - || (cmd == DWARF_INFO_GET_SYMBOL_TYPE) - || (cmd == DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE)) - return TRUE; - else - return FALSE; + return TRUE; } +/* + * Extract vmcoreinfo from /proc/vmcore and output it to /tmp/vmcoreinfo.tmp. + */ int -is_search_typedef(int cmd) -{ - if ((cmd == DWARF_INFO_GET_TYPEDEF_SIZE) - || (cmd == DWARF_INFO_GET_TYPEDEF_SRCNAME)) - return TRUE; - else - return FALSE; -} - -static void -search_structure(Dwarf *dwarfd, Dwarf_Die *die, int *found) +copy_vmcoreinfo(off_t offset, unsigned long size) { - int tag; - const char *name; - - /* - * If we get to here then we don't have any more - * children, check to see if this is a relevant tag - */ - do { - tag = dwarf_tag(die); - name = dwarf_diename(die); - if ((tag != DW_TAG_structure_type) || (!name) - || strcmp(name, dwarf_info.struct_name)) - continue; - /* - * Skip if DW_AT_byte_size is not included. - */ - dwarf_info.struct_size = dwarf_bytesize(die); - - if (dwarf_info.struct_size > 0) - break; + int fd; + char buf[VMCOREINFO_BYTES]; + const off_t failed = (off_t)-1; - } while (!dwarf_siblingof(die, die)); + if (!offset || !size) + return FALSE; - if (dwarf_info.struct_size <= 0) { - /* - * Not found the demanded structure. - */ - return; + if ((fd = mkstemp(info->name_vmcoreinfo)) < 0) { + ERRMSG("Can't open the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); + return FALSE; } - - /* - * Found the demanded structure. - */ - *found = TRUE; - switch (dwarf_info.cmd) { - case DWARF_INFO_GET_STRUCT_SIZE: - break; - case DWARF_INFO_GET_MEMBER_TYPE: - case DWARF_INFO_GET_MEMBER_OFFSET: - case DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION: - case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION: - case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: - search_member(dwarfd, die); - break; + if (lseek(info->fd_memory, offset, SEEK_SET) == failed) { + ERRMSG("Can't seek the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + return FALSE; } + if (read(info->fd_memory, &buf, size) != size) { + ERRMSG("Can't read the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + return FALSE; + } + if (write(fd, &buf, size) != size) { + ERRMSG("Can't write the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); + return FALSE; + } + if (close(fd) < 0) { + ERRMSG("Can't close the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); + return FALSE; + } + return TRUE; } -static void -search_number(Dwarf *dwarfd, Dwarf_Die *die, int *found) +int +read_vmcoreinfo_from_vmcore(off_t offset, unsigned long size, int flag_xen_hv) { - int tag; - Dwarf_Word const_value; - Dwarf_Attribute attr; - Dwarf_Die child, *walker; - const char *name; + int ret = FALSE; - do { - tag = dwarf_tag(die); - if (tag != DW_TAG_enumeration_type) - continue; + /* + * Copy vmcoreinfo to /tmp/vmcoreinfoXXXXXX. + */ + if (!(info->name_vmcoreinfo = strdup(FILENAME_VMCOREINFO))) { + MSG("Can't duplicate strings(%s).\n", FILENAME_VMCOREINFO); + return FALSE; + } + if (!copy_vmcoreinfo(offset, size)) + goto out; - if (dwarf_child(die, &child) != 0) - continue; + /* + * Read vmcoreinfo from /tmp/vmcoreinfoXXXXXX. + */ + if (!open_vmcoreinfo("r")) + goto out; - walker = &child; + unlink(info->name_vmcoreinfo); - do { - tag = dwarf_tag(walker); - name = dwarf_diename(walker); + if (flag_xen_hv) { + if (!read_vmcoreinfo_xen()) + goto out; + } else { + if (!read_vmcoreinfo()) + goto out; + } + close_vmcoreinfo(); - if ((tag != DW_TAG_enumerator) || (!name) - || strcmp(name, dwarf_info.enum_name)) - continue; + ret = TRUE; +out: + free(info->name_vmcoreinfo); + info->name_vmcoreinfo = NULL; - if (!dwarf_attr(walker, DW_AT_const_value, &attr)) - continue; + return ret; +} - if (dwarf_formudata(&attr, &const_value) < 0) - continue; +/* + * Get the number of online nodes. + */ +int +get_nodes_online(void) +{ + int len, i, j, online; + unsigned long node_online_map = 0, bitbuf, *maskptr; - *found = TRUE; - dwarf_info.enum_number = (long)const_value; + if ((SYMBOL(node_online_map) == NOT_FOUND_SYMBOL) + && (SYMBOL(node_states) == NOT_FOUND_SYMBOL)) + return 0; - } while (!dwarf_siblingof(walker, walker)); + if (SIZE(nodemask_t) == NOT_FOUND_STRUCTURE) { + ERRMSG("Can't get the size of nodemask_t.\n"); + return 0; + } - } while (!dwarf_siblingof(die, die)); + len = SIZE(nodemask_t); + vt.node_online_map_len = len/sizeof(unsigned long); + if (!(vt.node_online_map = (unsigned long *)malloc(len))) { + ERRMSG("Can't allocate memory for the node online map. %s\n", + strerror(errno)); + return 0; + } + if (SYMBOL(node_online_map) != NOT_FOUND_SYMBOL) { + node_online_map = SYMBOL(node_online_map); + } else if (SYMBOL(node_states) != NOT_FOUND_SYMBOL) { + /* + * For linux-2.6.23-rc4-mm1 + */ + node_online_map = SYMBOL(node_states) + + (SIZE(nodemask_t) * NUMBER(N_ONLINE)); + } + if (!readmem(VADDR, node_online_map, vt.node_online_map, len)){ + ERRMSG("Can't get the node online map.\n"); + return 0; + } + online = 0; + maskptr = (unsigned long *)vt.node_online_map; + for (i = 0; i < vt.node_online_map_len; i++, maskptr++) { + bitbuf = *maskptr; + for (j = 0; j < sizeof(bitbuf) * 8; j++) { + online += bitbuf & 1; + bitbuf = bitbuf >> 1; + } + } + return online; } -static void -search_typedef(Dwarf *dwarfd, Dwarf_Die *die, int *found) +int +get_numnodes(void) { - int tag = 0; - char *src_name = NULL; - const char *name; - Dwarf_Die die_type; - - /* - * If we get to here then we don't have any more - * children, check to see if this is a relevant tag - */ - do { - tag = dwarf_tag(die); - name = dwarf_diename(die); + if (!(vt.numnodes = get_nodes_online())) { + vt.numnodes = 1; + } + DEBUG_MSG("\n"); + DEBUG_MSG("num of NODEs : %d\n", vt.numnodes); + DEBUG_MSG("\n"); - if ((tag != DW_TAG_typedef) || (!name) - || strcmp(name, dwarf_info.struct_name)) - continue; + return TRUE; +} - if (dwarf_info.cmd == DWARF_INFO_GET_TYPEDEF_SIZE) { - if (!get_die_type(dwarfd, die, &die_type)) { - ERRMSG("Can't get CU die of DW_AT_type.\n"); - break; - } - dwarf_info.struct_size = dwarf_bytesize(&die_type); - if (dwarf_info.struct_size <= 0) - continue; +int +next_online_node(int first) +{ + int i, j, node; + unsigned long mask, *maskptr; - *found = TRUE; - break; - } else if (dwarf_info.cmd == DWARF_INFO_GET_TYPEDEF_SRCNAME) { - src_name = (char *)dwarf_decl_file(die); - if (!src_name) - continue; + /* It cannot occur */ + if ((first/(sizeof(unsigned long) * 8)) >= vt.node_online_map_len) { + ERRMSG("next_online_node: %d is too large!\n", first); + return -1; + } - *found = TRUE; - strncpy(dwarf_info.src_name, src_name, LEN_SRCFILE); - break; + maskptr = (unsigned long *)vt.node_online_map; + for (i = node = 0; i < vt.node_online_map_len; i++, maskptr++) { + mask = *maskptr; + for (j = 0; j < (sizeof(unsigned long) * 8); j++, node++) { + if (mask & 1) { + if (node >= first) + return node; + } + mask >>= 1; } - } while (!dwarf_siblingof(die, die)); + } + return -1; } -static void -search_symbol(Dwarf *dwarfd, Dwarf_Die *die, int *found) +unsigned long +next_online_pgdat(int node) { - int tag; - const char *name; + int i; + unsigned long pgdat; /* - * If we get to here then we don't have any more - * children, check to see if this is a relevant tag + * Get the pglist_data structure from symbol "node_data". + * The array number of symbol "node_data" cannot be gotten + * from vmlinux. Instead, check it is DW_TAG_array_type. */ - do { - tag = dwarf_tag(die); - name = dwarf_diename(die); + if ((SYMBOL(node_data) == NOT_FOUND_SYMBOL) + || (ARRAY_LENGTH(node_data) == NOT_FOUND_STRUCTURE)) + goto pgdat2; - if ((tag == DW_TAG_variable) && (name) - && !strcmp(name, dwarf_info.symbol_name)) - break; + if (!readmem(VADDR, SYMBOL(node_data) + (node * sizeof(void *)), + &pgdat, sizeof pgdat)) + goto pgdat2; - } while (!dwarf_siblingof(die, die)); + if (!is_kvaddr(pgdat)) + goto pgdat2; - if ((tag != DW_TAG_variable) || (!name) - || strcmp(name, dwarf_info.symbol_name)) { - /* - * Not found the demanded symbol. - */ - return; - } + return pgdat; +pgdat2: /* - * Found the demanded symbol. + * Get the pglist_data structure from symbol "pgdat_list". */ - *found = TRUE; - switch (dwarf_info.cmd) { - case DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH: - get_data_array_length(dwarfd, die); - break; - case DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE: - check_array_type(dwarfd, die); - break; - case DWARF_INFO_GET_SYMBOL_TYPE: - get_dwarf_base_type(dwarfd, die); - break; - } -} - -static void -search_die_tree(Dwarf *dwarfd, Dwarf_Die *die, int *found) -{ - Dwarf_Die child; + if (SYMBOL(pgdat_list) == NOT_FOUND_SYMBOL) + goto pgdat3; - /* - * start by looking at the children - */ - if (dwarf_child(die, &child) == 0) - search_die_tree(dwarfd, &child, found); + else if ((0 < node) + && (ARRAY_LENGTH(pgdat_list) == NOT_FOUND_STRUCTURE)) + goto pgdat3; - if (*found) - return; + else if ((ARRAY_LENGTH(pgdat_list) != NOT_FOUND_STRUCTURE) + && (ARRAY_LENGTH(pgdat_list) < node)) + goto pgdat3; - if (is_search_structure(dwarf_info.cmd)) - search_structure(dwarfd, die, found); + if (!readmem(VADDR, SYMBOL(pgdat_list) + (node * sizeof(void *)), + &pgdat, sizeof pgdat)) + goto pgdat3; - else if (is_search_number(dwarf_info.cmd)) - search_number(dwarfd, die, found); + if (!is_kvaddr(pgdat)) + goto pgdat3; - else if (is_search_symbol(dwarf_info.cmd)) - search_symbol(dwarfd, die, found); + return pgdat; - else if (is_search_typedef(dwarf_info.cmd)) - search_typedef(dwarfd, die, found); -} +pgdat3: + /* + * linux-2.6.16 or former + */ + if ((SYMBOL(pgdat_list) == NOT_FOUND_SYMBOL) + || (OFFSET(pglist_data.pgdat_next) == NOT_FOUND_STRUCTURE)) + goto pgdat4; -int -get_debug_info(void) -{ - int found = FALSE; - char *name = NULL; - size_t shstrndx, header_size; - uint8_t address_size, offset_size; - Dwarf *dwarfd = NULL; - Elf *elfd = NULL; - Dwarf_Off off = 0, next_off = 0, abbrev_offset = 0; - Elf_Scn *scn = NULL; - GElf_Shdr scnhdr_mem, *scnhdr = NULL; - Dwarf_Die cu_die; + if (!readmem(VADDR, SYMBOL(pgdat_list), &pgdat, sizeof pgdat)) + goto pgdat4; - int ret = FALSE; + if (!is_kvaddr(pgdat)) + goto pgdat4; - if (!init_dwarf_info()) - return FALSE; + if (node == 0) + return pgdat; - elfd = dwarf_info.elfd; - dwarfd = dwarf_info.dwarfd; + for (i = 1; i <= node; i++) { + if (!readmem(VADDR, pgdat+OFFSET(pglist_data.pgdat_next), + &pgdat, sizeof pgdat)) + goto pgdat4; - if (elf_getshstrndx(elfd, &shstrndx) < 0) { - ERRMSG("Can't get the section index of the string table.\n"); - goto out; + if (!is_kvaddr(pgdat)) + goto pgdat4; } + return pgdat; +pgdat4: /* - * Search for ".debug_info" section. + * Get the pglist_data structure from symbol "contig_page_data". */ - while ((scn = elf_nextscn(elfd, scn)) != NULL) { - scnhdr = gelf_getshdr(scn, &scnhdr_mem); - name = elf_strptr(elfd, shstrndx, scnhdr->sh_name); - if (!strcmp(name, ".debug_info")) - break; - } - if (strcmp(name, ".debug_info")) { - ERRMSG("Can't get .debug_info section.\n"); - goto out; - } + if (SYMBOL(contig_page_data) == NOT_FOUND_SYMBOL) + return FALSE; - /* - * Search by each CompileUnit. - */ - while (dwarf_nextcu(dwarfd, off, &next_off, &header_size, - &abbrev_offset, &address_size, &offset_size) == 0) { - off += header_size; - if (dwarf_offdie(dwarfd, off, &cu_die) == NULL) { - ERRMSG("Can't get CU die.\n"); - goto out; - } - search_die_tree(dwarfd, &cu_die, &found); - if (found) - break; - off = next_off; - } - ret = TRUE; -out: - clean_dwfl_info(); + if (node != 0) + return FALSE; - return ret; + return SYMBOL(contig_page_data); } -/* - * Get the size of structure. - */ -long -get_structure_size(char *structname, int flag_typedef) +void +dump_mem_map(unsigned long long pfn_start, + unsigned long long pfn_end, unsigned long mem_map, int num_mm) { - if (flag_typedef) - dwarf_info.cmd = DWARF_INFO_GET_TYPEDEF_SIZE; - else - dwarf_info.cmd = DWARF_INFO_GET_STRUCT_SIZE; + struct mem_map_data *mmd; - dwarf_info.struct_name = structname; - dwarf_info.struct_size = NOT_FOUND_STRUCTURE; + mmd = &info->mem_map_data[num_mm]; + mmd->pfn_start = pfn_start; + mmd->pfn_end = pfn_end; + mmd->mem_map = mem_map; - if (!get_debug_info()) - return FAILED_DWARFINFO; + DEBUG_MSG("mem_map (%d)\n", num_mm); + DEBUG_MSG(" mem_map : %lx\n", mem_map); + DEBUG_MSG(" pfn_start : %llx\n", pfn_start); + DEBUG_MSG(" pfn_end : %llx\n", pfn_end); - return dwarf_info.struct_size; + return; } -/* - * Get the size of pointer. - */ -long -get_pointer_size() +int +get_mm_flatmem(void) { - return sizeof(void *); -} - -/* - * Get the type of given symbol. - */ -char * -get_symbol_type_name(char *symname, int cmd, long *size, - unsigned long *flag) -{ - dwarf_info.cmd = cmd; - dwarf_info.symbol_name = symname; - dwarf_info.type_name = NULL; - dwarf_info.struct_size = NOT_FOUND_STRUCTURE; - dwarf_info.type_flag = 0; - - if (!get_debug_info()) - return NULL; - - if (size) - *size = dwarf_info.struct_size; + unsigned long mem_map; - if (flag) - *flag = dwarf_info.type_flag; + /* + * Get the address of the symbol "mem_map". + */ + if (!readmem(VADDR, SYMBOL(mem_map), &mem_map, sizeof mem_map) + || !mem_map) { + ERRMSG("Can't get the address of mem_map.\n"); + return FALSE; + } + info->num_mem_map = 1; + if ((info->mem_map_data = (struct mem_map_data *) + malloc(sizeof(struct mem_map_data)*info->num_mem_map)) == NULL) { + ERRMSG("Can't allocate memory for the mem_map_data. %s\n", + strerror(errno)); + return FALSE; + } + if (is_xen_memory()) + dump_mem_map(0, info->dom0_mapnr, mem_map, 0); + else + dump_mem_map(0, info->max_mapnr, mem_map, 0); - return dwarf_info.type_name; + return TRUE; } -/* - * Get the offset of member. - */ -long -get_member_offset(char *structname, char *membername, int cmd) +int +get_node_memblk(int num_memblk, + unsigned long *start_paddr, unsigned long *size, int *nid) { - dwarf_info.cmd = cmd; - dwarf_info.struct_name = structname; - dwarf_info.struct_size = NOT_FOUND_STRUCTURE; - dwarf_info.member_name = membername; - dwarf_info.member_offset = NOT_FOUND_STRUCTURE; - - if (!get_debug_info()) - return FAILED_DWARFINFO; + unsigned long node_memblk; - return dwarf_info.member_offset; + if (ARRAY_LENGTH(node_memblk) <= num_memblk) { + ERRMSG("Invalid num_memblk.\n"); + return FALSE; + } + node_memblk = SYMBOL(node_memblk) + SIZE(node_memblk_s) * num_memblk; + if (!readmem(VADDR, node_memblk+OFFSET(node_memblk_s.start_paddr), + start_paddr, sizeof(unsigned long))) { + ERRMSG("Can't get node_memblk_s.start_paddr.\n"); + return FALSE; + } + if (!readmem(VADDR, node_memblk + OFFSET(node_memblk_s.size), + size, sizeof(unsigned long))) { + ERRMSG("Can't get node_memblk_s.size.\n"); + return FALSE; + } + if (!readmem(VADDR, node_memblk + OFFSET(node_memblk_s.nid), + nid, sizeof(int))) { + ERRMSG("Can't get node_memblk_s.nid.\n"); + return FALSE; + } + return TRUE; } -/* - * Get the type name and size of member. - */ -char * -get_member_type_name(char *structname, char *membername, int cmd, long *size, - unsigned long *flag) -{ - dwarf_info.cmd = cmd; - dwarf_info.struct_name = structname; - dwarf_info.struct_size = NOT_FOUND_STRUCTURE; - dwarf_info.member_name = membername; - dwarf_info.type_name = NULL; - dwarf_info.type_flag = 0; - - if (!get_debug_info()) - return NULL; - - if (dwarf_info.struct_size == NOT_FOUND_STRUCTURE) - return NULL; - - if (size) - *size = dwarf_info.struct_size; +int +get_num_mm_discontigmem(void) +{ + int i, nid; + unsigned long start_paddr, size; - if (flag) - *flag = dwarf_info.type_flag; + if ((SYMBOL(node_memblk) == NOT_FOUND_SYMBOL) + || (ARRAY_LENGTH(node_memblk) == NOT_FOUND_STRUCTURE) + || (SIZE(node_memblk_s) == NOT_FOUND_STRUCTURE) + || (OFFSET(node_memblk_s.start_paddr) == NOT_FOUND_STRUCTURE) + || (OFFSET(node_memblk_s.size) == NOT_FOUND_STRUCTURE) + || (OFFSET(node_memblk_s.nid) == NOT_FOUND_STRUCTURE)) { + return vt.numnodes; + } else { + for (i = 0; i < ARRAY_LENGTH(node_memblk); i++) { + if (!get_node_memblk(i, &start_paddr, &size, &nid)) { + ERRMSG("Can't get the node_memblk (%d)\n", i); + return 0; + } + if (!start_paddr && !size &&!nid) + break; - return dwarf_info.type_name; + DEBUG_MSG("nid : %d\n", nid); + DEBUG_MSG(" start_paddr: %lx\n", start_paddr); + DEBUG_MSG(" size : %lx\n", size); + } + if (i == 0) { + /* + * On non-NUMA systems, node_memblk_s is not set. + */ + return vt.numnodes; + } else { + return i; + } + } } -/* - * Get the length of array. - */ -long -get_array_length(char *name01, char *name02, unsigned int cmd) +int +separate_mem_map(struct mem_map_data *mmd, int *id_mm, int nid_pgdat, + unsigned long mem_map_pgdat, unsigned long pfn_start_pgdat) { - switch (cmd) { - case DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH: - dwarf_info.symbol_name = name01; - break; - case DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE: - dwarf_info.symbol_name = name01; - break; - case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: - dwarf_info.struct_name = name01; - dwarf_info.member_name = name02; - break; - } - dwarf_info.cmd = cmd; - dwarf_info.struct_size = NOT_FOUND_STRUCTURE; - dwarf_info.member_offset = NOT_FOUND_STRUCTURE; - dwarf_info.array_length = NOT_FOUND_STRUCTURE; - - if (!get_debug_info()) - return FAILED_DWARFINFO; - - return dwarf_info.array_length; -} + int i, nid; + unsigned long start_paddr, size, pfn_start, pfn_end, mem_map; -long -get_enum_number(char *enum_name) { + for (i = 0; i < ARRAY_LENGTH(node_memblk); i++) { + if (!get_node_memblk(i, &start_paddr, &size, &nid)) { + ERRMSG("Can't get the node_memblk (%d)\n", i); + return FALSE; + } + if (!start_paddr && !size && !nid) + break; - dwarf_info.cmd = DWARF_INFO_GET_ENUM_NUMBER; - dwarf_info.enum_name = enum_name; - dwarf_info.enum_number = NOT_FOUND_NUMBER; + /* + * Check pglist_data.node_id and node_memblk_s.nid match. + */ + if (nid_pgdat != nid) + continue; - if (!get_debug_info()) - return FAILED_DWARFINFO; + pfn_start = paddr_to_pfn(start_paddr); + pfn_end = paddr_to_pfn(start_paddr + size); - return dwarf_info.enum_number; -} + if (pfn_start < pfn_start_pgdat) { + ERRMSG("node_memblk_s.start_paddr of node (%d) is invalid.\n", nid); + return FALSE; + } + if (info->max_mapnr < pfn_end) { + DEBUG_MSG("pfn_end of node (%d) is over max_mapnr.\n", + nid); + DEBUG_MSG(" pfn_start: %lx\n", pfn_start); + DEBUG_MSG(" pfn_end : %lx\n", pfn_end); + DEBUG_MSG(" max_mapnr: %llx\n", info->max_mapnr); -/* - * Get the source filename. - */ -int -get_source_filename(char *structname, char *src_name, int cmd) -{ - dwarf_info.cmd = cmd; - dwarf_info.struct_name = structname; + pfn_end = info->max_mapnr; + } - if (!get_debug_info()) - return FALSE; + mem_map = mem_map_pgdat+SIZE(page)*(pfn_start-pfn_start_pgdat); - strncpy(src_name, dwarf_info.src_name, LEN_SRCFILE); + mmd->pfn_start = pfn_start; + mmd->pfn_end = pfn_end; + mmd->mem_map = mem_map; + mmd++; + (*id_mm)++; + } return TRUE; } int -get_symbol_info(void) +get_mm_discontigmem(void) { - /* - * Get symbol info. - */ - SYMBOL_INIT(mem_map, "mem_map"); - SYMBOL_INIT(vmem_map, "vmem_map"); - SYMBOL_INIT(mem_section, "mem_section"); - SYMBOL_INIT(pkmap_count, "pkmap_count"); - SYMBOL_INIT_NEXT(pkmap_count_next, "pkmap_count"); - SYMBOL_INIT(system_utsname, "system_utsname"); - SYMBOL_INIT(init_uts_ns, "init_uts_ns"); - SYMBOL_INIT(_stext, "_stext"); - SYMBOL_INIT(swapper_pg_dir, "swapper_pg_dir"); - SYMBOL_INIT(init_level4_pgt, "init_level4_pgt"); - SYMBOL_INIT(vmlist, "vmlist"); - SYMBOL_INIT(phys_base, "phys_base"); - SYMBOL_INIT(node_online_map, "node_online_map"); - SYMBOL_INIT(node_states, "node_states"); - SYMBOL_INIT(node_memblk, "node_memblk"); - SYMBOL_INIT(node_data, "node_data"); - SYMBOL_INIT(pgdat_list, "pgdat_list"); - SYMBOL_INIT(contig_page_data, "contig_page_data"); - SYMBOL_INIT(log_buf, "log_buf"); - SYMBOL_INIT(log_buf_len, "log_buf_len"); - SYMBOL_INIT(log_end, "log_end"); - SYMBOL_INIT(max_pfn, "max_pfn"); - SYMBOL_INIT(modules, "modules"); - SYMBOL_INIT(high_memory, "high_memory"); - SYMBOL_INIT(linux_banner, "linux_banner"); - SYMBOL_INIT(bios_cpu_apicid, "bios_cpu_apicid"); - SYMBOL_INIT(x86_bios_cpu_apicid, "x86_bios_cpu_apicid"); - if (SYMBOL(x86_bios_cpu_apicid) == NOT_FOUND_SYMBOL) - SYMBOL_INIT(x86_bios_cpu_apicid, - "per_cpu__x86_bios_cpu_apicid"); - SYMBOL_INIT(x86_bios_cpu_apicid_early_ptr, - "x86_bios_cpu_apicid_early_ptr"); - SYMBOL_INIT(x86_bios_cpu_apicid_early_map, - "x86_bios_cpu_apicid_early_map"); - SYMBOL_INIT(crash_notes, "crash_notes"); - SYMBOL_INIT(__per_cpu_load, "__per_cpu_load"); - SYMBOL_INIT(__per_cpu_offset, "__per_cpu_offset"); - SYMBOL_INIT(cpu_online_mask, "cpu_online_mask"); - if (SYMBOL(cpu_online_mask) == NOT_FOUND_SYMBOL) - SYMBOL_INIT(cpu_online_mask, "cpu_online_map"); - SYMBOL_INIT(kexec_crash_image, "kexec_crash_image"); + int i, j, id_mm, node, num_mem_map, separate_mm = FALSE; + unsigned long pgdat, mem_map, pfn_start, pfn_end, node_spanned_pages; + unsigned long vmem_map; + struct mem_map_data temp_mmd; - if (SYMBOL(node_data) != NOT_FOUND_SYMBOL) - SYMBOL_ARRAY_TYPE_INIT(node_data, "node_data"); - if (SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) - SYMBOL_ARRAY_LENGTH_INIT(pgdat_list, "pgdat_list"); - if (SYMBOL(mem_section) != NOT_FOUND_SYMBOL) - SYMBOL_ARRAY_LENGTH_INIT(mem_section, "mem_section"); - if (SYMBOL(node_memblk) != NOT_FOUND_SYMBOL) - SYMBOL_ARRAY_LENGTH_INIT(node_memblk, "node_memblk"); - if (SYMBOL(__per_cpu_offset) != NOT_FOUND_SYMBOL) - SYMBOL_ARRAY_LENGTH_INIT(__per_cpu_offset, "__per_cpu_offset"); + num_mem_map = get_num_mm_discontigmem(); + if (num_mem_map < vt.numnodes) { + ERRMSG("Can't get the number of mem_map.\n"); + return FALSE; + } + struct mem_map_data mmd[num_mem_map]; + if (vt.numnodes < num_mem_map) { + separate_mm = TRUE; + } - return TRUE; -} + /* + * Note: + * This note is only for ia64 discontigmem kernel. + * It is better to take mem_map information from a symbol vmem_map + * instead of pglist_data.node_mem_map, because some node_mem_map + * sometimes does not have mem_map information corresponding to its + * node_start_pfn. + */ + if (SYMBOL(vmem_map) != NOT_FOUND_SYMBOL) { + if (!readmem(VADDR, SYMBOL(vmem_map), &vmem_map, sizeof vmem_map)) { + ERRMSG("Can't get vmem_map.\n"); + return FALSE; + } + } -int -get_structure_info(void) -{ /* - * Get offsets of the page_discriptor's members. - */ - SIZE_INIT(page, "page"); - OFFSET_INIT(page.flags, "page", "flags"); - OFFSET_INIT(page._count, "page", "_count"); - - OFFSET_INIT(page.mapping, "page", "mapping"); - - /* - * On linux-2.6.16 or later, page.mapping is defined - * in anonymous union. - */ - if (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE) - OFFSET_IN_UNION_INIT(page.mapping, "page", "mapping"); - - /* - * Some vmlinux(s) don't have debugging information about - * page.mapping. Then, makedumpfile assumes that there is - * "mapping" next to "private(unsigned long)" in the first - * union. - */ - if (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE) { - OFFSET(page.mapping) = get_member_offset("page", NULL, - DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION); - if (OFFSET(page.mapping) == FAILED_DWARFINFO) - return FALSE; - if (OFFSET(page.mapping) != NOT_FOUND_STRUCTURE) - OFFSET(page.mapping) += sizeof(unsigned long); - } - - OFFSET_INIT(page.lru, "page", "lru"); - - /* - * Get offsets of the mem_section's members. - */ - SIZE_INIT(mem_section, "mem_section"); - OFFSET_INIT(mem_section.section_mem_map, "mem_section", - "section_mem_map"); - - /* - * Get offsets of the pglist_data's members. - */ - SIZE_INIT(pglist_data, "pglist_data"); - OFFSET_INIT(pglist_data.node_zones, "pglist_data", "node_zones"); - OFFSET_INIT(pglist_data.nr_zones, "pglist_data", "nr_zones"); - OFFSET_INIT(pglist_data.node_mem_map, "pglist_data", "node_mem_map"); - OFFSET_INIT(pglist_data.node_start_pfn, "pglist_data","node_start_pfn"); - OFFSET_INIT(pglist_data.node_spanned_pages, "pglist_data", - "node_spanned_pages"); - OFFSET_INIT(pglist_data.pgdat_next, "pglist_data", "pgdat_next"); - - /* - * Get offsets of the zone's members. - */ - SIZE_INIT(zone, "zone"); - OFFSET_INIT(zone.free_pages, "zone", "free_pages"); - OFFSET_INIT(zone.free_area, "zone", "free_area"); - OFFSET_INIT(zone.vm_stat, "zone", "vm_stat"); - OFFSET_INIT(zone.spanned_pages, "zone", "spanned_pages"); - MEMBER_ARRAY_LENGTH_INIT(zone.free_area, "zone", "free_area"); - - /* - * Get offsets of the free_area's members. - */ - SIZE_INIT(free_area, "free_area"); - OFFSET_INIT(free_area.free_list, "free_area", "free_list"); - MEMBER_ARRAY_LENGTH_INIT(free_area.free_list, "free_area", "free_list"); - - /* - * Get offsets of the list_head's members. - */ - SIZE_INIT(list_head, "list_head"); - OFFSET_INIT(list_head.next, "list_head", "next"); - OFFSET_INIT(list_head.prev, "list_head", "prev"); - - /* - * Get offsets of the node_memblk_s's members. - */ - SIZE_INIT(node_memblk_s, "node_memblk_s"); - OFFSET_INIT(node_memblk_s.start_paddr, "node_memblk_s", "start_paddr"); - OFFSET_INIT(node_memblk_s.size, "node_memblk_s", "size"); - OFFSET_INIT(node_memblk_s.nid, "node_memblk_s", "nid"); - - OFFSET_INIT(vm_struct.addr, "vm_struct", "addr"); - - /* - * Get offset of the module members. - */ - SIZE_INIT(module, "module"); - OFFSET_INIT(module.strtab, "module", "strtab"); - OFFSET_INIT(module.symtab, "module", "symtab"); - OFFSET_INIT(module.num_symtab, "module", "num_symtab"); - OFFSET_INIT(module.list, "module", "list"); - OFFSET_INIT(module.name, "module", "name"); - OFFSET_INIT(module.module_core, "module", "module_core"); - OFFSET_INIT(module.core_size, "module", "core_size"); - OFFSET_INIT(module.module_init, "module", "module_init"); - OFFSET_INIT(module.init_size, "module", "init_size"); - - ENUM_NUMBER_INIT(NR_FREE_PAGES, "NR_FREE_PAGES"); - ENUM_NUMBER_INIT(N_ONLINE, "N_ONLINE"); - - ENUM_NUMBER_INIT(PG_lru, "PG_lru"); - ENUM_NUMBER_INIT(PG_private, "PG_private"); - ENUM_NUMBER_INIT(PG_swapcache, "PG_swapcache"); - - TYPEDEF_SIZE_INIT(nodemask_t, "nodemask_t"); - - SIZE_INIT(percpu_data, "percpu_data"); - - /* - * Get offset of the elf_prstatus members. - */ - SIZE_INIT(elf_prstatus, "elf_prstatus"); - OFFSET_INIT(elf_prstatus.pr_reg, "elf_prstatus", "pr_reg"); - - /* - * Get size of cpumask and cpumask_t. - */ - SIZE_INIT(cpumask, "cpumask"); - - TYPEDEF_SIZE_INIT(cpumask_t, "cpumask_t"); - - /* - * Get offset of the user_regs_struct members. - */ - SIZE_INIT(user_regs_struct, "user_regs_struct"); - -#ifdef __x86__ - if (SIZE(user_regs_struct) != NOT_FOUND_STRUCTURE) { - OFFSET_INIT(user_regs_struct.bx, "user_regs_struct", "bx"); - OFFSET_INIT(user_regs_struct.cx, "user_regs_struct", "cx"); - OFFSET_INIT(user_regs_struct.dx, "user_regs_struct", "dx"); - OFFSET_INIT(user_regs_struct.si, "user_regs_struct", "si"); - OFFSET_INIT(user_regs_struct.di, "user_regs_struct", "di"); - OFFSET_INIT(user_regs_struct.bp, "user_regs_struct", "bp"); - OFFSET_INIT(user_regs_struct.ax, "user_regs_struct", "ax"); - OFFSET_INIT(user_regs_struct.ds, "user_regs_struct", "ds"); - OFFSET_INIT(user_regs_struct.es, "user_regs_struct", "es"); - OFFSET_INIT(user_regs_struct.fs, "user_regs_struct", "fs"); - OFFSET_INIT(user_regs_struct.gs, "user_regs_struct", "gs"); - OFFSET_INIT(user_regs_struct.orig_ax, "user_regs_struct", - "orig_ax"); - OFFSET_INIT(user_regs_struct.ip, "user_regs_struct", "ip"); - OFFSET_INIT(user_regs_struct.cs, "user_regs_struct", "cs"); - OFFSET_INIT(user_regs_struct.flags, "user_regs_struct", - "flags"); - OFFSET_INIT(user_regs_struct.sp, "user_regs_struct", "sp"); - OFFSET_INIT(user_regs_struct.ss, "user_regs_struct", "ss"); - - if (OFFSET(user_regs_struct.bx) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.bx, "user_regs_struct", "ebx"); - if (OFFSET(user_regs_struct.cx) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.cx, "user_regs_struct", "ecx"); - if (OFFSET(user_regs_struct.dx) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.dx, "user_regs_struct", "edx"); - if (OFFSET(user_regs_struct.si) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.si, "user_regs_struct", "esi"); - if (OFFSET(user_regs_struct.di) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.di, "user_regs_struct", "edi"); - if (OFFSET(user_regs_struct.bp) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.bp, "user_regs_struct", "ebp"); - if (OFFSET(user_regs_struct.ax) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.ax, "user_regs_struct", "eax"); - if (OFFSET(user_regs_struct.orig_ax) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.orig_ax, "user_regs_struct", "orig_eax"); - if (OFFSET(user_regs_struct.ip) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.ip, "user_regs_struct", "eip"); - if (OFFSET(user_regs_struct.flags) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.flags, "user_regs_struct", "eflags"); - if (OFFSET(user_regs_struct.sp) == NOT_FOUND_STRUCTURE) - OFFSET_INIT(user_regs_struct.sp, "user_regs_struct", "esp"); - } else { - /* - * Note: Sometimes kernel debuginfo doesn't contain - * user_regs_struct structure information. Instead, we - * take offsets from actual datatype. - */ - OFFSET(user_regs_struct.bx) = offsetof(struct user_regs_struct, bx); - OFFSET(user_regs_struct.cx) = offsetof(struct user_regs_struct, cx); - OFFSET(user_regs_struct.dx) = offsetof(struct user_regs_struct, dx); - OFFSET(user_regs_struct.si) = offsetof(struct user_regs_struct, si); - OFFSET(user_regs_struct.di) = offsetof(struct user_regs_struct, di); - OFFSET(user_regs_struct.bp) = offsetof(struct user_regs_struct, bp); - OFFSET(user_regs_struct.ax) = offsetof(struct user_regs_struct, ax); - OFFSET(user_regs_struct.ds) = offsetof(struct user_regs_struct, ds); - OFFSET(user_regs_struct.es) = offsetof(struct user_regs_struct, es); - OFFSET(user_regs_struct.fs) = offsetof(struct user_regs_struct, fs); - OFFSET(user_regs_struct.gs) = offsetof(struct user_regs_struct, gs); - OFFSET(user_regs_struct.orig_ax) = offsetof(struct user_regs_struct, orig_ax); - OFFSET(user_regs_struct.ip) = offsetof(struct user_regs_struct, ip); - OFFSET(user_regs_struct.cs) = offsetof(struct user_regs_struct, cs); - OFFSET(user_regs_struct.flags) = offsetof(struct user_regs_struct, flags); - OFFSET(user_regs_struct.sp) = offsetof(struct user_regs_struct, sp); - OFFSET(user_regs_struct.ss) = offsetof(struct user_regs_struct, ss); - } -#endif /* __x86__ */ - -#ifdef __x86_64__ - if (SIZE(user_regs_struct) != NOT_FOUND_STRUCTURE) { - OFFSET_INIT(user_regs_struct.r15, "user_regs_struct", "r15"); - OFFSET_INIT(user_regs_struct.r14, "user_regs_struct", "r14"); - OFFSET_INIT(user_regs_struct.r13, "user_regs_struct", "r13"); - OFFSET_INIT(user_regs_struct.r12, "user_regs_struct", "r12"); - OFFSET_INIT(user_regs_struct.bp, "user_regs_struct", "bp"); - OFFSET_INIT(user_regs_struct.bx, "user_regs_struct", "bx"); - OFFSET_INIT(user_regs_struct.r11, "user_regs_struct", "r11"); - OFFSET_INIT(user_regs_struct.r10, "user_regs_struct", "r10"); - OFFSET_INIT(user_regs_struct.r9, "user_regs_struct", "r9"); - OFFSET_INIT(user_regs_struct.r8, "user_regs_struct", "r8"); - OFFSET_INIT(user_regs_struct.ax, "user_regs_struct", "ax"); - OFFSET_INIT(user_regs_struct.cx, "user_regs_struct", "cx"); - OFFSET_INIT(user_regs_struct.dx, "user_regs_struct", "dx"); - OFFSET_INIT(user_regs_struct.si, "user_regs_struct", "si"); - OFFSET_INIT(user_regs_struct.di, "user_regs_struct", "di"); - OFFSET_INIT(user_regs_struct.orig_ax, "user_regs_struct", - "orig_ax"); - OFFSET_INIT(user_regs_struct.ip, "user_regs_struct", "ip"); - OFFSET_INIT(user_regs_struct.cs, "user_regs_struct", "cs"); - OFFSET_INIT(user_regs_struct.flags, "user_regs_struct", - "flags"); - OFFSET_INIT(user_regs_struct.sp, "user_regs_struct", "sp"); - OFFSET_INIT(user_regs_struct.ss, "user_regs_struct", "ss"); - OFFSET_INIT(user_regs_struct.fs_base, "user_regs_struct", - "fs_base"); - OFFSET_INIT(user_regs_struct.gs_base, "user_regs_struct", - "gs_base"); - OFFSET_INIT(user_regs_struct.ds, "user_regs_struct", "ds"); - OFFSET_INIT(user_regs_struct.es, "user_regs_struct", "es"); - OFFSET_INIT(user_regs_struct.fs, "user_regs_struct", "fs"); - OFFSET_INIT(user_regs_struct.gs, "user_regs_struct", "gs"); - } else { - /* - * Note: Sometimes kernel debuginfo doesn't contain - * user_regs_struct structure information. Instead, we - * take offsets from actual datatype. - */ - OFFSET(user_regs_struct.r15) = offsetof(struct user_regs_struct, r15); - OFFSET(user_regs_struct.r14) = offsetof(struct user_regs_struct, r14); - OFFSET(user_regs_struct.r13) = offsetof(struct user_regs_struct, r13); - OFFSET(user_regs_struct.r12) = offsetof(struct user_regs_struct, r12); - OFFSET(user_regs_struct.bp) = offsetof(struct user_regs_struct, bp); - OFFSET(user_regs_struct.bx) = offsetof(struct user_regs_struct, bx); - OFFSET(user_regs_struct.r11) = offsetof(struct user_regs_struct, r11); - OFFSET(user_regs_struct.r10) = offsetof(struct user_regs_struct, r10); - OFFSET(user_regs_struct.r9) = offsetof(struct user_regs_struct, r9); - OFFSET(user_regs_struct.r8) = offsetof(struct user_regs_struct, r8); - OFFSET(user_regs_struct.ax) = offsetof(struct user_regs_struct, ax); - OFFSET(user_regs_struct.cx) = offsetof(struct user_regs_struct, cx); - OFFSET(user_regs_struct.dx) = offsetof(struct user_regs_struct, dx); - OFFSET(user_regs_struct.si) = offsetof(struct user_regs_struct, si); - OFFSET(user_regs_struct.di) = offsetof(struct user_regs_struct, di); - OFFSET(user_regs_struct.orig_ax) = offsetof(struct user_regs_struct, orig_ax); - OFFSET(user_regs_struct.ip) = offsetof(struct user_regs_struct, ip); - OFFSET(user_regs_struct.cs) = offsetof(struct user_regs_struct, cs); - OFFSET(user_regs_struct.flags) = offsetof(struct user_regs_struct, flags); - OFFSET(user_regs_struct.sp) = offsetof(struct user_regs_struct, sp); - OFFSET(user_regs_struct.ss) = offsetof(struct user_regs_struct, ss); - OFFSET(user_regs_struct.fs_base) = offsetof(struct user_regs_struct, fs_base); - OFFSET(user_regs_struct.gs_base) = offsetof(struct user_regs_struct, gs_base); - OFFSET(user_regs_struct.ds) = offsetof(struct user_regs_struct, ds); - OFFSET(user_regs_struct.es) = offsetof(struct user_regs_struct, es); - OFFSET(user_regs_struct.fs) = offsetof(struct user_regs_struct, fs); - OFFSET(user_regs_struct.gs) = offsetof(struct user_regs_struct, gs); - } -#endif /* __x86_64__ */ - - OFFSET_INIT(kimage.segment, "kimage", "segment"); - - MEMBER_ARRAY_LENGTH_INIT(kimage.segment, "kimage", "segment"); - - SIZE_INIT(kexec_segment, "kexec_segment"); - OFFSET_INIT(kexec_segment.mem, "kexec_segment", "mem"); - - OFFSET_INIT(elf64_hdr.e_phnum, "elf64_hdr", "e_phnum"); - OFFSET_INIT(elf64_hdr.e_phentsize, "elf64_hdr", "e_phentsize"); - OFFSET_INIT(elf64_hdr.e_phoff, "elf64_hdr", "e_phoff"); - - SIZE_INIT(elf64_hdr, "elf64_hdr"); - OFFSET_INIT(elf64_phdr.p_type, "elf64_phdr", "p_type"); - OFFSET_INIT(elf64_phdr.p_offset, "elf64_phdr", "p_offset"); - OFFSET_INIT(elf64_phdr.p_paddr, "elf64_phdr", "p_paddr"); - OFFSET_INIT(elf64_phdr.p_memsz, "elf64_phdr", "p_memsz"); - - return TRUE; -} - -int -get_srcfile_info(void) -{ - TYPEDEF_SRCFILE_INIT(pud_t, "pud_t"); - - return TRUE; -} - -int -get_value_for_old_linux(void) -{ - if (NUMBER(PG_lru) == NOT_FOUND_NUMBER) - NUMBER(PG_lru) = PG_lru_ORIGINAL; - if (NUMBER(PG_private) == NOT_FOUND_NUMBER) - NUMBER(PG_private) = PG_private_ORIGINAL; - if (NUMBER(PG_swapcache) == NOT_FOUND_NUMBER) - NUMBER(PG_swapcache) = PG_swapcache_ORIGINAL; - return TRUE; -} - -int -get_str_osrelease_from_vmlinux(void) -{ - struct utsname system_utsname; - unsigned long long utsname; - off_t offset; - const off_t failed = (off_t)-1; - - /* - * Get the kernel version. - */ - if (SYMBOL(system_utsname) != NOT_FOUND_SYMBOL) { - utsname = SYMBOL(system_utsname); - } else if (SYMBOL(init_uts_ns) != NOT_FOUND_SYMBOL) { - utsname = SYMBOL(init_uts_ns) + sizeof(int); - } else { - ERRMSG("Can't get the symbol of system_utsname.\n"); - return FALSE; - } - offset = vaddr_to_offset_slow(dwarf_info.fd_debuginfo, - dwarf_info.name_debuginfo, utsname); - - if (!offset) { - ERRMSG("Can't convert vaddr (%llx) of utsname to an offset.\n", - utsname); - return FALSE; - } - if (lseek(dwarf_info.fd_debuginfo, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek %s. %s\n", dwarf_info.name_debuginfo, - strerror(errno)); - return FALSE; - } - if (read(dwarf_info.fd_debuginfo, &system_utsname, sizeof system_utsname) - != sizeof system_utsname) { - ERRMSG("Can't read %s. %s\n", dwarf_info.name_debuginfo, - strerror(errno)); - return FALSE; - } - if (!strncpy(info->release, system_utsname.release, STRLEN_OSRELEASE)){ - ERRMSG("Can't do strncpy for osrelease."); - return FALSE; - } - return TRUE; -} - -int -is_sparsemem_extreme(void) -{ - if (ARRAY_LENGTH(mem_section) - == (NR_MEM_SECTIONS() / _SECTIONS_PER_ROOT_EXTREME())) - return TRUE; - else - return FALSE; -} - -int -get_mem_type(void) -{ - int ret; - - if ((SIZE(page) == NOT_FOUND_STRUCTURE) - || (OFFSET(page.flags) == NOT_FOUND_STRUCTURE) - || (OFFSET(page._count) == NOT_FOUND_STRUCTURE) - || (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE)) { - ret = NOT_FOUND_MEMTYPE; - } else if ((((SYMBOL(node_data) != NOT_FOUND_SYMBOL) - && (ARRAY_LENGTH(node_data) != NOT_FOUND_STRUCTURE)) - || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) - && (OFFSET(pglist_data.pgdat_next) != NOT_FOUND_STRUCTURE)) - || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) - && (ARRAY_LENGTH(pgdat_list) != NOT_FOUND_STRUCTURE))) - && (SIZE(pglist_data) != NOT_FOUND_STRUCTURE) - && (OFFSET(pglist_data.node_mem_map) != NOT_FOUND_STRUCTURE) - && (OFFSET(pglist_data.node_start_pfn) != NOT_FOUND_STRUCTURE) - && (OFFSET(pglist_data.node_spanned_pages) !=NOT_FOUND_STRUCTURE)){ - ret = DISCONTIGMEM; - } else if ((SYMBOL(mem_section) != NOT_FOUND_SYMBOL) - && (SIZE(mem_section) != NOT_FOUND_STRUCTURE) - && (OFFSET(mem_section.section_mem_map) != NOT_FOUND_STRUCTURE) - && (ARRAY_LENGTH(mem_section) != NOT_FOUND_STRUCTURE)) { - if (is_sparsemem_extreme()) - ret = SPARSEMEM_EX; - else - ret = SPARSEMEM; - } else if (SYMBOL(mem_map) != NOT_FOUND_SYMBOL) { - ret = FLATMEM; - } else { - ret = NOT_FOUND_MEMTYPE; - } - - return ret; -} - -/* - * Set the dwarf_info with kernel/module debuginfo file information. - */ -int -set_dwarf_debuginfo(char *mod_name, char *name_debuginfo, int fd_debuginfo) -{ - if (!mod_name) - return FALSE; - if (dwarf_info.module_name && !strcmp(dwarf_info.module_name, mod_name)) - return TRUE; - - /* Switching to different module. - * - * Close the file descriptor if previous module is != kernel and - * xen-syms. The reason is, vmlinux file will always be supplied - * by user and code to open/close kernel debuginfo file already - * in place. The module debuginfo files are opened only if '--config' - * option is used. This helps not to break the existing functionlity - * if called without '--config' option. - */ - - if (dwarf_info.module_name - && strcmp(dwarf_info.module_name, "vmlinux") - && strcmp(dwarf_info.module_name, "xen-syms")) { - if (dwarf_info.fd_debuginfo > 0) - close(dwarf_info.fd_debuginfo); - if (dwarf_info.name_debuginfo) - free(dwarf_info.name_debuginfo); - } - if (dwarf_info.module_name) - free(dwarf_info.module_name); - - dwarf_info.fd_debuginfo = fd_debuginfo; - dwarf_info.name_debuginfo = name_debuginfo; - dwarf_info.module_name = strdup(mod_name); - - if (!strcmp(dwarf_info.module_name, "vmlinux") || - !strcmp(dwarf_info.module_name, "xen-syms")) - return TRUE; - - /* check to see whether module debuginfo is available */ - return search_module_debuginfo(); -} - -void -write_vmcoreinfo_data(void) -{ - /* - * write 1st kernel's OSRELEASE - */ - fprintf(info->file_vmcoreinfo, "%s%s\n", STR_OSRELEASE, - info->release); - - /* - * write 1st kernel's PAGESIZE - */ - fprintf(info->file_vmcoreinfo, "%s%ld\n", STR_PAGESIZE, - info->page_size); - - /* - * write the symbol of 1st kernel - */ - WRITE_SYMBOL("mem_map", mem_map); - WRITE_SYMBOL("vmem_map", vmem_map); - WRITE_SYMBOL("mem_section", mem_section); - WRITE_SYMBOL("pkmap_count", pkmap_count); - WRITE_SYMBOL("pkmap_count_next", pkmap_count_next); - WRITE_SYMBOL("system_utsname", system_utsname); - WRITE_SYMBOL("init_uts_ns", init_uts_ns); - WRITE_SYMBOL("_stext", _stext); - WRITE_SYMBOL("swapper_pg_dir", swapper_pg_dir); - WRITE_SYMBOL("init_level4_pgt", init_level4_pgt); - WRITE_SYMBOL("vmlist", vmlist); - WRITE_SYMBOL("phys_base", phys_base); - WRITE_SYMBOL("node_online_map", node_online_map); - WRITE_SYMBOL("node_states", node_states); - WRITE_SYMBOL("node_data", node_data); - WRITE_SYMBOL("pgdat_list", pgdat_list); - WRITE_SYMBOL("contig_page_data", contig_page_data); - WRITE_SYMBOL("log_buf", log_buf); - WRITE_SYMBOL("log_buf_len", log_buf_len); - WRITE_SYMBOL("log_end", log_end); - WRITE_SYMBOL("max_pfn", max_pfn); - WRITE_SYMBOL("high_memory", high_memory); - - /* - * write the structure size of 1st kernel - */ - WRITE_STRUCTURE_SIZE("page", page); - WRITE_STRUCTURE_SIZE("mem_section", mem_section); - WRITE_STRUCTURE_SIZE("pglist_data", pglist_data); - WRITE_STRUCTURE_SIZE("zone", zone); - WRITE_STRUCTURE_SIZE("free_area", free_area); - WRITE_STRUCTURE_SIZE("list_head", list_head); - WRITE_STRUCTURE_SIZE("node_memblk_s", node_memblk_s); - WRITE_STRUCTURE_SIZE("nodemask_t", nodemask_t); - - /* - * write the member offset of 1st kernel - */ - WRITE_MEMBER_OFFSET("page.flags", page.flags); - WRITE_MEMBER_OFFSET("page._count", page._count); - WRITE_MEMBER_OFFSET("page.mapping", page.mapping); - WRITE_MEMBER_OFFSET("page.lru", page.lru); - WRITE_MEMBER_OFFSET("mem_section.section_mem_map", - mem_section.section_mem_map); - WRITE_MEMBER_OFFSET("pglist_data.node_zones", pglist_data.node_zones); - WRITE_MEMBER_OFFSET("pglist_data.nr_zones", pglist_data.nr_zones); - WRITE_MEMBER_OFFSET("pglist_data.node_mem_map", - pglist_data.node_mem_map); - WRITE_MEMBER_OFFSET("pglist_data.node_start_pfn", - pglist_data.node_start_pfn); - WRITE_MEMBER_OFFSET("pglist_data.node_spanned_pages", - pglist_data.node_spanned_pages); - WRITE_MEMBER_OFFSET("pglist_data.pgdat_next", pglist_data.pgdat_next); - WRITE_MEMBER_OFFSET("zone.free_pages", zone.free_pages); - WRITE_MEMBER_OFFSET("zone.free_area", zone.free_area); - WRITE_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat); - WRITE_MEMBER_OFFSET("zone.spanned_pages", zone.spanned_pages); - WRITE_MEMBER_OFFSET("free_area.free_list", free_area.free_list); - WRITE_MEMBER_OFFSET("list_head.next", list_head.next); - WRITE_MEMBER_OFFSET("list_head.prev", list_head.prev); - WRITE_MEMBER_OFFSET("node_memblk_s.start_paddr", node_memblk_s.start_paddr); - WRITE_MEMBER_OFFSET("node_memblk_s.size", node_memblk_s.size); - WRITE_MEMBER_OFFSET("node_memblk_s.nid", node_memblk_s.nid); - WRITE_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr); - - if (SYMBOL(node_data) != NOT_FOUND_SYMBOL) - WRITE_ARRAY_LENGTH("node_data", node_data); - if (SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL) - WRITE_ARRAY_LENGTH("pgdat_list", pgdat_list); - if (SYMBOL(mem_section) != NOT_FOUND_SYMBOL) - WRITE_ARRAY_LENGTH("mem_section", mem_section); - if (SYMBOL(node_memblk) != NOT_FOUND_SYMBOL) - WRITE_ARRAY_LENGTH("node_memblk", node_memblk); - - WRITE_ARRAY_LENGTH("zone.free_area", zone.free_area); - WRITE_ARRAY_LENGTH("free_area.free_list", free_area.free_list); - - WRITE_NUMBER("NR_FREE_PAGES", NR_FREE_PAGES); - WRITE_NUMBER("N_ONLINE", N_ONLINE); - - WRITE_NUMBER("PG_lru", PG_lru); - WRITE_NUMBER("PG_private", PG_private); - WRITE_NUMBER("PG_swapcache", PG_swapcache); - - /* - * write the source file of 1st kernel - */ - WRITE_SRCFILE("pud_t", pud_t); -} - -int -generate_vmcoreinfo(void) -{ - if (!set_page_size(sysconf(_SC_PAGE_SIZE))) - return FALSE; - - set_dwarf_debuginfo("vmlinux", info->name_vmlinux, info->fd_vmlinux); - - if (!get_symbol_info()) - return FALSE; - - if (!get_structure_info()) - return FALSE; - - if (!get_srcfile_info()) - return FALSE; - - if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL) - && (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) { - ERRMSG("Can't get the symbol of system_utsname.\n"); - return FALSE; - } - if (!get_str_osrelease_from_vmlinux()) - return FALSE; - - if (!(info->kernel_version = get_kernel_version(info->release))) - return FALSE; - - if (get_mem_type() == NOT_FOUND_MEMTYPE) { - ERRMSG("Can't find the memory type.\n"); - return FALSE; - } - - write_vmcoreinfo_data(); - - return TRUE; -} - -int -read_vmcoreinfo_basic_info(void) -{ - time_t tv_sec = 0; - long page_size = FALSE; - char buf[BUFSIZE_FGETS], *endp; - unsigned int get_release = FALSE, i; - - if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { - ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return FALSE; - } - - while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { - i = strlen(buf); - if (!i) - break; - if (buf[i - 1] == '\n') - buf[i - 1] = '\0'; - if (strncmp(buf, STR_OSRELEASE, strlen(STR_OSRELEASE)) == 0) { - get_release = TRUE; - /* if the release have been stored, skip this time. */ - if (strlen(info->release)) - continue; - strcpy(info->release, buf + strlen(STR_OSRELEASE)); - } - if (strncmp(buf, STR_PAGESIZE, strlen(STR_PAGESIZE)) == 0) { - page_size = strtol(buf+strlen(STR_PAGESIZE),&endp,10); - if ((!page_size || page_size == LONG_MAX) - || strlen(endp) != 0) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return FALSE; - } - if (!set_page_size(page_size)) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return FALSE; - } - } - if (strncmp(buf, STR_CRASHTIME, strlen(STR_CRASHTIME)) == 0) { - tv_sec = strtol(buf+strlen(STR_CRASHTIME),&endp,10); - if ((!tv_sec || tv_sec == LONG_MAX) - || strlen(endp) != 0) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return FALSE; - } - info->timestamp.tv_sec = tv_sec; - } - if (strncmp(buf, STR_CONFIG_X86_PAE, - strlen(STR_CONFIG_X86_PAE)) == 0) - vt.mem_flags |= MEMORY_X86_PAE; - - if (strncmp(buf, STR_CONFIG_PGTABLE_3, - strlen(STR_CONFIG_PGTABLE_3)) == 0) - vt.mem_flags |= MEMORY_PAGETABLE_3L; - - if (strncmp(buf, STR_CONFIG_PGTABLE_4, - strlen(STR_CONFIG_PGTABLE_4)) == 0) - vt.mem_flags |= MEMORY_PAGETABLE_4L; - } - if (!get_release || !info->page_size) { - ERRMSG("Invalid format in %s", info->name_vmcoreinfo); - return FALSE; - } - return TRUE; -} - -unsigned long -read_vmcoreinfo_symbol(char *str_symbol) -{ - unsigned long symbol = NOT_FOUND_SYMBOL; - char buf[BUFSIZE_FGETS], *endp; - unsigned int i; - - if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { - ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return INVALID_SYMBOL_DATA; - } - - while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { - i = strlen(buf); - if (!i) - break; - if (buf[i - 1] == '\n') - buf[i - 1] = '\0'; - if (strncmp(buf, str_symbol, strlen(str_symbol)) == 0) { - symbol = strtoul(buf + strlen(str_symbol), &endp, 16); - if ((!symbol || symbol == ULONG_MAX) - || strlen(endp) != 0) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return INVALID_SYMBOL_DATA; - } - break; - } - } - return symbol; -} - -long -read_vmcoreinfo_long(char *str_structure) -{ - long data = NOT_FOUND_LONG_VALUE; - char buf[BUFSIZE_FGETS], *endp; - unsigned int i; - - if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { - ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return INVALID_STRUCTURE_DATA; - } - - while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { - i = strlen(buf); - if (!i) - break; - if (buf[i - 1] == '\n') - buf[i - 1] = '\0'; - if (strncmp(buf, str_structure, strlen(str_structure)) == 0) { - data = strtol(buf + strlen(str_structure), &endp, 10); - if ((data == LONG_MAX) || strlen(endp) != 0) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return INVALID_STRUCTURE_DATA; - } - break; - } - } - return data; -} - -int -read_vmcoreinfo_string(char *str_in, char *str_out) -{ - char buf[BUFSIZE_FGETS]; - unsigned int i; - - if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { - ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return FALSE; - } - - while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { - i = strlen(buf); - if (!i) - break; - if (buf[i - 1] == '\n') - buf[i - 1] = '\0'; - if (strncmp(buf, str_in, strlen(str_in)) == 0) { - strncpy(str_out, buf + strlen(str_in), LEN_SRCFILE - strlen(str_in)); - break; - } - } - return TRUE; -} - -int -read_vmcoreinfo(void) -{ - if (!read_vmcoreinfo_basic_info()) - return FALSE; - - READ_SYMBOL("mem_map", mem_map); - READ_SYMBOL("vmem_map", vmem_map); - READ_SYMBOL("mem_section", mem_section); - READ_SYMBOL("pkmap_count", pkmap_count); - READ_SYMBOL("pkmap_count_next", pkmap_count_next); - READ_SYMBOL("system_utsname", system_utsname); - READ_SYMBOL("init_uts_ns", init_uts_ns); - READ_SYMBOL("_stext", _stext); - READ_SYMBOL("swapper_pg_dir", swapper_pg_dir); - READ_SYMBOL("init_level4_pgt", init_level4_pgt); - READ_SYMBOL("vmlist", vmlist); - READ_SYMBOL("phys_base", phys_base); - READ_SYMBOL("node_online_map", node_online_map); - READ_SYMBOL("node_states", node_states); - READ_SYMBOL("node_data", node_data); - READ_SYMBOL("pgdat_list", pgdat_list); - READ_SYMBOL("contig_page_data", contig_page_data); - READ_SYMBOL("log_buf", log_buf); - READ_SYMBOL("log_buf_len", log_buf_len); - READ_SYMBOL("log_end", log_end); - READ_SYMBOL("max_pfn", max_pfn); - READ_SYMBOL("high_memory", high_memory); - - READ_STRUCTURE_SIZE("page", page); - READ_STRUCTURE_SIZE("mem_section", mem_section); - READ_STRUCTURE_SIZE("pglist_data", pglist_data); - READ_STRUCTURE_SIZE("zone", zone); - READ_STRUCTURE_SIZE("free_area", free_area); - READ_STRUCTURE_SIZE("list_head", list_head); - READ_STRUCTURE_SIZE("node_memblk_s", node_memblk_s); - READ_STRUCTURE_SIZE("nodemask_t", nodemask_t); - - READ_MEMBER_OFFSET("page.flags", page.flags); - READ_MEMBER_OFFSET("page._count", page._count); - READ_MEMBER_OFFSET("page.mapping", page.mapping); - READ_MEMBER_OFFSET("page.lru", page.lru); - READ_MEMBER_OFFSET("mem_section.section_mem_map", - mem_section.section_mem_map); - READ_MEMBER_OFFSET("pglist_data.node_zones", pglist_data.node_zones); - READ_MEMBER_OFFSET("pglist_data.nr_zones", pglist_data.nr_zones); - READ_MEMBER_OFFSET("pglist_data.node_mem_map",pglist_data.node_mem_map); - READ_MEMBER_OFFSET("pglist_data.node_start_pfn", - pglist_data.node_start_pfn); - READ_MEMBER_OFFSET("pglist_data.node_spanned_pages", - pglist_data.node_spanned_pages); - READ_MEMBER_OFFSET("pglist_data.pgdat_next", pglist_data.pgdat_next); - READ_MEMBER_OFFSET("zone.free_pages", zone.free_pages); - READ_MEMBER_OFFSET("zone.free_area", zone.free_area); - READ_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat); - READ_MEMBER_OFFSET("zone.spanned_pages", zone.spanned_pages); - READ_MEMBER_OFFSET("free_area.free_list", free_area.free_list); - READ_MEMBER_OFFSET("list_head.next", list_head.next); - READ_MEMBER_OFFSET("list_head.prev", list_head.prev); - READ_MEMBER_OFFSET("node_memblk_s.start_paddr", node_memblk_s.start_paddr); - READ_MEMBER_OFFSET("node_memblk_s.size", node_memblk_s.size); - READ_MEMBER_OFFSET("node_memblk_s.nid", node_memblk_s.nid); - READ_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr); - - READ_ARRAY_LENGTH("node_data", node_data); - READ_ARRAY_LENGTH("pgdat_list", pgdat_list); - READ_ARRAY_LENGTH("mem_section", mem_section); - READ_ARRAY_LENGTH("node_memblk", node_memblk); - READ_ARRAY_LENGTH("zone.free_area", zone.free_area); - READ_ARRAY_LENGTH("free_area.free_list", free_area.free_list); - - READ_NUMBER("NR_FREE_PAGES", NR_FREE_PAGES); - READ_NUMBER("N_ONLINE", N_ONLINE); - - READ_NUMBER("PG_lru", PG_lru); - READ_NUMBER("PG_private", PG_private); - READ_NUMBER("PG_swapcache", PG_swapcache); - - READ_SRCFILE("pud_t", pud_t); - - return TRUE; -} - -#define MAX_SIZE_NHDR MAX(sizeof(Elf64_Nhdr), sizeof(Elf32_Nhdr)) - -off_t -offset_next_note(void *note) -{ - off_t offset; - Elf64_Nhdr *note64; - Elf32_Nhdr *note32; - - /* - * Both name and desc in ELF Note elements are padded to - * 4 byte boundary. - */ - if (info->flag_elf64_memory) { - note64 = (Elf64_Nhdr *)note; - offset = sizeof(Elf64_Nhdr) - + roundup(note64->n_namesz, 4) - + roundup(note64->n_descsz, 4); - } else { - note32 = (Elf32_Nhdr *)note; - offset = sizeof(Elf32_Nhdr) - + roundup(note32->n_namesz, 4) - + roundup(note32->n_descsz, 4); - } - return offset; -} - -int -note_type(void *note) -{ - int type; - Elf64_Nhdr *note64; - Elf32_Nhdr *note32; - - if (info->flag_elf64_memory) { - note64 = (Elf64_Nhdr *)note; - type = note64->n_type; - } else { - note32 = (Elf32_Nhdr *)note; - type = note32->n_type; - } - return type; -} - -int -note_descsz(void *note) -{ - int size; - Elf64_Nhdr *note64; - Elf32_Nhdr *note32; - - if (info->flag_elf64_memory) { - note64 = (Elf64_Nhdr *)note; - size = note64->n_descsz; - } else { - note32 = (Elf32_Nhdr *)note; - size = note32->n_descsz; - } - return size; -} - -off_t -offset_note_desc(void *note) -{ - off_t offset; - Elf64_Nhdr *note64; - Elf32_Nhdr *note32; - - if (info->flag_elf64_memory) { - note64 = (Elf64_Nhdr *)note; - offset = sizeof(Elf64_Nhdr) + roundup(note64->n_namesz, 4); - } else { - note32 = (Elf32_Nhdr *)note; - offset = sizeof(Elf32_Nhdr) + roundup(note32->n_namesz, 4); - } - return offset; -} - -int -get_pt_note_info(off_t off_note, unsigned long sz_note) -{ - int n_type, size_desc; - unsigned long p2m_mfn; - off_t offset, offset_desc, off_p2m = 0; - char buf[VMCOREINFO_XEN_NOTE_NAME_BYTES]; - char note[MAX_SIZE_NHDR]; - const off_t failed = (off_t)-1; - - offset = off_note; - while (offset < off_note + sz_note) { - if (lseek(info->fd_memory, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (read(info->fd_memory, note, sizeof(note)) != sizeof(note)) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (read(info->fd_memory, &buf, sizeof(buf)) != sizeof(buf)) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - n_type = note_type(note); - - if (n_type == NT_PRSTATUS) { - info->nr_cpus++; - offset += offset_next_note(note); - continue; - } - offset_desc = offset + offset_note_desc(note); - size_desc = note_descsz(note); - - /* - * Check whether /proc/vmcore contains vmcoreinfo, - * and get both the offset and the size. - * - * NOTE: The owner name of xen should be checked at first, - * because its name is "VMCOREINFO_XEN" and the one - * of linux is "VMCOREINFO". - */ - if (!strncmp(VMCOREINFO_XEN_NOTE_NAME, buf, - VMCOREINFO_XEN_NOTE_NAME_BYTES)) { - info->offset_vmcoreinfo_xen = offset_desc; - info->size_vmcoreinfo_xen = size_desc; - } else if (!strncmp(VMCOREINFO_NOTE_NAME, buf, - VMCOREINFO_NOTE_NAME_BYTES)) { - info->offset_vmcoreinfo = offset_desc; - info->size_vmcoreinfo = size_desc; - - /* - * Check whether /proc/vmcore contains xen's note. - */ - } else if (n_type == XEN_ELFNOTE_CRASH_INFO) { - vt.mem_flags |= MEMORY_XEN; - info->offset_xen_crash_info = offset_desc; - info->size_xen_crash_info = size_desc; - - off_p2m = offset + offset_next_note(note) - - sizeof(p2m_mfn); - if (lseek(info->fd_memory, off_p2m, SEEK_SET) - == failed){ - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (read(info->fd_memory, &p2m_mfn, sizeof(p2m_mfn)) - != sizeof(p2m_mfn)) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - info->p2m_mfn = p2m_mfn; - - /* - * Check whether a source dumpfile contains eraseinfo. - * /proc/vmcore does not contain eraseinfo, because eraseinfo - * is added only by makedumpfile and makedumpfile does not - * create /proc/vmcore. - */ - } else if (!strncmp(ERASEINFO_NOTE_NAME, buf, - ERASEINFO_NOTE_NAME_BYTES)) { - info->offset_eraseinfo = offset_desc; - info->size_eraseinfo = size_desc; - } - offset += offset_next_note(note); - } - if (vt.mem_flags & MEMORY_XEN) - DEBUG_MSG("Xen kdump\n"); - else - DEBUG_MSG("Linux kdump\n"); - - return TRUE; -} - -/* - * Extract vmcoreinfo from /proc/vmcore and output it to /tmp/vmcoreinfo.tmp. - */ -int -copy_vmcoreinfo(off_t offset, unsigned long size) -{ - int fd; - char buf[VMCOREINFO_BYTES]; - const off_t failed = (off_t)-1; - - if (!offset || !size) - return FALSE; - - if ((fd = mkstemp(info->name_vmcoreinfo)) < 0) { - ERRMSG("Can't open the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return FALSE; - } - if (lseek(info->fd_memory, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (read(info->fd_memory, &buf, size) != size) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } - if (write(fd, &buf, size) != size) { - ERRMSG("Can't write the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return FALSE; - } - if (close(fd) < 0) { - ERRMSG("Can't close the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); - return FALSE; - } - return TRUE; -} - -int -read_vmcoreinfo_from_vmcore(off_t offset, unsigned long size, int flag_xen_hv) -{ - int ret = FALSE; - - /* - * Copy vmcoreinfo to /tmp/vmcoreinfoXXXXXX. - */ - if (!(info->name_vmcoreinfo = strdup(FILENAME_VMCOREINFO))) { - MSG("Can't duplicate strings(%s).\n", FILENAME_VMCOREINFO); - return FALSE; - } - if (!copy_vmcoreinfo(offset, size)) - goto out; - - /* - * Read vmcoreinfo from /tmp/vmcoreinfoXXXXXX. - */ - if (!open_vmcoreinfo("r")) - goto out; - - unlink(info->name_vmcoreinfo); - - if (flag_xen_hv) { - if (!read_vmcoreinfo_xen()) - goto out; - } else { - if (!read_vmcoreinfo()) - goto out; - } - close_vmcoreinfo(); - - ret = TRUE; -out: - free(info->name_vmcoreinfo); - info->name_vmcoreinfo = NULL; - - return ret; -} - -/* - * Get the number of online nodes. - */ -int -get_nodes_online(void) -{ - int len, i, j, online; - unsigned long node_online_map = 0, bitbuf, *maskptr; - - if ((SYMBOL(node_online_map) == NOT_FOUND_SYMBOL) - && (SYMBOL(node_states) == NOT_FOUND_SYMBOL)) - return 0; - - if (SIZE(nodemask_t) == NOT_FOUND_STRUCTURE) { - ERRMSG("Can't get the size of nodemask_t.\n"); - return 0; - } - - len = SIZE(nodemask_t); - vt.node_online_map_len = len/sizeof(unsigned long); - if (!(vt.node_online_map = (unsigned long *)malloc(len))) { - ERRMSG("Can't allocate memory for the node online map. %s\n", - strerror(errno)); - return 0; - } - if (SYMBOL(node_online_map) != NOT_FOUND_SYMBOL) { - node_online_map = SYMBOL(node_online_map); - } else if (SYMBOL(node_states) != NOT_FOUND_SYMBOL) { - /* - * For linux-2.6.23-rc4-mm1 - */ - node_online_map = SYMBOL(node_states) - + (SIZE(nodemask_t) * NUMBER(N_ONLINE)); - } - if (!readmem(VADDR, node_online_map, vt.node_online_map, len)){ - ERRMSG("Can't get the node online map.\n"); - return 0; - } - online = 0; - maskptr = (unsigned long *)vt.node_online_map; - for (i = 0; i < vt.node_online_map_len; i++, maskptr++) { - bitbuf = *maskptr; - for (j = 0; j < sizeof(bitbuf) * 8; j++) { - online += bitbuf & 1; - bitbuf = bitbuf >> 1; - } - } - return online; -} - -int -get_numnodes(void) -{ - if (!(vt.numnodes = get_nodes_online())) { - vt.numnodes = 1; - } - DEBUG_MSG("\n"); - DEBUG_MSG("num of NODEs : %d\n", vt.numnodes); - DEBUG_MSG("\n"); - - return TRUE; -} - -int -next_online_node(int first) -{ - int i, j, node; - unsigned long mask, *maskptr; - - /* It cannot occur */ - if ((first/(sizeof(unsigned long) * 8)) >= vt.node_online_map_len) { - ERRMSG("next_online_node: %d is too large!\n", first); - return -1; - } - - maskptr = (unsigned long *)vt.node_online_map; - for (i = node = 0; i < vt.node_online_map_len; i++, maskptr++) { - mask = *maskptr; - for (j = 0; j < (sizeof(unsigned long) * 8); j++, node++) { - if (mask & 1) { - if (node >= first) - return node; - } - mask >>= 1; - } - } - return -1; -} - -unsigned long -next_online_pgdat(int node) -{ - int i; - unsigned long pgdat; - - /* - * Get the pglist_data structure from symbol "node_data". - * The array number of symbol "node_data" cannot be gotten - * from vmlinux. Instead, check it is DW_TAG_array_type. - */ - if ((SYMBOL(node_data) == NOT_FOUND_SYMBOL) - || (ARRAY_LENGTH(node_data) == NOT_FOUND_STRUCTURE)) - goto pgdat2; - - if (!readmem(VADDR, SYMBOL(node_data) + (node * sizeof(void *)), - &pgdat, sizeof pgdat)) - goto pgdat2; - - if (!is_kvaddr(pgdat)) - goto pgdat2; - - return pgdat; - -pgdat2: - /* - * Get the pglist_data structure from symbol "pgdat_list". - */ - if (SYMBOL(pgdat_list) == NOT_FOUND_SYMBOL) - goto pgdat3; - - else if ((0 < node) - && (ARRAY_LENGTH(pgdat_list) == NOT_FOUND_STRUCTURE)) - goto pgdat3; - - else if ((ARRAY_LENGTH(pgdat_list) != NOT_FOUND_STRUCTURE) - && (ARRAY_LENGTH(pgdat_list) < node)) - goto pgdat3; - - if (!readmem(VADDR, SYMBOL(pgdat_list) + (node * sizeof(void *)), - &pgdat, sizeof pgdat)) - goto pgdat3; - - if (!is_kvaddr(pgdat)) - goto pgdat3; - - return pgdat; - -pgdat3: - /* - * linux-2.6.16 or former - */ - if ((SYMBOL(pgdat_list) == NOT_FOUND_SYMBOL) - || (OFFSET(pglist_data.pgdat_next) == NOT_FOUND_STRUCTURE)) - goto pgdat4; - - if (!readmem(VADDR, SYMBOL(pgdat_list), &pgdat, sizeof pgdat)) - goto pgdat4; - - if (!is_kvaddr(pgdat)) - goto pgdat4; - - if (node == 0) - return pgdat; - - for (i = 1; i <= node; i++) { - if (!readmem(VADDR, pgdat+OFFSET(pglist_data.pgdat_next), - &pgdat, sizeof pgdat)) - goto pgdat4; - - if (!is_kvaddr(pgdat)) - goto pgdat4; - } - return pgdat; - -pgdat4: - /* - * Get the pglist_data structure from symbol "contig_page_data". - */ - if (SYMBOL(contig_page_data) == NOT_FOUND_SYMBOL) - return FALSE; - - if (node != 0) - return FALSE; - - return SYMBOL(contig_page_data); -} - -void -dump_mem_map(unsigned long long pfn_start, - unsigned long long pfn_end, unsigned long mem_map, int num_mm) -{ - struct mem_map_data *mmd; - - mmd = &info->mem_map_data[num_mm]; - mmd->pfn_start = pfn_start; - mmd->pfn_end = pfn_end; - mmd->mem_map = mem_map; - - DEBUG_MSG("mem_map (%d)\n", num_mm); - DEBUG_MSG(" mem_map : %lx\n", mem_map); - DEBUG_MSG(" pfn_start : %llx\n", pfn_start); - DEBUG_MSG(" pfn_end : %llx\n", pfn_end); - - return; -} - -int -get_mm_flatmem(void) -{ - unsigned long mem_map; - - /* - * Get the address of the symbol "mem_map". - */ - if (!readmem(VADDR, SYMBOL(mem_map), &mem_map, sizeof mem_map) - || !mem_map) { - ERRMSG("Can't get the address of mem_map.\n"); - return FALSE; - } - info->num_mem_map = 1; - if ((info->mem_map_data = (struct mem_map_data *) - malloc(sizeof(struct mem_map_data)*info->num_mem_map)) == NULL) { - ERRMSG("Can't allocate memory for the mem_map_data. %s\n", - strerror(errno)); - return FALSE; - } - if (vt.mem_flags & MEMORY_XEN) - dump_mem_map(0, info->dom0_mapnr, mem_map, 0); - else - dump_mem_map(0, info->max_mapnr, mem_map, 0); - - return TRUE; -} - -int -get_node_memblk(int num_memblk, - unsigned long *start_paddr, unsigned long *size, int *nid) -{ - unsigned long node_memblk; - - if (ARRAY_LENGTH(node_memblk) <= num_memblk) { - ERRMSG("Invalid num_memblk.\n"); - return FALSE; - } - node_memblk = SYMBOL(node_memblk) + SIZE(node_memblk_s) * num_memblk; - if (!readmem(VADDR, node_memblk+OFFSET(node_memblk_s.start_paddr), - start_paddr, sizeof(unsigned long))) { - ERRMSG("Can't get node_memblk_s.start_paddr.\n"); - return FALSE; - } - if (!readmem(VADDR, node_memblk + OFFSET(node_memblk_s.size), - size, sizeof(unsigned long))) { - ERRMSG("Can't get node_memblk_s.size.\n"); - return FALSE; - } - if (!readmem(VADDR, node_memblk + OFFSET(node_memblk_s.nid), - nid, sizeof(int))) { - ERRMSG("Can't get node_memblk_s.nid.\n"); - return FALSE; - } - return TRUE; -} - -int -get_num_mm_discontigmem(void) -{ - int i, nid; - unsigned long start_paddr, size; - - if ((SYMBOL(node_memblk) == NOT_FOUND_SYMBOL) - || (ARRAY_LENGTH(node_memblk) == NOT_FOUND_STRUCTURE) - || (SIZE(node_memblk_s) == NOT_FOUND_STRUCTURE) - || (OFFSET(node_memblk_s.start_paddr) == NOT_FOUND_STRUCTURE) - || (OFFSET(node_memblk_s.size) == NOT_FOUND_STRUCTURE) - || (OFFSET(node_memblk_s.nid) == NOT_FOUND_STRUCTURE)) { - return vt.numnodes; - } else { - for (i = 0; i < ARRAY_LENGTH(node_memblk); i++) { - if (!get_node_memblk(i, &start_paddr, &size, &nid)) { - ERRMSG("Can't get the node_memblk (%d)\n", i); - return 0; - } - if (!start_paddr && !size &&!nid) - break; - - DEBUG_MSG("nid : %d\n", nid); - DEBUG_MSG(" start_paddr: %lx\n", start_paddr); - DEBUG_MSG(" size : %lx\n", size); - } - if (i == 0) { - /* - * On non-NUMA systems, node_memblk_s is not set. - */ - return vt.numnodes; - } else { - return i; - } - } -} - -int -separate_mem_map(struct mem_map_data *mmd, int *id_mm, int nid_pgdat, - unsigned long mem_map_pgdat, unsigned long pfn_start_pgdat) -{ - int i, nid; - unsigned long start_paddr, size, pfn_start, pfn_end, mem_map; - - for (i = 0; i < ARRAY_LENGTH(node_memblk); i++) { - if (!get_node_memblk(i, &start_paddr, &size, &nid)) { - ERRMSG("Can't get the node_memblk (%d)\n", i); - return FALSE; - } - if (!start_paddr && !size && !nid) - break; - - /* - * Check pglist_data.node_id and node_memblk_s.nid match. - */ - if (nid_pgdat != nid) - continue; - - pfn_start = paddr_to_pfn(start_paddr); - pfn_end = paddr_to_pfn(start_paddr + size); - - if (pfn_start < pfn_start_pgdat) { - ERRMSG("node_memblk_s.start_paddr of node (%d) is invalid.\n", nid); - return FALSE; - } - if (info->max_mapnr < pfn_end) { - DEBUG_MSG("pfn_end of node (%d) is over max_mapnr.\n", - nid); - DEBUG_MSG(" pfn_start: %lx\n", pfn_start); - DEBUG_MSG(" pfn_end : %lx\n", pfn_end); - DEBUG_MSG(" max_mapnr: %llx\n", info->max_mapnr); - - pfn_end = info->max_mapnr; - } - - mem_map = mem_map_pgdat+SIZE(page)*(pfn_start-pfn_start_pgdat); - - mmd->pfn_start = pfn_start; - mmd->pfn_end = pfn_end; - mmd->mem_map = mem_map; - - mmd++; - (*id_mm)++; - } - return TRUE; -} - -int -get_mm_discontigmem(void) -{ - int i, j, id_mm, node, num_mem_map, separate_mm = FALSE; - unsigned long pgdat, mem_map, pfn_start, pfn_end, node_spanned_pages; - unsigned long vmem_map; - struct mem_map_data temp_mmd; - - num_mem_map = get_num_mm_discontigmem(); - if (num_mem_map < vt.numnodes) { - ERRMSG("Can't get the number of mem_map.\n"); - return FALSE; - } - struct mem_map_data mmd[num_mem_map]; - if (vt.numnodes < num_mem_map) { - separate_mm = TRUE; - } - - /* - * Note: - * This note is only for ia64 discontigmem kernel. - * It is better to take mem_map information from a symbol vmem_map - * instead of pglist_data.node_mem_map, because some node_mem_map - * sometimes does not have mem_map information corresponding to its - * node_start_pfn. - */ - if (SYMBOL(vmem_map) != NOT_FOUND_SYMBOL) { - if (!readmem(VADDR, SYMBOL(vmem_map), &vmem_map, sizeof vmem_map)) { - ERRMSG("Can't get vmem_map.\n"); - return FALSE; - } - } - - /* - * Get the first node_id. + * Get the first node_id. */ if ((node = next_online_node(0)) < 0) { ERRMSG("Can't get next online node.\n"); @@ -4223,7 +2385,7 @@ get_mm_discontigmem(void) } } i = num_mem_map - 1; - if (vt.mem_flags & MEMORY_XEN) { + if (is_xen_memory()) { if (mmd[i].pfn_end < info->dom0_mapnr) dump_mem_map(mmd[i].pfn_end, info->dom0_mapnr, NOT_MEMMAP_ADDR, id_mm); @@ -4356,7 +2518,7 @@ get_mem_map_without_mm(void) strerror(errno)); return FALSE; } - if (vt.mem_flags & MEMORY_XEN) + if (is_xen_memory()) dump_mem_map(0, info->dom0_mapnr, NOT_MEMMAP_ADDR, 0); else dump_mem_map(0, info->max_mapnr, NOT_MEMMAP_ADDR, 0); @@ -4369,14 +2531,6 @@ get_mem_map(void) { int ret; - if (vt.mem_flags & MEMORY_XEN) { - if (!get_dom0_mapnr()) { - ERRMSG("Can't domain-0 pfn.\n"); - return FALSE; - } - DEBUG_MSG("domain-0 pfn : %llx\n", info->dom0_mapnr); - } - switch (get_mem_type()) { case SPARSEMEM: DEBUG_MSG("\n"); @@ -4462,14 +2616,47 @@ initialize_bitmap_memory(void) int initial(void) { + off_t offset; + unsigned long size; int debug_info = FALSE; - if (!(vt.mem_flags & MEMORY_XEN) && info->flag_exclude_xen_dom) { - MSG("'-X' option is disable,"); - MSG("because %s is not Xen's memory core image.\n", info->name_memory); - MSG("Commandline parameter is invalid.\n"); - MSG("Try `makedumpfile --help' for more information.\n"); + if (is_xen_memory() && !initial_xen()) return FALSE; + +#ifdef USELZO + if (lzo_init() == LZO_E_OK) + info->flag_lzo_support = TRUE; +#else + if (info->flag_compress == DUMP_DH_COMPRESSED_LZO) { + MSG("'-l' option is disabled, "); + MSG("because this binary doesn't support lzo compression.\n"); + MSG("Try `make USELZO=on` when building.\n"); + } +#endif + +#ifndef USESNAPPY + if (info->flag_compress == DUMP_DH_COMPRESSED_SNAPPY) { + MSG("'-p' option is disabled, "); + MSG("because this binary doesn't support snappy " + "compression.\n"); + MSG("Try `make USESNAPPY=on` when building.\n"); + } +#endif + + if (info->flag_exclude_xen_dom) { + if(info->flag_cyclic) { + info->flag_cyclic = FALSE; + MSG("Switched running mode from cyclic to non-cyclic,\n"); + MSG("because the cyclic mode doesn't support Xen.\n"); + } + + if (!is_xen_memory()) { + MSG("'-X' option is disable,"); + MSG("because %s is not Xen's memory core image.\n", info->name_memory); + MSG("Commandline parameter is invalid.\n"); + MSG("Try `makedumpfile --help' for more information.\n"); + return FALSE; + } } if (info->flag_refiltering) { @@ -4479,6 +2666,14 @@ initial(void) info->name_memory); return FALSE; } + + if(info->flag_cyclic) { + info->flag_cyclic = FALSE; + MSG("Switched running mode from cyclic to non-cyclic,\n"); + MSG("because the cyclic mode doesn't support refiltering\n"); + MSG("kdump compressed format.\n"); + } + info->phys_base = info->kh_memory->phys_base; info->max_dump_level |= info->kh_memory->dump_level; @@ -4493,6 +2688,12 @@ initial(void) return FALSE; } + if(info->flag_cyclic) { + info->flag_cyclic = FALSE; + MSG("Switched running mode from cyclic to non-cyclic,\n"); + MSG("because the cyclic mode doesn't support sadump format.\n"); + } + set_page_size(sadump_page_size()); if (!sadump_initialize_bitmap_memory()) @@ -4524,8 +2725,8 @@ initial(void) * Get the debug information for analysis from the kernel file */ } else if (info->name_vmlinux) { - set_dwarf_debuginfo("vmlinux", info->name_vmlinux, - info->fd_vmlinux); + set_dwarf_debuginfo("vmlinux", NULL, + info->name_vmlinux, info->fd_vmlinux); if (!get_symbol_info()) return FALSE; @@ -4542,7 +2743,7 @@ initial(void) * Check whether /proc/vmcore contains vmcoreinfo, * and get both the offset and the size. */ - if (!info->offset_vmcoreinfo || !info->size_vmcoreinfo) { + if (!has_vmcoreinfo()) { if (info->max_dump_level <= DL_EXCLUDE_ZERO) goto out; @@ -4562,15 +2763,13 @@ initial(void) * in /proc/vmcore. vmcoreinfo in /proc/vmcore is more reliable * than -x/-i option. */ - if (info->offset_vmcoreinfo && info->size_vmcoreinfo) { - if (!read_vmcoreinfo_from_vmcore(info->offset_vmcoreinfo, - info->size_vmcoreinfo, FALSE)) + if (has_vmcoreinfo()) { + get_vmcoreinfo(&offset, &size); + if (!read_vmcoreinfo_from_vmcore(offset, size, FALSE)) return FALSE; debug_info = TRUE; } - if (!get_value_for_old_linux()) - return FALSE; out: if (!info->page_size) { /* @@ -4583,6 +2782,41 @@ out: if (!get_max_mapnr()) return FALSE; + if (info->flag_cyclic) { + if (info->bufsize_cyclic == 0) { + if (!calculate_cyclic_buffer_size()) + return FALSE; + } else { + unsigned long long free_memory; + + /* + * The buffer size is specified as Kbyte with + * --cyclic-buffer option. + */ + info->bufsize_cyclic <<= 10; + + /* + * Truncate the buffer size to free memory size. + */ + free_memory = get_free_memory_size(); + if (info->bufsize_cyclic > free_memory) { + MSG("Specified buffer size is larger than free memory.\n"); + MSG("The buffer size for the cyclic mode will "); + MSG("be truncated to %lld byte.\n", free_memory); + /* + * bufsize_cyclic is used to allocate 1st and 2nd bitmap, + * so it should be truncated to the half of free_memory. + */ + info->bufsize_cyclic = free_memory / 2; + } + } + + info->pfn_cyclic = info->bufsize_cyclic * BITPERBYTE; + + DEBUG_MSG("\n"); + DEBUG_MSG("Buffer size for the cyclic mode: %ld\n", info->bufsize_cyclic); + } + if (debug_info) { if (info->flag_sadump) (void) sadump_virt_phys_base(); @@ -4597,7 +2831,7 @@ out: if (!online_cpus) return FALSE; - info->nr_cpus = online_cpus; + set_nr_cpus(online_cpus); } if (!check_release()) @@ -4627,11 +2861,23 @@ out: !sadump_generate_elf_note_from_dumpfile()) return FALSE; + if (info->flag_cyclic && info->dump_level & DL_EXCLUDE_FREE) + check_cyclic_buffer_overrun(); + } else { if (!get_mem_map_without_mm()) return FALSE; } + if (is_xen_memory() && !get_dom0_mapnr()) + return FALSE; + + if (!get_value_for_old_linux()) + return FALSE; + + if (info->flag_cyclic && (info->dump_level & DL_EXCLUDE_FREE)) + setup_page_is_buddy(); + return TRUE; } @@ -4645,6 +2891,12 @@ initialize_bitmap(struct dump_bitmap *bi } void +initialize_bitmap_cyclic(char *bitmap) +{ + memset(bitmap, 0, info->bufsize_cyclic); +} + +void initialize_1st_bitmap(struct dump_bitmap *bitmap) { initialize_bitmap(bitmap); @@ -4708,6 +2960,27 @@ set_bitmap(struct dump_bitmap *bitmap, u } int +set_bitmap_cyclic(char *bitmap, unsigned long long pfn, int val) +{ + int byte, bit; + + if (pfn < info->cyclic_start_pfn || info->cyclic_end_pfn <= pfn) + return FALSE; + + /* + * If val is 0, clear bit on the bitmap. + */ + byte = (pfn - info->cyclic_start_pfn)>>3; + bit = (pfn - info->cyclic_start_pfn) & 7; + if (val) + bitmap[byte] |= 1<bitmap1, pfn, 1); + if (info->flag_cyclic) { + return set_bitmap_cyclic(info->partial_bitmap1, pfn, 1); + } else { + return set_bitmap(info->bitmap1, pfn, 1); + } } int clear_bit_on_1st_bitmap(unsigned long long pfn) { - return set_bitmap(info->bitmap1, pfn, 0); + if (info->flag_cyclic) { + return set_bitmap_cyclic(info->partial_bitmap1, pfn, 0); + } else { + return set_bitmap(info->bitmap1, pfn, 0); + } } int clear_bit_on_2nd_bitmap(unsigned long long pfn) { - return set_bitmap(info->bitmap2, pfn, 0); + if (info->flag_cyclic) { + return set_bitmap_cyclic(info->partial_bitmap2, pfn, 0); + } else { + return set_bitmap(info->bitmap2, pfn, 0); + } } int @@ -4769,7 +3054,7 @@ clear_bit_on_2nd_bitmap_for_kernel(unsig { unsigned long long maddr; - if (vt.mem_flags & MEMORY_XEN) { + if (is_xen_memory()) { maddr = ptom_xen(pfn_to_paddr(pfn)); if (maddr == NOT_PADDR) { ERRMSG("Can't convert a physical address(%llx) to machine address.\n", @@ -4784,7 +3069,7 @@ clear_bit_on_2nd_bitmap_for_kernel(unsig static inline int is_in_segs(unsigned long long paddr) { - if (info->flag_refiltering) { + if (info->flag_refiltering || info->flag_sadump) { static struct dump_bitmap bitmap1 = {0}; if (bitmap1.fd == 0) @@ -5076,38 +3361,12 @@ rearrange_dumpdata(void) return TRUE; } -/* - * Same as paddr_to_offset() but makes sure that the specified offset (hint) - * in the segment. - */ -off_t -paddr_to_offset2(unsigned long long paddr, off_t hint) -{ - int i; - off_t offset; - unsigned long long len; - struct pt_load_segment *pls; - - for (i = offset = 0; i < info->num_load_memory; i++) { - pls = &info->pt_load_segments[i]; - len = pls->phys_end - pls->phys_start; - if ((paddr >= pls->phys_start) - && (paddr < pls->phys_end) - && (hint >= pls->file_offset) - && (hint < pls->file_offset + len)) { - offset = (off_t)(paddr - pls->phys_start) + - pls->file_offset; - break; - } - } - return offset; -} - unsigned long long page_to_pfn(unsigned long page) { unsigned int num; - unsigned long long pfn = 0, index = 0; + unsigned long long pfn = ULONGLONG_MAX; + unsigned long long index = 0; struct mem_map_data *mmd; mmd = info->mem_map_data; @@ -5117,12 +3376,12 @@ page_to_pfn(unsigned long page) if (page < mmd->mem_map) continue; index = (page - mmd->mem_map) / SIZE(page); - if (index > mmd->pfn_end - mmd->pfn_start) + if (index >= mmd->pfn_end - mmd->pfn_start) continue; pfn = mmd->pfn_start + index; break; } - if (!pfn) { + if (pfn == ULONGLONG_MAX) { ERRMSG("Can't convert the address of page descriptor (%lx) to pfn.\n", page); return ULONGLONG_MAX; } @@ -5176,9 +3435,9 @@ reset_bitmap_of_free_pages(unsigned long } for (i = 0; i < (1<flag_cyclic) { /* * On linux-2.6.21 or later, the number of free_pages is * sometimes different from the one of the list "free_area", @@ -5222,19 +3481,104 @@ reset_bitmap_of_free_pages(unsigned long DEBUG_MSG(" free_pages = %ld\n", free_pages); DEBUG_MSG(" found_free_pages = %ld\n", found_free_pages); } - pfn_free += found_free_pages; + pfn_free += found_free_pages; + + return TRUE; +} + +static int +dump_log_entry(char *logptr, int fp) +{ + char *msg, *p; + unsigned int i, text_len; + unsigned long long ts_nsec; + char buf[BUFSIZE]; + ulonglong nanos; + ulong rem; + + text_len = USHORT(logptr + OFFSET(log.text_len)); + ts_nsec = ULONGLONG(logptr + OFFSET(log.ts_nsec)); + + nanos = (ulonglong)ts_nsec / (ulonglong)1000000000; + rem = (ulonglong)ts_nsec % (ulonglong)1000000000; + + msg = logptr + SIZE(log); + + sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000); + + for (i = 0, p = msg; i < text_len; i++, p++) { + if (*p == '\n') + sprintf(buf, "%s.", buf); + else if (isprint(*p) || isspace(*p)) + sprintf(buf, "%s%c", buf, *p); + else + sprintf(buf, "%s.", buf); + } + + sprintf(buf, "%s\n", buf); + + if (write(info->fd_dumpfile, buf, strlen(buf)) < 0) + return FALSE; + else + return TRUE; +} + +/* + * get log record by index; idx must point to valid message. + */ +static char * +log_from_idx(unsigned int idx, char *logbuf) +{ + char *logptr; + unsigned int msglen; + + logptr = logbuf + idx; + + /* + * A length == 0 record is the end of buffer marker. + * Wrap around and return the message at the start of + * the buffer. + */ + + msglen = USHORT(logptr + OFFSET(log.len)); + if (!msglen) + logptr = logbuf; + + return logptr; +} + +static long +log_next(unsigned int idx, char *logbuf) +{ + char *logptr; + unsigned int msglen; + + logptr = logbuf + idx; + + /* + * A length == 0 record is the end of buffer marker. Wrap around and + * read the message at the start of the buffer as *this* one, and + * return the one after that. + */ + + msglen = USHORT(logptr + OFFSET(log.len)); + if (!msglen) { + msglen = USHORT(logbuf + OFFSET(log.len)); + return msglen; + } - return TRUE; + return idx + msglen; } int dump_dmesg() { int log_buf_len, length_log, length_oldlog, ret = FALSE; - unsigned long log_buf, log_end, index; + unsigned long index, log_buf, log_end; + unsigned int idx, log_first_idx, log_next_idx; unsigned long log_end_2_6_24; unsigned log_end_2_6_25; - char *log_buffer = NULL; + char *log_buffer = NULL, *log_ptr = NULL; /* * log_end has been changed to "unsigned" since linux-2.6.25. @@ -5245,84 +3589,130 @@ dump_dmesg() return FALSE; if (!info->flag_refiltering && !info->flag_sadump) { - if (!get_elf_info()) + if (!get_elf_info(info->fd_memory, info->name_memory)) return FALSE; } if (!initial()) return FALSE; if ((SYMBOL(log_buf) == NOT_FOUND_SYMBOL) - || (SYMBOL(log_buf_len) == NOT_FOUND_SYMBOL) - || (SYMBOL(log_end) == NOT_FOUND_SYMBOL)) { + || (SYMBOL(log_buf_len) == NOT_FOUND_SYMBOL)) { ERRMSG("Can't find some symbols for log_buf.\n"); return FALSE; } + /* + * kernel 3.5 variable-length record buffer structure + */ + if (SYMBOL(log_end) == NOT_FOUND_SYMBOL) { + if ((SYMBOL(log_first_idx) == NOT_FOUND_SYMBOL) + || (SYMBOL(log_next_idx) == NOT_FOUND_SYMBOL)) { + ERRMSG("Can't find variable-length record symbols"); + return FALSE; + } else { + if (!readmem(VADDR, SYMBOL(log_first_idx), &log_first_idx, + sizeof(log_first_idx))) { + ERRMSG("Can't get log_first_idx.\n"); + return FALSE; + } + if (!readmem(VADDR, SYMBOL(log_next_idx), &log_next_idx, + sizeof(log_next_idx))) { + ERRMSG("Can't get log_next_idx.\n"); + return FALSE; + } + } + } if (!readmem(VADDR, SYMBOL(log_buf), &log_buf, sizeof(log_buf))) { ERRMSG("Can't get log_buf.\n"); return FALSE; } - if (info->kernel_version >= KERNEL_VERSION(2, 6, 25)) { - if (!readmem(VADDR, SYMBOL(log_end), &log_end_2_6_25, - sizeof(log_end_2_6_25))) { - ERRMSG("Can't to get log_end.\n"); - return FALSE; - } - log_end = log_end_2_6_25; - } else { - if (!readmem(VADDR, SYMBOL(log_end), &log_end_2_6_24, - sizeof(log_end_2_6_24))) { - ERRMSG("Can't to get log_end.\n"); - return FALSE; + if (info->kernel_version < KERNEL_VERSION(3, 5, 0)) { + if (info->kernel_version >= KERNEL_VERSION(2, 6, 25)) { + if (!readmem(VADDR, SYMBOL(log_end), &log_end_2_6_25, + sizeof(log_end_2_6_25))) { + ERRMSG("Can't to get log_end.\n"); + return FALSE; + } + log_end = log_end_2_6_25; + } else { + if (!readmem(VADDR, SYMBOL(log_end), &log_end_2_6_24, + sizeof(log_end_2_6_24))) { + ERRMSG("Can't to get log_end.\n"); + return FALSE; + } + log_end = log_end_2_6_24; } - log_end = log_end_2_6_24; - } + } else + log_end = 0; + if (!readmem(VADDR, SYMBOL(log_buf_len), &log_buf_len, sizeof(log_buf_len))) { ERRMSG("Can't get log_buf_len.\n"); return FALSE; } DEBUG_MSG("\n"); - DEBUG_MSG("log_buf : %lx\n", log_buf); - DEBUG_MSG("log_end : %lx\n", log_end); - DEBUG_MSG("log_buf_len : %d\n", log_buf_len); + DEBUG_MSG("log_buf : %lx\n", log_buf); + DEBUG_MSG("log_end : %lx\n", log_end); + DEBUG_MSG("log_buf_len : %d\n", log_buf_len); + DEBUG_MSG("log_first_idx : %u\n", log_first_idx); + DEBUG_MSG("log_next_idx : %u\n", log_next_idx); if ((log_buffer = malloc(log_buf_len)) == NULL) { ERRMSG("Can't allocate memory for log_buf. %s\n", - strerror(errno)); + strerror(errno)); return FALSE; } - if (log_end < log_buf_len) { - length_log = log_end; - if(!readmem(VADDR, log_buf, log_buffer, length_log)) { - ERRMSG("Can't read dmesg log.\n"); + if (info->kernel_version < KERNEL_VERSION(3, 5, 0)) { + if (log_end < log_buf_len) { + length_log = log_end; + if (!readmem(VADDR, log_buf, log_buffer, length_log)) { + ERRMSG("Can't read dmesg log.\n"); + goto out; + } + } else { + index = log_end & (log_buf_len - 1); + DEBUG_MSG("index : %lx\n", index); + length_log = log_buf_len; + length_oldlog = log_buf_len - index; + if (!readmem(VADDR, log_buf + index, log_buffer, length_oldlog)) { + ERRMSG("Can't read old dmesg log.\n"); + goto out; + } + if (!readmem(VADDR, log_buf, log_buffer + length_oldlog, index)) { + ERRMSG("Can't read new dmesg log.\n"); + goto out; + } + } + DEBUG_MSG("length_log : %d\n", length_log); + + if (!open_dump_file()) { + ERRMSG("Can't open output file.\n"); goto out; } + if (write(info->fd_dumpfile, log_buffer, length_log) < 0) + goto out; + + if (!close_files_for_creating_dumpfile()) + goto out; } else { - index = log_end & (log_buf_len - 1); - DEBUG_MSG("index : %lx\n", index); - length_log = log_buf_len; - length_oldlog = log_buf_len - index; - if(!readmem(VADDR, log_buf + index, log_buffer, length_oldlog)) { - ERRMSG("Can't read old dmesg log.\n"); + if (!readmem(VADDR, log_buf, log_buffer, log_buf_len)) { + ERRMSG("Can't read indexed dmesg log.\n"); goto out; } - if(!readmem(VADDR, log_buf, log_buffer + length_oldlog, index)) { - ERRMSG("Can't read new dmesg log.\n"); + if (!open_dump_file()) { + ERRMSG("Can't open output file.\n"); goto out; } + idx = log_first_idx; + while (idx != log_next_idx) { + log_ptr = log_from_idx(idx, log_buffer); + if (!dump_log_entry(log_ptr, info->fd_dumpfile)) + goto out; + idx = log_next(idx, log_buffer); + } + if (!close_files_for_creating_dumpfile()) + goto out; } - DEBUG_MSG("length_log : %d\n", length_log); - - if (!open_dump_file()) { - ERRMSG("Can't open output file.\n"); - goto out; - } - if (write(info->fd_dumpfile, log_buffer, length_log) < 0) - goto out; - - if (!close_files_for_creating_dumpfile()) - goto out; ret = TRUE; out: @@ -5338,6 +3728,7 @@ _exclude_free_page(void) { int i, nr_zones, num_nodes, node; unsigned long node_zones, zone, spanned_pages, pgdat; + struct timeval tv_start; if ((node = next_online_node(0)) < 0) { ERRMSG("Can't get next online node.\n"); @@ -5347,6 +3738,8 @@ _exclude_free_page(void) ERRMSG("Can't get pgdat list.\n"); return FALSE; } + gettimeofday(&tv_start, NULL); + for (num_nodes = 1; num_nodes <= vt.numnodes; num_nodes++) { print_progress(PROGRESS_FREE_PAGES, num_nodes - 1, vt.numnodes); @@ -5391,6 +3784,7 @@ _exclude_free_page(void) * print [100 %] */ print_progress(PROGRESS_FREE_PAGES, vt.numnodes, vt.numnodes); + print_execution_time(PROGRESS_FREE_PAGES, &tv_start); return TRUE; } @@ -5423,6 +3817,10 @@ exclude_free_page(void) ERRMSG("Can't get necessary structures for excluding free pages.\n"); return FALSE; } + if (is_xen_memory() && !info->dom0_mapnr) { + ERRMSG("Can't get max domain-0 PFN for excluding free pages.\n"); + return FALSE; + } /* * Detect free pages and update 2nd-bitmap. @@ -5434,6 +3832,110 @@ exclude_free_page(void) } /* + * Let C be a cyclic buffer size and B a bitmap size used for + * representing maximum block size managed by buddy allocator. + * + * For some combinations of C and B, clearing operation can overrun + * the cyclic buffer. Let's consider three cases. + * + * - If C == B, this is trivially safe. + * + * - If B > C, overrun can easily happen. + * + * - In case of C > B, if C mod B != 0, then there exist n > m > 0, + * B > b > 0 such that n x C = m x B + b. This means that clearing + * operation overruns cyclic buffer (B - b)-bytes in the + * combination of n-th cycle and m-th block. + * + * Note that C mod B != 0 iff (m x C) mod B != 0 for some m. + * + * If C == B, C mod B == 0 always holds. Again, if B > C, C mod B != 0 + * always holds. Hence, it's always sufficient to check the condition + * C mod B != 0 in order to determine whether overrun can happen or + * not. + * + * The bitmap size used for maximum block size B is calculated from + * MAX_ORDER as: + * + * B := DIVIDE_UP((1 << (MAX_ORDER - 1)), BITS_PER_BYTE) + * + * Normally, MAX_ORDER is 11 at default. This is configurable through + * CONFIG_FORCE_MAX_ZONEORDER. + */ +static void +check_cyclic_buffer_overrun(void) +{ + int max_order = ARRAY_LENGTH(zone.free_area); + int max_order_nr_pages = 1 << (max_order - 1); + unsigned long max_block_size = roundup(max_order_nr_pages, BITPERBYTE); + + if (info->bufsize_cyclic % + roundup(max_order_nr_pages, BITPERBYTE)) { + unsigned long bufsize; + + if (max_block_size > info->bufsize_cyclic) { + MSG("WARNING: some free pages are not filtered.\n"); + return; + } + + bufsize = info->bufsize_cyclic; + info->bufsize_cyclic = round(bufsize, max_block_size); + + MSG("cyclic buffer size has been changed: %lu => %lu\n", + bufsize, info->bufsize_cyclic); + } +} + +/* + * For the kernel versions from v2.6.17 to v2.6.37. + */ +static int +page_is_buddy_v2(unsigned long flags, unsigned int _mapcount, + unsigned long private, unsigned int _count) +{ + if (flags & (1UL << NUMBER(PG_buddy))) + return TRUE; + + return FALSE; +} + +/* + * For v2.6.38 and later kernel versions. + */ +static int +page_is_buddy_v3(unsigned long flags, unsigned int _mapcount, + unsigned long private, unsigned int _count) +{ + if (flags & (1UL << NUMBER(PG_slab))) + return FALSE; + + if (_mapcount == (int)NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE)) + return TRUE; + + return FALSE; +} + +static void +setup_page_is_buddy(void) +{ + if (OFFSET(page.private) == NOT_FOUND_STRUCTURE) + goto out; + + if (NUMBER(PG_buddy) == NOT_FOUND_NUMBER) { + if (NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE) != NOT_FOUND_NUMBER) { + if (OFFSET(page._mapcount) != NOT_FOUND_STRUCTURE) + info->page_is_buddy = page_is_buddy_v3; + } + } else + info->page_is_buddy = page_is_buddy_v2; + +out: + if (!info->page_is_buddy) + DEBUG_MSG("Can't select page_is_buddy handler; " + "follow free lists instead of mem_map array.\n"); +} + +/* * If using a dumpfile in kdump-compressed format as a source file * instead of /proc/vmcore, 1st-bitmap of a new dumpfile must be * the same as the one of a source file. @@ -5480,9 +3982,11 @@ int create_1st_bitmap(void) { int i; + unsigned int num_pt_loads = get_num_pt_loads(); char buf[info->page_size]; unsigned long long pfn, pfn_start, pfn_end, pfn_bitmap1; - struct pt_load_segment *pls; + unsigned long long phys_start, phys_end; + struct timeval tv_start; off_t offset_page; if (info->flag_refiltering) @@ -5512,16 +4016,18 @@ create_1st_bitmap(void) offset_page += info->page_size; } + gettimeofday(&tv_start, NULL); + /* * If page is on memory hole, set bit on the 1st-bitmap. */ - for (i = pfn_bitmap1 = 0; i < info->num_load_memory; i++) { + pfn_bitmap1 = 0; + for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) { - print_progress(PROGRESS_HOLES, i, info->num_load_memory); + print_progress(PROGRESS_HOLES, i, num_pt_loads); - pls = &info->pt_load_segments[i]; - pfn_start = paddr_to_pfn(pls->phys_start); - pfn_end = paddr_to_pfn(pls->phys_end); + pfn_start = paddr_to_pfn(phys_start); + pfn_end = paddr_to_pfn(phys_end); if (!is_in_segs(pfn_to_paddr(pfn_start))) pfn_start++; @@ -5536,6 +4042,7 @@ create_1st_bitmap(void) * print 100 % */ print_progress(PROGRESS_HOLES, info->max_mapnr, info->max_mapnr); + print_execution_time(PROGRESS_HOLES, &tv_start); if (!sync_1st_bitmap()) return FALSE; @@ -5543,6 +4050,39 @@ create_1st_bitmap(void) return TRUE; } +int +create_1st_bitmap_cyclic() +{ + int i; + unsigned long long pfn, pfn_bitmap1; + unsigned long long phys_start, phys_end; + unsigned long long pfn_start, pfn_end; + + /* + * At first, clear all the bits on the 1st-bitmap. + */ + initialize_bitmap_cyclic(info->partial_bitmap1); + + /* + * If page is on memory hole, set bit on the 1st-bitmap. + */ + pfn_bitmap1 = 0; + for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) { + pfn_start = paddr_to_pfn(phys_start); + pfn_end = paddr_to_pfn(phys_end); + + if (!is_in_segs(pfn_to_paddr(pfn_start))) + pfn_start++; + for (pfn = pfn_start; pfn < pfn_end; pfn++) { + if (set_bit_on_1st_bitmap(pfn)) + pfn_bitmap1++; + } + } + pfn_memhole -= pfn_bitmap1; + + return TRUE; +} + /* * Exclude the page filled with zero in case of creating an elf dumpfile. */ @@ -5551,11 +4091,14 @@ exclude_zero_pages(void) { unsigned long long pfn, paddr; struct dump_bitmap bitmap2; + struct timeval tv_start; unsigned char buf[info->page_size]; initialize_2nd_bitmap(&bitmap2); - for (pfn = paddr = 0; pfn < info->max_mapnr; + gettimeofday(&tv_start, NULL); + + for (pfn = 0, paddr = pfn_to_paddr(pfn); pfn < info->max_mapnr; pfn++, paddr += info->page_size) { print_progress(PROGRESS_ZERO_PAGES, pfn, info->max_mapnr); @@ -5566,7 +4109,7 @@ exclude_zero_pages(void) if (!is_dumpable(&bitmap2, pfn)) continue; - if (vt.mem_flags & MEMORY_XEN) { + if (is_xen_memory()) { if (!readmem(MADDR_XEN, paddr, buf, info->page_size)) { ERRMSG("Can't get the page data(pfn:%llx, max_mapnr:%llx).\n", pfn, info->max_mapnr); @@ -5580,8 +4123,8 @@ exclude_zero_pages(void) } } if (is_zero_page(buf, info->page_size)) { - clear_bit_on_2nd_bitmap(pfn); - pfn_zero++; + if (clear_bit_on_2nd_bitmap(pfn)) + pfn_zero++; } } @@ -5589,6 +4132,7 @@ exclude_zero_pages(void) * print [100 %] */ print_progress(PROGRESS_ZERO_PAGES, info->max_mapnr, info->max_mapnr); + print_execution_time(PROGRESS_ZERO_PAGES, &tv_start); return TRUE; } @@ -5601,8 +4145,8 @@ __exclude_unnecessary_pages(unsigned lon unsigned long long pfn_read_start, pfn_read_end, index_pg; unsigned char page_cache[SIZE(page) * PGMM_CACHED]; unsigned char *pcache; - unsigned int _count; - unsigned long flags, mapping; + unsigned int _count, _mapcount = 0; + unsigned long flags, mapping, private = 0; /* * Refresh the buffer of struct page, when changing mem_map. @@ -5613,9 +4157,15 @@ __exclude_unnecessary_pages(unsigned lon for (pfn = pfn_start; pfn < pfn_end; pfn++, mem_map += SIZE(page)) { /* + * If this pfn doesn't belong to target region, skip this pfn. + */ + if (info->flag_cyclic && !is_cyclic_region(pfn)) + continue; + + /* * Exclude the memory hole. */ - if (vt.mem_flags & MEMORY_XEN) { + if (is_xen_memory()) { maddr = ptom_xen(pfn_to_paddr(pfn)); if (maddr == NOT_PADDR) { ERRMSG("Can't convert a physical address(%llx) to machine address.\n", @@ -5650,15 +4200,42 @@ __exclude_unnecessary_pages(unsigned lon flags = ULONG(pcache + OFFSET(page.flags)); _count = UINT(pcache + OFFSET(page._count)); mapping = ULONG(pcache + OFFSET(page.mapping)); + if (OFFSET(page._mapcount) != NOT_FOUND_STRUCTURE) + _mapcount = UINT(pcache + OFFSET(page._mapcount)); + if (OFFSET(page.private) != NOT_FOUND_STRUCTURE) + private = ULONG(pcache + OFFSET(page.private)); + + /* + * Exclude the free page managed by a buddy + */ + if ((info->dump_level & DL_EXCLUDE_FREE) + && info->flag_cyclic + && info->page_is_buddy + && info->page_is_buddy(flags, _mapcount, private, _count)) { + int i; + for (i = 0; i < (1 << private); ++i) { + /* + * According to combination of + * MAX_ORDER and size of cyclic + * buffer, this clearing bit operation + * can overrun the cyclic buffer. + * + * See check_cyclic_buffer_overrun() + * for the detail. + */ + clear_bit_on_2nd_bitmap_for_kernel(pfn + i); + } + pfn_free += i; + } /* * Exclude the cache page without the private page. */ - if ((info->dump_level & DL_EXCLUDE_CACHE) + else if ((info->dump_level & DL_EXCLUDE_CACHE) && (isLRU(flags) || isSwapCache(flags)) && !isPrivate(flags) && !isAnon(mapping)) { - clear_bit_on_2nd_bitmap_for_kernel(pfn); - pfn_cache++; + if (clear_bit_on_2nd_bitmap_for_kernel(pfn)) + pfn_cache++; } /* * Exclude the cache page with the private page. @@ -5666,16 +4243,23 @@ __exclude_unnecessary_pages(unsigned lon else if ((info->dump_level & DL_EXCLUDE_CACHE_PRI) && (isLRU(flags) || isSwapCache(flags)) && !isAnon(mapping)) { - clear_bit_on_2nd_bitmap_for_kernel(pfn); - pfn_cache_private++; + if (clear_bit_on_2nd_bitmap_for_kernel(pfn)) + pfn_cache_private++; } /* * Exclude the data page of the user process. */ else if ((info->dump_level & DL_EXCLUDE_USER_DATA) && isAnon(mapping)) { - clear_bit_on_2nd_bitmap_for_kernel(pfn); - pfn_user++; + if (clear_bit_on_2nd_bitmap_for_kernel(pfn)) + pfn_user++; + } + /* + * Exclude the hwpoison page. + */ + else if (isHWPOISON(flags)) { + if (clear_bit_on_2nd_bitmap_for_kernel(pfn)) + pfn_hwpoison++; } } return TRUE; @@ -5686,6 +4270,14 @@ exclude_unnecessary_pages(void) { unsigned int mm; struct mem_map_data *mmd; + struct timeval tv_start; + + if (is_xen_memory() && !info->dom0_mapnr) { + ERRMSG("Can't get max domain-0 PFN for excluding pages.\n"); + return FALSE; + } + + gettimeofday(&tv_start, NULL); for (mm = 0; mm < info->num_mem_map; mm++) { print_progress(PROGRESS_UNN_PAGES, mm, info->num_mem_map); @@ -5704,11 +4296,90 @@ exclude_unnecessary_pages(void) * print [100 %] */ print_progress(PROGRESS_UNN_PAGES, info->num_mem_map, info->num_mem_map); + print_execution_time(PROGRESS_UNN_PAGES, &tv_start); - if (info->dump_level & DL_EXCLUDE_FREE) + return TRUE; +} + +void +copy_bitmap_cyclic(void) +{ + memcpy(info->partial_bitmap2, info->partial_bitmap1, info->bufsize_cyclic); +} + +int +exclude_unnecessary_pages_cyclic(void) +{ + unsigned int mm; + struct mem_map_data *mmd; + struct timeval tv_start; + + /* + * Copy 1st-bitmap to 2nd-bitmap. + */ + copy_bitmap_cyclic(); + + if ((info->dump_level & DL_EXCLUDE_FREE) && !info->page_is_buddy) if (!exclude_free_page()) return FALSE; + /* + * Exclude cache pages, cache private pages, user data pages, + * free pages and hwpoison pages. + */ + if (info->dump_level & DL_EXCLUDE_CACHE || + info->dump_level & DL_EXCLUDE_CACHE_PRI || + info->dump_level & DL_EXCLUDE_USER_DATA || + NUMBER(PG_hwpoison) != NOT_FOUND_NUMBER || + ((info->dump_level & DL_EXCLUDE_FREE) && info->page_is_buddy)) { + + gettimeofday(&tv_start, NULL); + + for (mm = 0; mm < info->num_mem_map; mm++) { + + print_progress(PROGRESS_UNN_PAGES, mm, info->num_mem_map); + + mmd = &info->mem_map_data[mm]; + + if (mmd->mem_map == NOT_MEMMAP_ADDR) + continue; + + if (mmd->pfn_end >= info->cyclic_start_pfn && + mmd->pfn_start <= info->cyclic_end_pfn) { + if (!__exclude_unnecessary_pages(mmd->mem_map, + mmd->pfn_start, mmd->pfn_end)) + return FALSE; + } + } + + /* + * print [100 %] + */ + print_progress(PROGRESS_UNN_PAGES, info->num_mem_map, info->num_mem_map); + print_execution_time(PROGRESS_UNN_PAGES, &tv_start); + } + + return TRUE; +} + +int +update_cyclic_region(unsigned long long pfn) +{ + if (is_cyclic_region(pfn)) + return TRUE; + + info->cyclic_start_pfn = round(pfn, info->pfn_cyclic); + info->cyclic_end_pfn = info->cyclic_start_pfn + info->pfn_cyclic; + + if (info->cyclic_end_pfn > info->max_mapnr) + info->cyclic_end_pfn = info->max_mapnr; + + if (!create_1st_bitmap_cyclic()) + return FALSE; + + if (!exclude_unnecessary_pages_cyclic()) + return FALSE; + return TRUE; } @@ -5761,9 +4432,13 @@ create_2nd_bitmap(void) } /* - * Exclude unnecessary pages (free pages, cache pages, etc.) + * Exclude cache pages, cache private pages, user data pages, + * and hwpoison pages. */ - if (DL_EXCLUDE_ZERO < info->dump_level) { + if (info->dump_level & DL_EXCLUDE_CACHE || + info->dump_level & DL_EXCLUDE_CACHE_PRI || + info->dump_level & DL_EXCLUDE_USER_DATA || + NUMBER(PG_hwpoison) != NOT_FOUND_NUMBER) { if (!exclude_unnecessary_pages()) { ERRMSG("Can't exclude unnecessary pages.\n"); return FALSE; @@ -5771,6 +4446,13 @@ create_2nd_bitmap(void) } /* + * Exclude free pages. + */ + if (info->dump_level & DL_EXCLUDE_FREE) + if (!exclude_free_page()) + return FALSE; + + /* * Exclude Xen user domain. */ if (info->flag_exclude_xen_dom) { @@ -5844,6 +4526,38 @@ prepare_bitmap_buffer(void) return TRUE; } +int +prepare_bitmap_buffer_cyclic(void) +{ + unsigned long tmp; + + /* + * Create 2 bitmaps (1st-bitmap & 2nd-bitmap) on block_size boundary. + * The crash utility requires both of them to be aligned to block_size + * boundary. + */ + tmp = divideup(divideup(info->max_mapnr, BITPERBYTE), info->page_size); + info->len_bitmap = tmp*info->page_size*2; + + /* + * Prepare partial bitmap buffers for cyclic processing. + */ + if ((info->partial_bitmap1 = (char *)malloc(info->bufsize_cyclic)) == NULL) { + ERRMSG("Can't allocate memory for the 1st-bitmap. %s\n", + strerror(errno)); + return FALSE; + } + if ((info->partial_bitmap2 = (char *)malloc(info->bufsize_cyclic)) == NULL) { + ERRMSG("Can't allocate memory for the 2nd-bitmap. %s\n", + strerror(errno)); + return FALSE; + } + initialize_bitmap_cyclic(info->partial_bitmap1); + initialize_bitmap_cyclic(info->partial_bitmap2); + + return TRUE; +} + void free_bitmap_buffer(void) { @@ -5864,44 +4578,27 @@ create_dump_bitmap(void) { int ret = FALSE; - if (!prepare_bitmap_buffer()) - goto out; - - if (!create_1st_bitmap()) - goto out; - - if (!create_2nd_bitmap()) - goto out; - - ret = TRUE; -out: - free_bitmap_buffer(); - - return ret; -} + if (info->flag_cyclic) { + if (!prepare_bitmap_buffer_cyclic()) + goto out; -int -get_phnum_memory(void) -{ - int phnum; - Elf64_Ehdr ehdr64; - Elf32_Ehdr ehdr32; + info->num_dumpable = get_num_dumpable_cyclic(); + } else { + if (!prepare_bitmap_buffer()) + goto out; - if (info->flag_elf64_memory) { /* ELF64 */ - if (!get_elf64_ehdr(&ehdr64)) { - ERRMSG("Can't get ehdr64.\n"); - return FALSE; - } - phnum = ehdr64.e_phnum; - } else { /* ELF32 */ - if (!get_elf32_ehdr(&ehdr32)) { - ERRMSG("Can't get ehdr32.\n"); - return FALSE; - } - phnum = ehdr32.e_phnum; + if (!create_1st_bitmap()) + goto out; + + if (!create_2nd_bitmap()) + goto out; } - return phnum; + ret = TRUE; +out: + free_bitmap_buffer(); + + return ret; } int @@ -5920,7 +4617,7 @@ get_loads_dumpfile(void) return FALSE; for (i = 0; i < phnum; i++) { - if (!get_elf_phdr_memory(i, &load)) + if (!get_phdr_memory(i, &load)) return FALSE; if (load.p_type != PT_LOAD) continue; @@ -6038,7 +4735,7 @@ write_elf_phdr(struct cache_data *cd_hdr { Elf32_Phdr load32; - if (info->flag_elf64_memory) { /* ELF64 */ + if (is_elf64_memory()) { /* ELF64 */ if (!write_cache(cd_hdr, load, sizeof(Elf64_Phdr))) return FALSE; @@ -6068,8 +4765,6 @@ write_elf_header(struct cache_data *cd_h Elf64_Ehdr ehdr64; Elf32_Ehdr ehdr32; Elf64_Phdr note; - char size_str[MAX_SIZE_STR_LEN]; - struct filter_info *fl_info = filter_info; char *buf = NULL; const off_t failed = (off_t)-1; @@ -6082,13 +4777,21 @@ write_elf_header(struct cache_data *cd_h /* * Get the PT_LOAD number of the dumpfile. */ - if (!(num_loads_dumpfile = get_loads_dumpfile())) { - ERRMSG("Can't get a number of PT_LOAD.\n"); - goto out; + if (info->flag_cyclic) { + if (!(num_loads_dumpfile = get_loads_dumpfile_cyclic())) { + ERRMSG("Can't get a number of PT_LOAD.\n"); + goto out; + } + } else { + if (!(num_loads_dumpfile = get_loads_dumpfile())) { + ERRMSG("Can't get a number of PT_LOAD.\n"); + goto out; + } } - if (info->flag_elf64_memory) { /* ELF64 */ - if (!get_elf64_ehdr(&ehdr64)) { + if (is_elf64_memory()) { /* ELF64 */ + if (!get_elf64_ehdr(info->fd_memory, + info->name_memory, &ehdr64)) { ERRMSG("Can't get ehdr64.\n"); goto out; } @@ -6097,7 +4800,8 @@ write_elf_header(struct cache_data *cd_h */ ehdr64.e_phnum = 1 + num_loads_dumpfile; } else { /* ELF32 */ - if (!get_elf32_ehdr(&ehdr32)) { + if (!get_elf32_ehdr(info->fd_memory, + info->name_memory, &ehdr32)) { ERRMSG("Can't get ehdr32.\n"); goto out; } @@ -6110,7 +4814,7 @@ write_elf_header(struct cache_data *cd_h /* * Write an ELF header. */ - if (info->flag_elf64_memory) { /* ELF64 */ + if (is_elf64_memory()) { /* ELF64 */ if (!write_buffer(info->fd_dumpfile, 0, &ehdr64, sizeof(ehdr64), info->name_dumpfile)) goto out; @@ -6126,30 +4830,14 @@ write_elf_header(struct cache_data *cd_h * section so that we can add enough space in ELF notes section and * adjust the PT_LOAD offset accordingly. */ - while (fl_info) { - struct erase_info *ei; - - if (!fl_info->erase_info_idx) - continue; - ei = &erase_info[fl_info->erase_info_idx]; - if (fl_info->nullify) - sprintf(size_str, "nullify\n"); - else - sprintf(size_str, "size %ld\n", fl_info->size); - - size_eraseinfo += strlen("erase ") + - strlen(ei->symbol_expr) + 1 + - strlen(size_str); - fl_info = fl_info->next; - } + size_eraseinfo = get_size_eraseinfo(); /* * Store the size_eraseinfo for later use in write_elf_eraseinfo() - * function. This will overwrite the size fetched during - * get elf_info() function but we are ok with that. + * function. */ - info->size_eraseinfo = size_eraseinfo; - DEBUG_MSG("erase info size: %lu\n", info->size_eraseinfo); + info->size_elf_eraseinfo = size_eraseinfo; + DEBUG_MSG("erase info size: %lu\n", info->size_elf_eraseinfo); /* * Write a PT_NOTE header. @@ -6158,7 +4846,7 @@ write_elf_header(struct cache_data *cd_h goto out; for (i = 0; i < phnum; i++) { - if (!get_elf_phdr_memory(i, ¬e)) + if (!get_phdr_memory(i, ¬e)) return FALSE; if (note.p_type == PT_NOTE) break; @@ -6168,7 +4856,7 @@ write_elf_header(struct cache_data *cd_h goto out; } - if (info->flag_elf64_memory) { /* ELF64 */ + if (is_elf64_memory()) { /* ELF64 */ cd_header->offset = sizeof(ehdr64); offset_note_dumpfile = sizeof(ehdr64) + sizeof(Elf64_Phdr) * ehdr64.e_phnum; @@ -6185,8 +4873,8 @@ write_elf_header(struct cache_data *cd_h * Modify the note size in PT_NOTE header to accomodate eraseinfo data. * Eraseinfo will be written later. */ - if (info->size_eraseinfo) { - if (info->flag_elf64_memory) + if (info->size_elf_eraseinfo) { + if (is_elf64_memory()) note.p_filesz += sizeof(Elf64_Nhdr); else note.p_filesz += sizeof(Elf32_Nhdr); @@ -6242,6 +4930,8 @@ write_kdump_header(void) { int ret = FALSE; size_t size; + off_t offset_note, offset_vmcoreinfo; + unsigned long size_note, size_vmcoreinfo; struct disk_dump_header *dh = info->dump_header; struct kdump_sub_header kh; char *buf = NULL; @@ -6249,16 +4939,18 @@ write_kdump_header(void) if (info->flag_elf_dumpfile) return FALSE; + get_pt_note(&offset_note, &size_note); + /* * Write common header */ - strcpy(dh->signature, KDUMP_SIGNATURE); + strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); dh->header_version = 5; dh->block_size = info->page_size; - dh->sub_hdr_size = sizeof(kh) + info->size_note; + dh->sub_hdr_size = sizeof(kh) + size_note; dh->sub_hdr_size = divideup(dh->sub_hdr_size, dh->block_size); dh->max_mapnr = info->max_mapnr; - dh->nr_cpus = info->nr_cpus; + dh->nr_cpus = get_nr_cpus(); dh->bitmap_blocks = divideup(info->len_bitmap, dh->block_size); memcpy(&dh->timestamp, &info->timestamp, sizeof(dh->timestamp)); memcpy(&dh->utsname, &info->system_utsname, sizeof(dh->utsname)); @@ -6279,15 +4971,15 @@ write_kdump_header(void) kh.start_pfn = info->split_start_pfn; kh.end_pfn = info->split_end_pfn; } - if (info->offset_note && info->size_note) { + if (has_pt_note()) { /* * Write ELF note section */ kh.offset_note = DISKDUMP_HEADER_BLOCKS * dh->block_size + sizeof(kh); - kh.size_note = info->size_note; + kh.size_note = size_note; - buf = malloc(info->size_note); + buf = malloc(size_note); if (buf == NULL) { ERRMSG("Can't allocate memory for ELF note section. %s\n", strerror(errno)); @@ -6295,26 +4987,27 @@ write_kdump_header(void) } if (!info->flag_sadump) { - if (lseek(info->fd_memory, info->offset_note, SEEK_SET) < 0) { + if (lseek(info->fd_memory, offset_note, SEEK_SET) < 0) { ERRMSG("Can't seek the dump memory(%s). %s\n", info->name_memory, strerror(errno)); goto out; } - if (read(info->fd_memory, buf, info->size_note) != info->size_note) { + if (read(info->fd_memory, buf, size_note) != size_note) { ERRMSG("Can't read the dump memory(%s). %s\n", info->name_memory, strerror(errno)); goto out; } } else { - if (!sadump_read_elf_note(buf, info->size_note)) + if (!sadump_read_elf_note(buf, size_note)) goto out; - } + } if (!write_buffer(info->fd_dumpfile, kh.offset_note, buf, kh.size_note, info->name_dumpfile)) goto out; - if (info->offset_vmcoreinfo && info->size_vmcoreinfo) { + if (has_vmcoreinfo()) { + get_vmcoreinfo(&offset_vmcoreinfo, &size_vmcoreinfo); /* * Set vmcoreinfo data * @@ -6322,9 +5015,9 @@ write_kdump_header(void) * kh.offset_vmcoreinfo points the vmcoreinfo data. */ kh.offset_vmcoreinfo - = info->offset_vmcoreinfo - info->offset_note + = offset_vmcoreinfo - offset_note + kh.offset_note; - kh.size_vmcoreinfo = info->size_vmcoreinfo; + kh.size_vmcoreinfo = size_vmcoreinfo; } } if (!write_buffer(info->fd_dumpfile, dh->block_size, &kh, @@ -6343,32 +5036,6 @@ out: return ret; } -void -print_progress(const char *msg, unsigned long current, unsigned long end) -{ - int progress; - time_t tm; - static time_t last_time = 0; - - if (current < end) { - tm = time(NULL); - if (tm - last_time < 1) - return; - last_time = tm; - progress = current * 100 / end; - } else - progress = 100; - - if (flag_ignore_r_char) { - PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3d %%]\n", - msg, progress); - } else { - PROGRESS_MSG("\r"); - PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3d %%] ", - msg, progress); - } -} - unsigned long long get_num_dumpable(void) { @@ -6384,104 +5051,20 @@ get_num_dumpable(void) return num_dumpable; } -void -split_filter_info(struct filter_info *prev, unsigned long long next_paddr, - size_t size) -{ - struct filter_info *new; - - if ((new = calloc(1, sizeof(struct filter_info))) == NULL) { - ERRMSG("Can't allocate memory to split filter info\n"); - return; - } - new->nullify = prev->nullify; - new->erase_info_idx = prev->erase_info_idx; - new->size_idx = prev->size_idx; - new->paddr = next_paddr; - new->size = size; - new->next = prev->next; - prev->next = new; -} - -void -update_erase_info(struct filter_info *fi) -{ - struct erase_info *ei; - - if (!fi->erase_info_idx) - return; - - ei = &erase_info[fi->erase_info_idx]; - - if (!ei->sizes) { - /* First time, allocate sizes array */ - ei->sizes = calloc(ei->num_sizes, sizeof(long)); - if (!ei->sizes) { - ERRMSG("Can't allocate memory for erase info sizes\n"); - return; - } - } - ei->erased = 1; - if (!fi->nullify) - ei->sizes[fi->size_idx] += fi->size; - else - ei->sizes[fi->size_idx] = -1; -} - -int -extract_filter_info(unsigned long long start_paddr, - unsigned long long end_paddr, - struct filter_info *fl_info) +unsigned long long +get_num_dumpable_cyclic(void) { - struct filter_info *fi = filter_info; - struct filter_info *prev = NULL; - size_t size1, size2; + unsigned long long pfn, num_dumpable=0; - if (!fl_info) - return FALSE; + for (pfn = 0; pfn < info->max_mapnr; pfn++) { + if (!update_cyclic_region(pfn)) + return FALSE; - while (fi) { - if ((fi->paddr >= start_paddr) && (fi->paddr < end_paddr)) { - size1 = end_paddr - fi->paddr; - if (fi->size <= size1) - break; - size2 = fi->size - size1; - fi->size = size1; - split_filter_info(fi, fi->paddr + size1, size2); - break; - } - prev = fi; - fi = fi->next; - } - if (fi) { - *fl_info = *fi; - fl_info->next = NULL; - /* Delete this node */ - if (!prev) - filter_info = fi->next; - else - prev->next = fi->next; - update_erase_info(fi); - free(fi); - return TRUE; + if (is_dumpable_cyclic(info->partial_bitmap2, pfn)) + num_dumpable++; } - return FALSE; -} - -void -filter_data_buffer(unsigned char *buf, unsigned long long paddr, - size_t size) -{ - struct filter_info fl_info; - unsigned char *buf_ptr; - while (extract_filter_info(paddr, paddr + size, &fl_info)) { - buf_ptr = buf + (fl_info.paddr - paddr); - if (fl_info.nullify) - memset(buf_ptr, 0, fl_info.size); - else - memset(buf_ptr, 'X', fl_info.size); - } + return num_dumpable; } int @@ -6531,12 +5114,13 @@ write_elf_pages(struct cache_data *cd_he int i, phnum; long page_size = info->page_size; unsigned long long pfn, pfn_start, pfn_end, paddr, num_excluded; - unsigned long long num_dumpable, num_dumped = 0, per; + unsigned long long num_dumpable, per; unsigned long long memsz, filesz; unsigned long frac_head, frac_tail; off_t off_seg_load, off_memory; Elf64_Phdr load; struct dump_bitmap bitmap2; + struct timeval tv_start; if (!info->flag_elf_dumpfile) return FALSE; @@ -6552,8 +5136,10 @@ write_elf_pages(struct cache_data *cd_he if (!(phnum = get_phnum_memory())) return FALSE; + gettimeofday(&tv_start, NULL); + for (i = 0; i < phnum; i++) { - if (!get_elf_phdr_memory(i, &load)) + if (!get_phdr_memory(i, &load)) return FALSE; if (load.p_type != PT_LOAD) @@ -6705,6 +5291,7 @@ write_elf_pages(struct cache_data *cd_he * print [100 %] */ print_progress(PROGRESS_COPY, num_dumpable, num_dumpable); + print_execution_time(PROGRESS_COPY, &tv_start); PROGRESS_MSG("\n"); return TRUE; @@ -6782,3023 +5369,2130 @@ read_pfn(unsigned long long pfn, unsigne } int -write_kdump_pages(struct cache_data *cd_header, struct cache_data *cd_page) +get_loads_dumpfile_cyclic(void) { - unsigned long long pfn, per, num_dumpable, num_dumped = 0; - unsigned long long start_pfn, end_pfn; - unsigned long size_out; - struct page_desc pd, pd_zero; - off_t offset_data = 0; - struct disk_dump_header *dh = info->dump_header; - unsigned char buf[info->page_size], *buf_out = NULL; - unsigned long len_buf_out; - struct dump_bitmap bitmap2; - const off_t failed = (off_t)-1; - - int ret = FALSE; - - if (info->flag_elf_dumpfile) - return FALSE; - - initialize_2nd_bitmap(&bitmap2); - - len_buf_out = compressBound(info->page_size); - if ((buf_out = malloc(len_buf_out)) == NULL) { - ERRMSG("Can't allocate memory for the compression buffer. %s\n", - strerror(errno)); - goto out; - } - - num_dumpable = get_num_dumpable(); - per = num_dumpable / 100; - - /* - * Calculate the offset of the page data. - */ - cd_header->offset - = (DISKDUMP_HEADER_BLOCKS + dh->sub_hdr_size + dh->bitmap_blocks) - * dh->block_size; - cd_page->offset = cd_header->offset + sizeof(page_desc_t)*num_dumpable; - offset_data = cd_page->offset; - - /* - * Set a fileoffset of Physical Address 0x0. - */ - if (lseek(info->fd_memory, info->offset_load_memory, SEEK_SET) - == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - goto out; - } - - /* - * Write the data of zero-filled page. - */ - if (info->dump_level & DL_EXCLUDE_ZERO) { - pd_zero.size = info->page_size; - pd_zero.flags = 0; - pd_zero.offset = offset_data; - pd_zero.page_flags = 0; - memset(buf, 0, pd_zero.size); - if (!write_cache(cd_page, buf, pd_zero.size)) - goto out; - offset_data += pd_zero.size; - } - if (info->flag_split) { - start_pfn = info->split_start_pfn; - end_pfn = info->split_end_pfn; - } - else { - start_pfn = 0; - end_pfn = info->max_mapnr; - } - for (pfn = start_pfn; pfn < end_pfn; pfn++) { - - if ((num_dumped % per) == 0) - print_progress(PROGRESS_COPY, num_dumped, num_dumpable); - - /* - * Check the excluded page. - */ - if (!is_dumpable(&bitmap2, pfn)) - continue; - - num_dumped++; - - if (!read_pfn(pfn, buf)) - goto out; - - /* - * Exclude the page filled with zeros. - */ - if ((info->dump_level & DL_EXCLUDE_ZERO) - && is_zero_page(buf, info->page_size)) { - if (!write_cache(cd_header, &pd_zero, sizeof(page_desc_t))) - goto out; - pfn_zero++; - continue; - } - /* - * Compress the page data. - */ - size_out = len_buf_out; - if (info->flag_compress - && (compress2(buf_out, &size_out, buf, - info->page_size, Z_BEST_SPEED) == Z_OK) - && (size_out < info->page_size)) { - pd.flags = 1; - pd.size = size_out; - memcpy(buf, buf_out, pd.size); - } else { - pd.flags = 0; - pd.size = info->page_size; - } - pd.page_flags = 0; - pd.offset = offset_data; - offset_data += pd.size; - - /* - * Write the page header. - */ - if (!write_cache(cd_header, &pd, sizeof(page_desc_t))) - goto out; - - /* - * Write the page data. - */ - if (!write_cache(cd_page, buf, pd.size)) - goto out; - } - - /* - * Write the remainder. - */ - if (!write_cache_bufsz(cd_page)) - goto out; - if (!write_cache_bufsz(cd_header)) - goto out; + int i, phnum, num_new_load = 0; + long page_size = info->page_size; + unsigned char buf[info->page_size]; + unsigned long long pfn, pfn_start, pfn_end, num_excluded; + unsigned long long paddr; + unsigned long frac_head, frac_tail; + Elf64_Phdr load; /* - * print [100 %] + * Initialize target region and bitmap. */ - print_progress(PROGRESS_COPY, num_dumpable, num_dumpable); - PROGRESS_MSG("\n"); - - ret = TRUE; -out: - if (buf_out != NULL) - free(buf_out); - - return ret; -} - -/* - * Copy eraseinfo from input dumpfile/vmcore to output dumpfile. - */ -static int -copy_eraseinfo(struct cache_data *cd_eraseinfo) -{ - char *buf = NULL; - int ret = FALSE; - - buf = malloc(info->size_eraseinfo); - if (buf == NULL) { - ERRMSG("Can't allocate memory for erase info section. %s\n", - strerror(errno)); + info->cyclic_start_pfn = 0; + info->cyclic_end_pfn = info->pfn_cyclic; + if (!create_1st_bitmap_cyclic()) + return FALSE; + if (!exclude_unnecessary_pages_cyclic()) return FALSE; - } - if (lseek(info->fd_memory, info->offset_eraseinfo, SEEK_SET) < 0) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - goto out; - } - if (read(info->fd_memory, buf, info->size_eraseinfo) - != info->size_eraseinfo) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - goto out; - } - if (!write_cache(cd_eraseinfo, buf, info->size_eraseinfo)) - goto out; - ret = TRUE; -out: - if (buf) - free(buf); - return ret; -} -static int -update_sub_header(void) -{ - off_t offset; + if (!(phnum = get_phnum_memory())) + return FALSE; - /* seek to kdump sub header offset */ - offset = DISKDUMP_HEADER_BLOCKS * info->page_size; + for (i = 0; i < phnum; i++) { + if (!get_phdr_memory(i, &load)) + return FALSE; + if (load.p_type != PT_LOAD) + continue; - info->sub_header.offset_eraseinfo = info->offset_eraseinfo; - info->sub_header.size_eraseinfo = info->size_eraseinfo; + pfn_start = paddr_to_pfn(load.p_paddr); + pfn_end = paddr_to_pfn(load.p_paddr + load.p_memsz); + frac_head = page_size - (load.p_paddr % page_size); + frac_tail = (load.p_paddr + load.p_memsz) % page_size; - if (!write_buffer(info->fd_dumpfile, offset, &info->sub_header, - sizeof(struct kdump_sub_header), info->name_dumpfile)) - return FALSE; + num_new_load++; + num_excluded = 0; - return TRUE; -} + if (frac_head && (frac_head != page_size)) + pfn_start++; + if (frac_tail) + pfn_end++; -/* - * Traverse through eraseinfo nodes and write it to the o/p dumpfile if the - * node has erased flag set. - */ -int -write_eraseinfo(struct cache_data *cd_page, unsigned long *size_out) -{ - int i, j, obuf_size = 0, ei_size = 0; - int ret = FALSE; - unsigned long size_eraseinfo = 0; - char *obuf = NULL; - char size_str[MAX_SIZE_STR_LEN]; + for (pfn = pfn_start; pfn < pfn_end; pfn++) { + /* + * Update target region and bitmap + */ + if (!is_cyclic_region(pfn)) { + if (!update_cyclic_region(pfn)) + return FALSE; + } - for (i = 1; i < num_erase_info; i++) { - if (!erase_info[i].erased) - continue; - for (j = 0; j < erase_info[i].num_sizes; j++) { - if (erase_info[i].sizes[j] > 0) - sprintf(size_str, "size %ld\n", - erase_info[i].sizes[j]); - else if (erase_info[i].sizes[j] == -1) - sprintf(size_str, "nullify\n"); + if (!is_dumpable_cyclic(info->partial_bitmap2, pfn)) { + num_excluded++; + continue; + } - /* Calculate the required buffer size. */ - ei_size = strlen("erase ") + - strlen(erase_info[i].symbol_expr) + 1 + - strlen(size_str) + - 1; /* - * If obuf is allocated in the previous run and is - * big enough to hold current erase info string then - * reuse it otherwise realloc. + * Exclude zero pages. */ - if (ei_size > obuf_size) { - obuf_size = ei_size; - obuf = realloc(obuf, obuf_size); - if (!obuf) { - ERRMSG("Can't allocate memory for" - " output buffer\n"); + if (info->dump_level & DL_EXCLUDE_ZERO) { + paddr = pfn_to_paddr(pfn); + if (!readmem(PADDR, paddr, buf, page_size)) { + ERRMSG("Can't get the page data(pfn:%llx,max_mapnr:%llx).\n", + pfn, info->max_mapnr); return FALSE; } + if (is_zero_page(buf, page_size)) { + num_excluded++; + continue; + } } - sprintf(obuf, "erase %s %s", erase_info[i].symbol_expr, - size_str); - DEBUG_MSG(obuf); - if (!write_cache(cd_page, obuf, strlen(obuf))) - goto out; - size_eraseinfo += strlen(obuf); + + info->num_dumpable++; + + /* + * If the number of the contiguous pages to be excluded + * is 256 or more, those pages are excluded really. + * And a new PT_LOAD segment is created. + */ + if (num_excluded >= PFN_EXCLUDED) { + num_new_load++; + } + num_excluded = 0; } } + return num_new_load; +} + +int +write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page) +{ + int i, phnum; + long page_size = info->page_size; + unsigned char buf[info->page_size]; + unsigned long long pfn, pfn_start, pfn_end, paddr, num_excluded; + unsigned long long paddr_buf; + unsigned long long num_dumpable, per; + unsigned long long memsz, filesz; + unsigned long frac_head, frac_tail; + off_t off_seg_load, off_memory; + Elf64_Phdr load; + struct timeval tv_start; + + if (!info->flag_elf_dumpfile) + return FALSE; + + num_dumpable = info->num_dumpable; + per = num_dumpable / 100; + + off_seg_load = info->offset_load_dumpfile; + cd_page->offset = info->offset_load_dumpfile; + /* - * Write the remainder. + * Reset counter for debug message. */ - if (!write_cache_bufsz(cd_page)) - goto out; + pfn_zero = pfn_cache = pfn_cache_private = 0; + pfn_user = pfn_free = pfn_hwpoison = 0; + pfn_memhole = info->max_mapnr; + + info->cyclic_start_pfn = 0; + info->cyclic_end_pfn = 0; + if (!update_cyclic_region(0)) + return FALSE; - *size_out = size_eraseinfo; - ret = TRUE; -out: - if (obuf) - free(obuf); + if (!(phnum = get_phnum_memory())) + return FALSE; - return ret; -} + gettimeofday(&tv_start, NULL); -int -write_elf_eraseinfo(struct cache_data *cd_header) -{ - char note[MAX_SIZE_NHDR]; - char buf[ERASEINFO_NOTE_NAME_BYTES + 4]; - unsigned long note_header_size, size_eraseinfo; + for (i = 0; i < phnum; i++) { + if (!get_phdr_memory(i, &load)) + return FALSE; - if (!info->size_eraseinfo) - return TRUE; + if (load.p_type != PT_LOAD) + continue; - DEBUG_MSG("Writing erase info...\n"); + off_memory= load.p_offset; + paddr = load.p_paddr; + pfn_start = paddr_to_pfn(load.p_paddr); + pfn_end = paddr_to_pfn(load.p_paddr + load.p_memsz); + frac_head = page_size - (load.p_paddr % page_size); + frac_tail = (load.p_paddr + load.p_memsz)%page_size; - /* calculate the eraseinfo ELF note offset */ - cd_header->offset = info->offset_note_dumpfile + - roundup(info->size_note, 4); + num_excluded = 0; + memsz = 0; + filesz = 0; + if (frac_head && (frac_head != page_size)) { + memsz = frac_head; + filesz = frac_head; + pfn_start++; + } - /* Write eraseinfo ELF note header. */ - memset(note, 0, sizeof(note)); - if (info->flag_elf64_memory) { - Elf64_Nhdr *nh = (Elf64_Nhdr *)note; + if (frac_tail) + pfn_end++; - note_header_size = sizeof(Elf64_Nhdr); - nh->n_namesz = ERASEINFO_NOTE_NAME_BYTES; - nh->n_descsz = info->size_eraseinfo; - nh->n_type = 0; - } else { - Elf32_Nhdr *nh = (Elf32_Nhdr *)note; + for (pfn = pfn_start; pfn < pfn_end; pfn++) { + /* + * Update target region and partial bitmap if necessary. + */ + if (!update_cyclic_region(pfn)) + return FALSE; - note_header_size = sizeof(Elf32_Nhdr); - nh->n_namesz = ERASEINFO_NOTE_NAME_BYTES; - nh->n_descsz = info->size_eraseinfo; - nh->n_type = 0; - } - if (!write_cache(cd_header, note, note_header_size)) - return FALSE; + if (!is_dumpable_cyclic(info->partial_bitmap2, pfn)) { + num_excluded++; + if ((pfn == pfn_end - 1) && frac_tail) + memsz += frac_tail; + else + memsz += page_size; + continue; + } - /* Write eraseinfo Note name */ - memset(buf, 0, sizeof(buf)); - memcpy(buf, ERASEINFO_NOTE_NAME, ERASEINFO_NOTE_NAME_BYTES); - if (!write_cache(cd_header, buf, - roundup(ERASEINFO_NOTE_NAME_BYTES, 4))) - return FALSE; + /* + * Exclude zero pages. + */ + if (info->dump_level & DL_EXCLUDE_ZERO) { + paddr_buf = pfn_to_paddr(pfn); + if (!readmem(PADDR, paddr_buf, buf, page_size)) { + ERRMSG("Can't get the page data(pfn:%llx max_mapnr:%llx).\n", + pfn, info->max_mapnr); + return FALSE; + } + if (is_zero_page(buf, page_size)) { + pfn_zero++; + num_excluded++; + if ((pfn == pfn_end - 1) && frac_tail) + memsz += frac_tail; + else + memsz += page_size; + continue; + } + } - info->offset_eraseinfo = cd_header->offset; - if (!write_eraseinfo(cd_header, &size_eraseinfo)) - return FALSE; + if ((num_dumped % per) == 0) + print_progress(PROGRESS_COPY, num_dumped, num_dumpable); - /* - * The actual eraseinfo written may be less than pre-calculated size. - * Hence fill up the rest of size with zero's. - */ - if (size_eraseinfo < info->size_eraseinfo) - write_cache_zero(cd_header, - info->size_eraseinfo - size_eraseinfo); + num_dumped++; + + /* + * The dumpable pages are continuous. + */ + if (!num_excluded) { + if ((pfn == pfn_end - 1) && frac_tail) { + memsz += frac_tail; + filesz += frac_tail; + } else { + memsz += page_size; + filesz += page_size; + } + continue; + /* + * If the number of the contiguous pages to be excluded + * is 255 or less, those pages are not excluded. + */ + } else if (num_excluded < PFN_EXCLUDED) { + if ((pfn == pfn_end - 1) && frac_tail) { + memsz += frac_tail; + filesz += (page_size*num_excluded + + frac_tail); + }else { + memsz += page_size; + filesz += (page_size*num_excluded + + page_size); + } + num_excluded = 0; + continue; + } - DEBUG_MSG("offset_eraseinfo: %lx, size_eraseinfo: %ld\n", - info->offset_eraseinfo, info->size_eraseinfo); + /* + * If the number of the contiguous pages to be excluded + * is 256 or more, those pages are excluded really. + * And a new PT_LOAD segment is created. + */ + load.p_memsz = memsz; + load.p_filesz = filesz; + if (load.p_filesz) + load.p_offset = off_seg_load; + else + /* + * If PT_LOAD segment does not have real data + * due to the all excluded pages, the file + * offset is not effective and it should be 0. + */ + load.p_offset = 0; - return TRUE; -} + /* + * Write a PT_LOAD header. + */ + if (!write_elf_phdr(cd_header, &load)) + return FALSE; -int -write_kdump_eraseinfo(struct cache_data *cd_page) -{ - off_t offset_eraseinfo; - unsigned long size_eraseinfo; + /* + * Write a PT_LOAD segment. + */ + if (load.p_filesz) + if (!write_elf_load_segment(cd_page, paddr, + off_memory, load.p_filesz)) + return FALSE; - DEBUG_MSG("Writing erase info...\n"); - offset_eraseinfo = cd_page->offset; + load.p_paddr += load.p_memsz; +#ifdef __x86__ + /* + * FIXME: + * (x86) Fill PT_LOAD headers with appropriate + * virtual addresses. + */ + if (load.p_paddr < MAXMEM) + load.p_vaddr += load.p_memsz; +#else + load.p_vaddr += load.p_memsz; +#endif /* x86 */ + paddr = load.p_paddr; + off_seg_load += load.p_filesz; - /* - * In case of refiltering copy the existing eraseinfo from input - * dumpfile to o/p dumpfile. - */ - if (info->offset_eraseinfo && info->size_eraseinfo) { - if (!copy_eraseinfo(cd_page)) + num_excluded = 0; + memsz = page_size; + filesz = page_size; + } + /* + * Write the last PT_LOAD. + */ + load.p_memsz = memsz; + load.p_filesz = filesz; + load.p_offset = off_seg_load; + + /* + * Write a PT_LOAD header. + */ + if (!write_elf_phdr(cd_header, &load)) return FALSE; - } - /* Initialize eraseinfo offset with new offset value. */ - info->offset_eraseinfo = offset_eraseinfo; + /* + * Write a PT_LOAD segment. + */ + if (load.p_filesz) + if (!write_elf_load_segment(cd_page, paddr, + off_memory, load.p_filesz)) + return FALSE; - if (!write_eraseinfo(cd_page, &size_eraseinfo)) + off_seg_load += load.p_filesz; + } + if (!write_cache_bufsz(cd_header)) + return FALSE; + if (!write_cache_bufsz(cd_page)) return FALSE; - info->size_eraseinfo += size_eraseinfo; - DEBUG_MSG("offset_eraseinfo: %lx, size_eraseinfo: %ld\n", - info->offset_eraseinfo, info->size_eraseinfo); - - if (info->size_eraseinfo) - /* Update the erase info offset and size in kdump sub header */ - if (!update_sub_header()) - return FALSE; + /* + * print [100 %] + */ + print_progress(PROGRESS_COPY, num_dumpable, num_dumpable); + print_execution_time(PROGRESS_COPY, &tv_start); + PROGRESS_MSG("\n"); return TRUE; } int -write_kdump_bitmap(void) +write_kdump_pages(struct cache_data *cd_header, struct cache_data *cd_page) { - struct cache_data bm; - long buf_size; - off_t offset; + unsigned long long pfn, per, num_dumpable; + unsigned long long start_pfn, end_pfn; + unsigned long size_out; + struct page_desc pd, pd_zero; + off_t offset_data = 0; + struct disk_dump_header *dh = info->dump_header; + unsigned char buf[info->page_size], *buf_out = NULL; + unsigned long len_buf_out; + struct dump_bitmap bitmap2; + struct timeval tv_start; + const off_t failed = (off_t)-1; + unsigned long len_buf_out_zlib, len_buf_out_lzo, len_buf_out_snappy; int ret = FALSE; if (info->flag_elf_dumpfile) return FALSE; - bm.fd = info->fd_bitmap; - bm.file_name = info->name_bitmap; - bm.offset = 0; - bm.buf = NULL; - - if ((bm.buf = calloc(1, BUFSIZE_BITMAP)) == NULL) { - ERRMSG("Can't allocate memory for dump bitmap buffer. %s\n", - strerror(errno)); - goto out; - } - offset = info->offset_bitmap1; - buf_size = info->len_bitmap; - - while (buf_size > 0) { - if (buf_size >= BUFSIZE_BITMAP) - bm.cache_size = BUFSIZE_BITMAP; - else - bm.cache_size = buf_size; - - if(!read_cache(&bm)) - goto out; - - if (!write_buffer(info->fd_dumpfile, offset, - bm.buf, bm.cache_size, info->name_dumpfile)) - goto out; - - offset += bm.cache_size; - buf_size -= BUFSIZE_BITMAP; - } - ret = TRUE; -out: - if (bm.buf != NULL) - free(bm.buf); - - return ret; -} - -void -close_vmcoreinfo(void) -{ - if(fclose(info->file_vmcoreinfo) < 0) - ERRMSG("Can't close the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); -} - -void -close_dump_memory(void) -{ - if ((info->fd_memory = close(info->fd_memory)) < 0) - ERRMSG("Can't close the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); -} - -void -close_dump_file(void) -{ - if (info->flag_flatten) - return; + initialize_2nd_bitmap(&bitmap2); - if ((info->fd_dumpfile = close(info->fd_dumpfile)) < 0) - ERRMSG("Can't close the dump file(%s). %s\n", - info->name_dumpfile, strerror(errno)); -} + len_buf_out_zlib = len_buf_out_lzo = len_buf_out_snappy = 0; -void -close_dump_bitmap(void) -{ - if ((info->fd_bitmap = close(info->fd_bitmap)) < 0) - ERRMSG("Can't close the bitmap file(%s). %s\n", - info->name_bitmap, strerror(errno)); - free(info->name_bitmap); - info->name_bitmap = NULL; -} +#ifdef USELZO + lzo_bytep wrkmem; -void -close_kernel_file(void) -{ - if (info->name_vmlinux) { - if ((info->fd_vmlinux = close(info->fd_vmlinux)) < 0) { - ERRMSG("Can't close the kernel file(%s). %s\n", - info->name_vmlinux, strerror(errno)); - } - } - if (info->name_xen_syms) { - if ((info->fd_xen_syms = close(info->fd_xen_syms)) < 0) { - ERRMSG("Can't close the kernel file(%s). %s\n", - info->name_xen_syms, strerror(errno)); - } + if ((wrkmem = malloc(LZO1X_1_MEM_COMPRESS)) == NULL) { + ERRMSG("Can't allocate memory for the working memory. %s\n", + strerror(errno)); + goto out; } -} - -/* - * Close the following files when it generates the vmcoreinfo file. - * - vmlinux - * - vmcoreinfo file - */ -int -close_files_for_generating_vmcoreinfo(void) -{ - close_kernel_file(); - close_vmcoreinfo(); - - return TRUE; -} - -/* - * Close the following file when it rearranges the dump data. - * - dump file - */ -int -close_files_for_rearranging_dumpdata(void) -{ - close_dump_file(); + len_buf_out_lzo = info->page_size + info->page_size / 16 + 64 + 3; +#endif - return TRUE; -} +#ifdef USESNAPPY + len_buf_out_snappy = snappy_max_compressed_length(info->page_size); +#endif -/* - * Close the following files when it creates the dump file. - * - dump mem - * - dump file - * - bit map - * if it reads the vmcoreinfo file - * - vmcoreinfo file - * else - * - vmlinux - */ -int -close_files_for_creating_dumpfile(void) -{ - if (info->max_dump_level > DL_EXCLUDE_ZERO) - close_kernel_file(); + len_buf_out_zlib = compressBound(info->page_size); + + len_buf_out = MAX(len_buf_out_zlib, + MAX(len_buf_out_lzo, + len_buf_out_snappy)); - /* free name for vmcoreinfo */ - if (info->offset_vmcoreinfo && info->size_vmcoreinfo) { - free(info->name_vmcoreinfo); - info->name_vmcoreinfo = NULL; + if ((buf_out = malloc(len_buf_out)) == NULL) { + ERRMSG("Can't allocate memory for the compression buffer. %s\n", + strerror(errno)); + goto out; } - close_dump_memory(); - close_dump_bitmap(); - - return TRUE; -} + num_dumpable = get_num_dumpable(); + per = num_dumpable / 100; -/* - * for Xen extraction - */ -int -get_symbol_info_xen(void) -{ /* - * Common symbol + * Calculate the offset of the page data. */ - SYMBOL_INIT(dom_xen, "dom_xen"); - SYMBOL_INIT(dom_io, "dom_io"); - SYMBOL_INIT(domain_list, "domain_list"); - SYMBOL_INIT(frame_table, "frame_table"); - SYMBOL_INIT(alloc_bitmap, "alloc_bitmap"); - SYMBOL_INIT(max_page, "max_page"); - SYMBOL_INIT(xenheap_phys_end, "xenheap_phys_end"); + cd_header->offset + = (DISKDUMP_HEADER_BLOCKS + dh->sub_hdr_size + dh->bitmap_blocks) + * dh->block_size; + cd_page->offset = cd_header->offset + sizeof(page_desc_t)*num_dumpable; + offset_data = cd_page->offset; /* - * Architecture specific + * Set a fileoffset of Physical Address 0x0. */ - SYMBOL_INIT(pgd_l2, "idle_pg_table_l2"); /* x86 */ - SYMBOL_INIT(pgd_l3, "idle_pg_table_l3"); /* x86-PAE */ - if (SYMBOL(pgd_l3) == NOT_FOUND_SYMBOL) - SYMBOL_INIT(pgd_l3, "idle_pg_table"); /* x86-PAE */ - SYMBOL_INIT(pgd_l4, "idle_pg_table_4"); /* x86_64 */ - if (SYMBOL(pgd_l4) == NOT_FOUND_SYMBOL) - SYMBOL_INIT(pgd_l4, "idle_pg_table"); /* x86_64 */ - - SYMBOL_INIT(xen_heap_start, "xen_heap_start"); /* ia64 */ - SYMBOL_INIT(xen_pstart, "xen_pstart"); /* ia64 */ - SYMBOL_INIT(frametable_pg_dir, "frametable_pg_dir"); /* ia64 */ + if (lseek(info->fd_memory, get_offset_pt_load_memory(), SEEK_SET) + == failed) { + ERRMSG("Can't seek the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + goto out; + } - return TRUE; -} + /* + * Write the data of zero-filled page. + */ + gettimeofday(&tv_start, NULL); + if (info->dump_level & DL_EXCLUDE_ZERO) { + pd_zero.size = info->page_size; + pd_zero.flags = 0; + pd_zero.offset = offset_data; + pd_zero.page_flags = 0; + memset(buf, 0, pd_zero.size); + if (!write_cache(cd_page, buf, pd_zero.size)) + goto out; + offset_data += pd_zero.size; + } + if (info->flag_split) { + start_pfn = info->split_start_pfn; + end_pfn = info->split_end_pfn; + } + else { + start_pfn = 0; + end_pfn = info->max_mapnr; + } -int -get_structure_info_xen(void) -{ - SIZE_INIT(page_info, "page_info"); - OFFSET_INIT(page_info.count_info, "page_info", "count_info"); - /* - * _domain is the first member of union u - */ - OFFSET_INIT(page_info._domain, "page_info", "u"); + for (pfn = start_pfn; pfn < end_pfn; pfn++) { - SIZE_INIT(domain, "domain"); - OFFSET_INIT(domain.domain_id, "domain", "domain_id"); - OFFSET_INIT(domain.next_in_list, "domain", "next_in_list"); + if ((num_dumped % per) == 0) + print_progress(PROGRESS_COPY, num_dumped, num_dumpable); - return TRUE; -} + /* + * Check the excluded page. + */ + if (!is_dumpable(&bitmap2, pfn)) + continue; -int -get_xen_phys_start(void) -{ - off_t offset; - unsigned long xen_phys_start; - const off_t failed = (off_t)-1; + num_dumped++; - if (info->xen_phys_start) - return TRUE; + if (!read_pfn(pfn, buf)) + goto out; - if (info->size_xen_crash_info >= SIZE_XEN_CRASH_INFO_V2) { - offset = info->offset_xen_crash_info + info->size_xen_crash_info - - sizeof(unsigned long) * 2; - if (lseek(info->fd_memory, offset, SEEK_SET) == failed) { - ERRMSG("Can't seek the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; + /* + * Exclude the page filled with zeros. + */ + if ((info->dump_level & DL_EXCLUDE_ZERO) + && is_zero_page(buf, info->page_size)) { + if (!write_cache(cd_header, &pd_zero, sizeof(page_desc_t))) + goto out; + pfn_zero++; + continue; } - if (read(info->fd_memory, &xen_phys_start, sizeof(unsigned long)) - != sizeof(unsigned long)) { - ERRMSG("Can't read the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; + /* + * Compress the page data. + */ + size_out = len_buf_out; + if ((info->flag_compress & DUMP_DH_COMPRESSED_ZLIB) + && ((size_out = len_buf_out), + compress2(buf_out, &size_out, buf, info->page_size, + Z_BEST_SPEED) == Z_OK) + && (size_out < info->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_ZLIB; + pd.size = size_out; + memcpy(buf, buf_out, pd.size); +#ifdef USELZO + } else if (info->flag_lzo_support + && (info->flag_compress & DUMP_DH_COMPRESSED_LZO) + && ((size_out = info->page_size), + lzo1x_1_compress(buf, info->page_size, buf_out, + &size_out, wrkmem) == LZO_E_OK) + && (size_out < info->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_LZO; + pd.size = size_out; + memcpy(buf, buf_out, pd.size); +#endif +#ifdef USESNAPPY + } else if ((info->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) + && ((size_out = len_buf_out_snappy), + snappy_compress((char *)buf, info->page_size, + (char *)buf_out, + (size_t *)&size_out) + == SNAPPY_OK) + && (size_out < info->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_SNAPPY; + pd.size = size_out; + memcpy(buf, buf_out, pd.size); +#endif + } else { + pd.flags = 0; + pd.size = info->page_size; } - info->xen_phys_start = xen_phys_start; - } - - return TRUE; -} + pd.page_flags = 0; + pd.offset = offset_data; + offset_data += pd.size; -int -get_xen_info(void) -{ - unsigned long domain; - unsigned int domain_id; - int num_domain; + /* + * Write the page header. + */ + if (!write_cache(cd_header, &pd, sizeof(page_desc_t))) + goto out; - if (SYMBOL(alloc_bitmap) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of alloc_bitmap.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(alloc_bitmap), &info->alloc_bitmap, - sizeof(info->alloc_bitmap))) { - ERRMSG("Can't get the value of alloc_bitmap.\n"); - return FALSE; - } - if (SYMBOL(max_page) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of max_page.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(max_page), &info->max_page, - sizeof(info->max_page))) { - ERRMSG("Can't get the value of max_page.\n"); - return FALSE; + /* + * Write the page data. + */ + if (!write_cache(cd_page, buf, pd.size)) + goto out; } /* - * Walk through domain_list + * Write the remainder. */ - if (SYMBOL(domain_list) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of domain_list.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(domain_list), &domain, sizeof(domain))){ - ERRMSG("Can't get the value of domain_list.\n"); - return FALSE; - } + if (!write_cache_bufsz(cd_page)) + goto out; + if (!write_cache_bufsz(cd_header)) + goto out; /* - * Get numbers of domain first + * print [100 %] */ - num_domain = 0; - while (domain) { - num_domain++; - if (!readmem(VADDR_XEN, domain + OFFSET(domain.next_in_list), - &domain, sizeof(domain))) { - ERRMSG("Can't get through the domain_list.\n"); - return FALSE; - } - } + print_progress(PROGRESS_COPY, num_dumpable, num_dumpable); + print_execution_time(PROGRESS_COPY, &tv_start); + PROGRESS_MSG("\n"); - if ((info->domain_list = (struct domain_list *) - malloc(sizeof(struct domain_list) * (num_domain + 2))) == NULL) { - ERRMSG("Can't allcate memory for domain_list.\n"); - return FALSE; - } + ret = TRUE; +out: + if (buf_out != NULL) + free(buf_out); +#ifdef USELZO + if (wrkmem != NULL) + free(wrkmem); +#endif - info->num_domain = num_domain + 2; + return ret; +} - if (!readmem(VADDR_XEN, SYMBOL(domain_list), &domain, sizeof(domain))) { - ERRMSG("Can't get the value of domain_list.\n"); - return FALSE; - } - num_domain = 0; - while (domain) { - if (!readmem(VADDR_XEN, domain + OFFSET(domain.domain_id), - &domain_id, sizeof(domain_id))) { - ERRMSG("Can't get the domain_id.\n"); - return FALSE; - } - info->domain_list[num_domain].domain_addr = domain; - info->domain_list[num_domain].domain_id = domain_id; - /* - * pickled_id is set by architecture specific - */ - num_domain++; +int +write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page, + struct page_desc *pd_zero, off_t *offset_data) +{ + unsigned long long pfn, per; + unsigned long long start_pfn, end_pfn; + unsigned long size_out; + struct page_desc pd; + unsigned char buf[info->page_size], *buf_out = NULL; + unsigned long len_buf_out; + const off_t failed = (off_t)-1; + unsigned long len_buf_out_zlib, len_buf_out_lzo, len_buf_out_snappy; - if (!readmem(VADDR_XEN, domain + OFFSET(domain.next_in_list), - &domain, sizeof(domain))) { - ERRMSG("Can't get through the domain_list.\n"); - return FALSE; - } - } + int ret = FALSE; - /* - * special domains - */ - if (SYMBOL(dom_xen) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of dom_xen.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(dom_xen), &domain, sizeof(domain))) { - ERRMSG("Can't get the value of dom_xen.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, domain + OFFSET(domain.domain_id), &domain_id, - sizeof(domain_id))) { - ERRMSG( "Can't get the value of dom_xen domain_id.\n"); + if (info->flag_elf_dumpfile) return FALSE; - } - info->domain_list[num_domain].domain_addr = domain; - info->domain_list[num_domain].domain_id = domain_id; - num_domain++; - if (SYMBOL(dom_io) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of dom_io.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(dom_io), &domain, sizeof(domain))) { - ERRMSG("Can't get the value of dom_io.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, domain + OFFSET(domain.domain_id), &domain_id, - sizeof(domain_id))) { - ERRMSG( "Can't get the value of dom_io domain_id.\n"); - return FALSE; + len_buf_out_zlib = len_buf_out_lzo = len_buf_out_snappy = 0; + +#ifdef USELZO + lzo_bytep wrkmem; + + if ((wrkmem = malloc(LZO1X_1_MEM_COMPRESS)) == NULL) { + ERRMSG("Can't allocate memory for the working memory. %s\n", + strerror(errno)); + goto out; } - info->domain_list[num_domain].domain_addr = domain; - info->domain_list[num_domain].domain_id = domain_id; - /* - * Get architecture specific data - */ - if (!get_xen_info_arch()) - return FALSE; + len_buf_out_lzo = info->page_size + info->page_size / 16 + 64 + 3; +#endif +#ifdef USESNAPPY + len_buf_out_snappy = snappy_max_compressed_length(info->page_size); +#endif - return TRUE; -} + len_buf_out_zlib = compressBound(info->page_size); -void -show_data_xen(void) -{ - int i; + len_buf_out = MAX(len_buf_out_zlib, + MAX(len_buf_out_lzo, + len_buf_out_snappy)); - /* - * Show data for debug - */ - MSG("\n"); - MSG("SYMBOL(dom_xen): %llx\n", SYMBOL(dom_xen)); - MSG("SYMBOL(dom_io): %llx\n", SYMBOL(dom_io)); - MSG("SYMBOL(domain_list): %llx\n", SYMBOL(domain_list)); - MSG("SYMBOL(xen_heap_start): %llx\n", SYMBOL(xen_heap_start)); - MSG("SYMBOL(frame_table): %llx\n", SYMBOL(frame_table)); - MSG("SYMBOL(alloc_bitmap): %llx\n", SYMBOL(alloc_bitmap)); - MSG("SYMBOL(max_page): %llx\n", SYMBOL(max_page)); - MSG("SYMBOL(pgd_l2): %llx\n", SYMBOL(pgd_l2)); - MSG("SYMBOL(pgd_l3): %llx\n", SYMBOL(pgd_l3)); - MSG("SYMBOL(pgd_l4): %llx\n", SYMBOL(pgd_l4)); - MSG("SYMBOL(xenheap_phys_end): %llx\n", SYMBOL(xenheap_phys_end)); - MSG("SYMBOL(xen_pstart): %llx\n", SYMBOL(xen_pstart)); - MSG("SYMBOL(frametable_pg_dir): %llx\n", SYMBOL(frametable_pg_dir)); + if ((buf_out = malloc(len_buf_out)) == NULL) { + ERRMSG("Can't allocate memory for the compression buffer. %s\n", + strerror(errno)); + goto out; + } - MSG("SIZE(page_info): %ld\n", SIZE(page_info)); - MSG("OFFSET(page_info.count_info): %ld\n", OFFSET(page_info.count_info)); - MSG("OFFSET(page_info._domain): %ld\n", OFFSET(page_info._domain)); - MSG("SIZE(domain): %ld\n", SIZE(domain)); - MSG("OFFSET(domain.domain_id): %ld\n", OFFSET(domain.domain_id)); - MSG("OFFSET(domain.next_in_list): %ld\n", OFFSET(domain.next_in_list)); + per = info->num_dumpable / 100; - MSG("\n"); - MSG("xen_phys_start: %lx\n", info->xen_phys_start); - MSG("frame_table_vaddr: %lx\n", info->frame_table_vaddr); - MSG("xen_heap_start: %lx\n", info->xen_heap_start); - MSG("xen_heap_end:%lx\n", info->xen_heap_end); - MSG("alloc_bitmap: %lx\n", info->alloc_bitmap); - MSG("max_page: %lx\n", info->max_page); - MSG("num_domain: %d\n", info->num_domain); - for (i = 0; i < info->num_domain; i++) { - MSG(" %u: %x: %lx\n", info->domain_list[i].domain_id, - info->domain_list[i].pickled_id, - info->domain_list[i].domain_addr); + /* + * Set a fileoffset of Physical Address 0x0. + */ + if (lseek(info->fd_memory, get_offset_pt_load_memory(), SEEK_SET) + == failed) { + ERRMSG("Can't seek the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + goto out; } -} -int -generate_vmcoreinfo_xen(void) -{ - if ((info->page_size = sysconf(_SC_PAGE_SIZE)) <= 0) { - ERRMSG("Can't get the size of page.\n"); - return FALSE; + start_pfn = info->cyclic_start_pfn; + end_pfn = info->cyclic_end_pfn; + + if (info->flag_split) { + if (start_pfn < info->split_start_pfn) + start_pfn = info->split_start_pfn; + if (end_pfn > info->split_end_pfn) + end_pfn = info->split_end_pfn; } - set_dwarf_debuginfo("xen-syms", info->name_xen_syms, info->fd_xen_syms); - if (!get_symbol_info_xen()) - return FALSE; + for (pfn = start_pfn; pfn < end_pfn; pfn++) { - if (!get_structure_info_xen()) - return FALSE; + if ((num_dumped % per) == 0) + print_progress(PROGRESS_COPY, num_dumped, info->num_dumpable); - /* - * write 1st kernel's PAGESIZE - */ - fprintf(info->file_vmcoreinfo, "%s%ld\n", STR_PAGESIZE, - info->page_size); + /* + * Check the excluded page. + */ + if (!is_dumpable_cyclic(info->partial_bitmap2, pfn)) + continue; - /* - * write the symbol of 1st kernel - */ - WRITE_SYMBOL("dom_xen", dom_xen); - WRITE_SYMBOL("dom_io", dom_io); - WRITE_SYMBOL("domain_list", domain_list); - WRITE_SYMBOL("xen_heap_start", xen_heap_start); - WRITE_SYMBOL("frame_table", frame_table); - WRITE_SYMBOL("alloc_bitmap", alloc_bitmap); - WRITE_SYMBOL("max_page", max_page); - WRITE_SYMBOL("pgd_l2", pgd_l2); - WRITE_SYMBOL("pgd_l3", pgd_l3); - WRITE_SYMBOL("pgd_l4", pgd_l4); - WRITE_SYMBOL("xenheap_phys_end", xenheap_phys_end); - WRITE_SYMBOL("xen_pstart", xen_pstart); - WRITE_SYMBOL("frametable_pg_dir", frametable_pg_dir); + num_dumped++; - /* - * write the structure size of 1st kernel - */ - WRITE_STRUCTURE_SIZE("page_info", page_info); - WRITE_STRUCTURE_SIZE("domain", domain); + if (!read_pfn(pfn, buf)) + goto out; - /* - * write the member offset of 1st kernel - */ - WRITE_MEMBER_OFFSET("page_info.count_info", page_info.count_info); - WRITE_MEMBER_OFFSET("page_info._domain", page_info._domain); - WRITE_MEMBER_OFFSET("domain.domain_id", domain.domain_id); - WRITE_MEMBER_OFFSET("domain.next_in_list", domain.next_in_list); + /* + * Exclude the page filled with zeros. + */ + if ((info->dump_level & DL_EXCLUDE_ZERO) + && is_zero_page(buf, info->page_size)) { + if (!write_cache(cd_header, pd_zero, sizeof(page_desc_t))) + goto out; + pfn_zero++; + continue; + } + /* + * Compress the page data. + */ + size_out = len_buf_out; + if ((info->flag_compress & DUMP_DH_COMPRESSED_ZLIB) + && ((size_out = len_buf_out), + compress2(buf_out, &size_out, buf, info->page_size, + Z_BEST_SPEED) == Z_OK) + && (size_out < info->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_ZLIB; + pd.size = size_out; + memcpy(buf, buf_out, pd.size); +#ifdef USELZO + } else if (info->flag_lzo_support + && (info->flag_compress & DUMP_DH_COMPRESSED_LZO) + && ((size_out = info->page_size), + lzo1x_1_compress(buf, info->page_size, buf_out, + &size_out, wrkmem) == LZO_E_OK) + && (size_out < info->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_LZO; + pd.size = size_out; + memcpy(buf, buf_out, pd.size); +#endif +#ifdef USESNAPPY + } else if ((info->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) + && ((size_out = len_buf_out_snappy), + snappy_compress((char *)buf, info->page_size, + (char *)buf_out, + (size_t *)&size_out) + == SNAPPY_OK) + && (size_out < info->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_SNAPPY; + pd.size = size_out; + memcpy(buf, buf_out, pd.size); +#endif + } else { + pd.flags = 0; + pd.size = info->page_size; + } + pd.page_flags = 0; + pd.offset = *offset_data; + *offset_data += pd.size; - return TRUE; + /* + * Write the page header. + */ + if (!write_cache(cd_header, &pd, sizeof(page_desc_t))) + goto out; + + /* + * Write the page data. + */ + if (!write_cache(cd_page, buf, pd.size)) + goto out; + } + + ret = TRUE; +out: + if (buf_out != NULL) + free(buf_out); +#ifdef USELZO + if (wrkmem != NULL) + free(wrkmem); +#endif + + return ret; } -int -read_vmcoreinfo_basic_info_xen(void) +/* + * Copy eraseinfo from input dumpfile/vmcore to output dumpfile. + */ +static int +copy_eraseinfo(struct cache_data *cd_eraseinfo) { - long page_size = FALSE; - char buf[BUFSIZE_FGETS], *endp; - unsigned int i; + char *buf = NULL; + off_t offset; + unsigned long size; + int ret = FALSE; - if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { - ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", - info->name_vmcoreinfo, strerror(errno)); + get_eraseinfo(&offset, &size); + buf = malloc(size); + if (buf == NULL) { + ERRMSG("Can't allocate memory for erase info section. %s\n", + strerror(errno)); return FALSE; } - - while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { - i = strlen(buf); - if (!i) - break; - if (buf[i - 1] == '\n') - buf[i - 1] = '\0'; - if (strncmp(buf, STR_PAGESIZE, strlen(STR_PAGESIZE)) == 0) { - page_size = strtol(buf+strlen(STR_PAGESIZE),&endp,10); - if ((!page_size || page_size == LONG_MAX) - || strlen(endp) != 0) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return FALSE; - } - if (!set_page_size(page_size)) { - ERRMSG("Invalid data in %s: %s", - info->name_vmcoreinfo, buf); - return FALSE; - } - break; - } + if (lseek(info->fd_memory, offset, SEEK_SET) < 0) { + ERRMSG("Can't seek the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + goto out; } - if (!info->page_size) { - ERRMSG("Invalid format in %s", info->name_vmcoreinfo); - return FALSE; + if (read(info->fd_memory, buf, size) != size) { + ERRMSG("Can't read the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + goto out; } - return TRUE; + if (!write_cache(cd_eraseinfo, buf, size)) + goto out; + ret = TRUE; +out: + if (buf) + free(buf); + return ret; } -int -read_vmcoreinfo_xen(void) +static int +update_eraseinfo_of_sub_header(off_t offset_eraseinfo, + unsigned long size_eraseinfo) { - if (!read_vmcoreinfo_basic_info_xen()) - return FALSE; + off_t offset; - READ_SYMBOL("dom_xen", dom_xen); - READ_SYMBOL("dom_io", dom_io); - READ_SYMBOL("domain_list", domain_list); - READ_SYMBOL("xen_heap_start", xen_heap_start); - READ_SYMBOL("frame_table", frame_table); - READ_SYMBOL("alloc_bitmap", alloc_bitmap); - READ_SYMBOL("max_page", max_page); - READ_SYMBOL("pgd_l2", pgd_l2); - READ_SYMBOL("pgd_l3", pgd_l3); - READ_SYMBOL("pgd_l4", pgd_l4); - READ_SYMBOL("xenheap_phys_end", xenheap_phys_end); - READ_SYMBOL("xen_pstart", xen_pstart); - READ_SYMBOL("frametable_pg_dir", frametable_pg_dir); + /* seek to kdump sub header offset */ + offset = DISKDUMP_HEADER_BLOCKS * info->page_size; - READ_STRUCTURE_SIZE("page_info", page_info); - READ_STRUCTURE_SIZE("domain", domain); + info->sub_header.offset_eraseinfo = offset_eraseinfo; + info->sub_header.size_eraseinfo = size_eraseinfo; - READ_MEMBER_OFFSET("page_info.count_info", page_info.count_info); - READ_MEMBER_OFFSET("page_info._domain", page_info._domain); - READ_MEMBER_OFFSET("domain.domain_id", domain.domain_id); - READ_MEMBER_OFFSET("domain.next_in_list", domain.next_in_list); + if (!write_buffer(info->fd_dumpfile, offset, &info->sub_header, + sizeof(struct kdump_sub_header), info->name_dumpfile)) + return FALSE; return TRUE; } +/* + * Traverse through eraseinfo nodes and write it to the o/p dumpfile if the + * node has erased flag set. + */ int -allocated_in_map(unsigned long long pfn) -{ - static unsigned long long cur_idx = -1; - static unsigned long cur_word; - unsigned long long idx; - - idx = pfn / PAGES_PER_MAPWORD; - if (idx != cur_idx) { - if (!readmem(VADDR_XEN, - info->alloc_bitmap + idx * sizeof(unsigned long), - &cur_word, sizeof(cur_word))) { - ERRMSG("Can't access alloc_bitmap.\n"); - return 0; - } - cur_idx = idx; - } - - return !!(cur_word & (1UL << (pfn & (PAGES_PER_MAPWORD - 1)))); -} - -int -is_select_domain(unsigned int id) +write_eraseinfo(struct cache_data *cd_page, unsigned long *size_out) { - int i; + int i, j, obuf_size = 0, ei_size = 0; + int ret = FALSE; + unsigned long size_eraseinfo = 0; + char *obuf = NULL; + char size_str[MAX_SIZE_STR_LEN]; - /* selected domain is fix to dom0 only now !! - (yes... domain_list is not necessary right now, - it can get from "dom0" directly) */ + for (i = 1; i < num_erase_info; i++) { + if (!erase_info[i].erased) + continue; + for (j = 0; j < erase_info[i].num_sizes; j++) { + if (erase_info[i].sizes[j] > 0) + sprintf(size_str, "size %ld\n", + erase_info[i].sizes[j]); + else if (erase_info[i].sizes[j] == -1) + sprintf(size_str, "nullify\n"); - for (i = 0; i < info->num_domain; i++) { - if (info->domain_list[i].domain_id == 0 && - info->domain_list[i].pickled_id == id) - return TRUE; + /* Calculate the required buffer size. */ + ei_size = strlen("erase ") + + strlen(erase_info[i].symbol_expr) + 1 + + strlen(size_str) + + 1; + /* + * If obuf is allocated in the previous run and is + * big enough to hold current erase info string then + * reuse it otherwise realloc. + */ + if (ei_size > obuf_size) { + obuf_size = ei_size; + obuf = realloc(obuf, obuf_size); + if (!obuf) { + ERRMSG("Can't allocate memory for" + " output buffer\n"); + return FALSE; + } + } + sprintf(obuf, "erase %s %s", erase_info[i].symbol_expr, + size_str); + DEBUG_MSG(obuf); + if (!write_cache(cd_page, obuf, strlen(obuf))) + goto out; + size_eraseinfo += strlen(obuf); + } } + /* + * Write the remainder. + */ + if (!write_cache_bufsz(cd_page)) + goto out; - return FALSE; + *size_out = size_eraseinfo; + ret = TRUE; +out: + if (obuf) + free(obuf); + + return ret; } int -exclude_xen_user_domain(void) +write_elf_eraseinfo(struct cache_data *cd_header) { - int i; - unsigned int count_info, _domain; - unsigned long page_info_addr; - unsigned long long pfn, pfn_end; - unsigned long long j, size; - struct pt_load_segment *pls; + char note[MAX_SIZE_NHDR]; + char buf[ERASEINFO_NOTE_NAME_BYTES + 4]; + off_t offset_eraseinfo; + unsigned long note_header_size, size_written, size_note; - /* - * NOTE: the first half of bitmap is not used for Xen extraction - */ - for (i = 0; i < info->num_load_memory; i++) { + if (!info->size_elf_eraseinfo) + return TRUE; - print_progress(PROGRESS_XEN_DOMAIN, i, info->num_load_memory); + DEBUG_MSG("Writing erase info...\n"); - pls = &info->pt_load_segments[i]; - pfn = paddr_to_pfn(pls->phys_start); - pfn_end = paddr_to_pfn(pls->phys_end); - size = pfn_end - pfn; + /* calculate the eraseinfo ELF note offset */ + get_pt_note(NULL, &size_note); + cd_header->offset = info->offset_note_dumpfile + + roundup(size_note, 4); - for (j = 0; pfn < pfn_end; pfn++, j++) { - print_progress(PROGRESS_XEN_DOMAIN, j + (size * i), - size * info->num_load_memory); + /* Write eraseinfo ELF note header. */ + memset(note, 0, sizeof(note)); + if (is_elf64_memory()) { + Elf64_Nhdr *nh = (Elf64_Nhdr *)note; - if (!allocated_in_map(pfn)) { - clear_bit_on_2nd_bitmap(pfn); - continue; - } + note_header_size = sizeof(Elf64_Nhdr); + nh->n_namesz = ERASEINFO_NOTE_NAME_BYTES; + nh->n_descsz = info->size_elf_eraseinfo; + nh->n_type = 0; + } else { + Elf32_Nhdr *nh = (Elf32_Nhdr *)note; - page_info_addr = info->frame_table_vaddr + pfn * SIZE(page_info); - if (!readmem(VADDR_XEN, - page_info_addr + OFFSET(page_info.count_info), - &count_info, sizeof(count_info))) { - clear_bit_on_2nd_bitmap(pfn); - continue; /* page_info may not exist */ - } - if (!readmem(VADDR_XEN, - page_info_addr + OFFSET(page_info._domain), - &_domain, sizeof(_domain))) { - ERRMSG("Can't get page_info._domain.\n"); - return FALSE; - } - /* - * select: - * - anonymous (_domain == 0), or - * - xen heap area, or - * - selected domain page - */ - if (_domain == 0) - continue; - if (info->xen_heap_start <= pfn && pfn < info->xen_heap_end) - continue; - if ((count_info & 0xffff) && is_select_domain(_domain)) - continue; - clear_bit_on_2nd_bitmap(pfn); - } + note_header_size = sizeof(Elf32_Nhdr); + nh->n_namesz = ERASEINFO_NOTE_NAME_BYTES; + nh->n_descsz = info->size_elf_eraseinfo; + nh->n_type = 0; } + if (!write_cache(cd_header, note, note_header_size)) + return FALSE; + + /* Write eraseinfo Note name */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, ERASEINFO_NOTE_NAME, ERASEINFO_NOTE_NAME_BYTES); + if (!write_cache(cd_header, buf, + roundup(ERASEINFO_NOTE_NAME_BYTES, 4))) + return FALSE; + + offset_eraseinfo = cd_header->offset; + if (!write_eraseinfo(cd_header, &size_written)) + return FALSE; /* - * print [100 %] + * The actual eraseinfo written may be less than pre-calculated size. + * Hence fill up the rest of size with zero's. */ - print_progress(PROGRESS_XEN_DOMAIN, info->num_load_memory, info->num_load_memory); + if (size_written < info->size_elf_eraseinfo) + write_cache_zero(cd_header, + info->size_elf_eraseinfo - size_written); + + DEBUG_MSG("offset_eraseinfo: %llx, size_eraseinfo: %ld\n", + (unsigned long long)offset_eraseinfo, info->size_elf_eraseinfo); return TRUE; } int -initial_xen(void) +write_kdump_eraseinfo(struct cache_data *cd_page) { -#ifdef __powerpc__ - MSG("\n"); - MSG("ppc64 xen is not supported.\n"); - return FALSE; -#else - if(!info->flag_elf_dumpfile) { - MSG("Specify '-E' option for Xen.\n"); - MSG("Commandline parameter is invalid.\n"); - MSG("Try `makedumpfile --help' for more information.\n"); - return FALSE; - } -#ifndef __x86_64__ - if (DL_EXCLUDE_ZERO < info->max_dump_level) { - MSG("Dump_level is invalid. It should be 0 or 1.\n"); - MSG("Commandline parameter is invalid.\n"); - MSG("Try `makedumpfile --help' for more information.\n"); - return FALSE; - } -#endif - if (!fallback_to_current_page_size()) - return FALSE; - /* - * Get the debug information for analysis from the vmcoreinfo file - */ - if (info->flag_read_vmcoreinfo) { - if (!read_vmcoreinfo_xen()) - return FALSE; - close_vmcoreinfo(); - /* - * Get the debug information for analysis from the xen-syms file - */ - } else if (info->name_xen_syms) { - set_dwarf_debuginfo("xen-syms", info->name_xen_syms, - info->fd_xen_syms); + off_t offset_eraseinfo; + unsigned long size_eraseinfo, size_written; + + DEBUG_MSG("Writing erase info...\n"); + offset_eraseinfo = cd_page->offset; - if (!get_symbol_info_xen()) - return FALSE; - if (!get_structure_info_xen()) - return FALSE; /* - * Get the debug information for analysis from /proc/vmcore + * In case of refiltering copy the existing eraseinfo from input + * dumpfile to o/p dumpfile. */ - } else { - /* - * Check whether /proc/vmcore contains vmcoreinfo, - * and get both the offset and the size. - */ - if (!info->offset_vmcoreinfo_xen || !info->size_vmcoreinfo_xen){ - if (!info->flag_exclude_xen_dom) - goto out; - - MSG("%s doesn't contain a vmcoreinfo for Xen.\n", - info->name_memory); - MSG("Specify '--xen-syms' option or '--xen-vmcoreinfo' option.\n"); - MSG("Commandline parameter is invalid.\n"); - MSG("Try `makedumpfile --help' for more information.\n"); - return FALSE; - } - /* - * Get the debug information from /proc/vmcore - */ - if (!read_vmcoreinfo_from_vmcore(info->offset_vmcoreinfo_xen, - info->size_vmcoreinfo_xen, TRUE)) + if (has_eraseinfo()) { + get_eraseinfo(NULL, &size_eraseinfo); + if (!copy_eraseinfo(cd_page)) return FALSE; - } - if (!get_xen_phys_start()) - return FALSE; - if (!get_xen_info()) - return FALSE; + } else + size_eraseinfo = 0; - if (message_level & ML_PRINT_DEBUG_MSG) - show_data_xen(); -out: - if (!get_max_mapnr()) + if (!write_eraseinfo(cd_page, &size_written)) return FALSE; + size_eraseinfo += size_written; + DEBUG_MSG("offset_eraseinfo: %llx, size_eraseinfo: %ld\n", + (unsigned long long)offset_eraseinfo, size_eraseinfo); + + if (size_eraseinfo) + /* Update the erase info offset and size in kdump sub header */ + if (!update_eraseinfo_of_sub_header(offset_eraseinfo, + size_eraseinfo)) + return FALSE; + return TRUE; -#endif } -void -print_vtop(void) +int +write_kdump_bitmap(void) { - unsigned long long paddr; + struct cache_data bm; + long buf_size; + off_t offset; - if (!info->vaddr_for_vtop) - return; + int ret = FALSE; - MSG("\n"); - MSG("Translating virtual address %lx to physical address.\n", info->vaddr_for_vtop); + if (info->flag_elf_dumpfile) + return FALSE; - paddr = vaddr_to_paddr(info->vaddr_for_vtop); + bm.fd = info->fd_bitmap; + bm.file_name = info->name_bitmap; + bm.offset = 0; + bm.buf = NULL; - MSG("VIRTUAL PHYSICAL\n"); - MSG("%16lx %llx\n", info->vaddr_for_vtop, paddr); - MSG("\n"); + if ((bm.buf = calloc(1, BUFSIZE_BITMAP)) == NULL) { + ERRMSG("Can't allocate memory for dump bitmap buffer. %s\n", + strerror(errno)); + goto out; + } + offset = info->offset_bitmap1; + buf_size = info->len_bitmap; - info->vaddr_for_vtop = 0; + while (buf_size > 0) { + if (buf_size >= BUFSIZE_BITMAP) + bm.cache_size = BUFSIZE_BITMAP; + else + bm.cache_size = buf_size; - return; + if(!read_cache(&bm)) + goto out; + + if (!write_buffer(info->fd_dumpfile, offset, + bm.buf, bm.cache_size, info->name_dumpfile)) + goto out; + + offset += bm.cache_size; + buf_size -= BUFSIZE_BITMAP; + } + ret = TRUE; +out: + if (bm.buf != NULL) + free(bm.buf); + + return ret; } -void -print_report(void) +int +write_kdump_bitmap_cyclic(void) { - unsigned long long pfn_original, pfn_excluded, shrinking; + off_t offset; + int increment; + int ret = FALSE; - /* - * /proc/vmcore doesn't contain the memory hole area. - */ - pfn_original = info->max_mapnr - pfn_memhole; + increment = divideup(info->cyclic_end_pfn - info->cyclic_start_pfn, BITPERBYTE); - pfn_excluded = pfn_zero + pfn_cache + pfn_cache_private - + pfn_user + pfn_free; - shrinking = (pfn_original - pfn_excluded) * 100; - shrinking = shrinking / pfn_original; + if (info->flag_elf_dumpfile) + return FALSE; - REPORT_MSG("Original pages : 0x%016llx\n", pfn_original); - REPORT_MSG(" Excluded pages : 0x%016llx\n", pfn_excluded); - REPORT_MSG(" Pages filled with zero : 0x%016llx\n", pfn_zero); - REPORT_MSG(" Cache pages : 0x%016llx\n", pfn_cache); - REPORT_MSG(" Cache pages + private : 0x%016llx\n", - pfn_cache_private); - REPORT_MSG(" User process data pages : 0x%016llx\n", pfn_user); - REPORT_MSG(" Free pages : 0x%016llx\n", pfn_free); - REPORT_MSG(" Remaining pages : 0x%016llx\n", - pfn_original - pfn_excluded); - REPORT_MSG(" (The number of pages is reduced to %lld%%.)\n", - shrinking); - REPORT_MSG("Memory Hole : 0x%016llx\n", pfn_memhole); - REPORT_MSG("--------------------------------------------------\n"); - REPORT_MSG("Total pages : 0x%016llx\n", info->max_mapnr); - REPORT_MSG("\n"); + offset = info->offset_bitmap1; + if (!write_buffer(info->fd_dumpfile, offset, + info->partial_bitmap1, increment, info->name_dumpfile)) + goto out; + + offset += info->len_bitmap / 2; + if (!write_buffer(info->fd_dumpfile, offset, + info->partial_bitmap2, increment, info->name_dumpfile)) + goto out; + + info->offset_bitmap1 += increment; + + ret = TRUE; +out: + + return ret; } int -writeout_dumpfile(void) +write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_data *cd_page) { - int ret = FALSE; - struct cache_data cd_header, cd_page; + struct page_desc pd_zero; + off_t offset_data=0; + struct disk_dump_header *dh = info->dump_header; + unsigned char buf[info->page_size]; + unsigned long long pfn; + struct timeval tv_start; - info->flag_nospace = FALSE; + gettimeofday(&tv_start, NULL); - if (!open_dump_file()) - return FALSE; + /* + * Reset counter for debug message. + */ + pfn_zero = pfn_cache = pfn_cache_private = 0; + pfn_user = pfn_free = pfn_hwpoison = 0; + pfn_memhole = info->max_mapnr; - if (info->flag_flatten) { - if (!write_start_flat_header()) + cd_header->offset + = (DISKDUMP_HEADER_BLOCKS + dh->sub_hdr_size + dh->bitmap_blocks) + * dh->block_size; + cd_page->offset = cd_header->offset + sizeof(page_desc_t)*info->num_dumpable; + offset_data = cd_page->offset; + + /* + * Write the data of zero-filled page. + */ + if (info->dump_level & DL_EXCLUDE_ZERO) { + pd_zero.size = info->page_size; + pd_zero.flags = 0; + pd_zero.offset = offset_data; + pd_zero.page_flags = 0; + memset(buf, 0, pd_zero.size); + if (!write_cache(cd_page, buf, pd_zero.size)) return FALSE; + offset_data += pd_zero.size; } - if (!prepare_cache_data(&cd_header)) - return FALSE; - if (!prepare_cache_data(&cd_page)) { - free_cache_data(&cd_header); + /* + * Write pages and bitmap cyclically. + */ + info->cyclic_start_pfn = 0; + info->cyclic_end_pfn = 0; + for (pfn = 0; pfn < info->max_mapnr; pfn++) { + if (is_cyclic_region(pfn)) + continue; + + if (!update_cyclic_region(pfn)) + return FALSE; + + if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero, &offset_data)) + return FALSE; + + if (!write_kdump_bitmap_cyclic()) + return FALSE; + } + + /* + * Write the remainder. + */ + if (!write_cache_bufsz(cd_page)) + return FALSE; + if (!write_cache_bufsz(cd_header)) return FALSE; - } - if (info->flag_elf_dumpfile) { - if (!write_elf_header(&cd_header)) - goto out; - if (!write_elf_pages(&cd_header, &cd_page)) - goto out; - if (!write_elf_eraseinfo(&cd_header)) - goto out; - } else { - if (!write_kdump_header()) - goto out; - if (!write_kdump_pages(&cd_header, &cd_page)) - goto out; - if (!write_kdump_eraseinfo(&cd_page)) - goto out; - if (!write_kdump_bitmap()) - goto out; - } - if (info->flag_flatten) { - if (!write_end_flat_header()) - goto out; - } - ret = TRUE; -out: - free_cache_data(&cd_header); - free_cache_data(&cd_page); + /* + * print [100 %] + */ + print_progress(PROGRESS_COPY, num_dumped, info->num_dumpable); + print_execution_time(PROGRESS_COPY, &tv_start); + PROGRESS_MSG("\n"); - close_dump_file(); + return TRUE; +} + +void +close_vmcoreinfo(void) +{ + if(fclose(info->file_vmcoreinfo) < 0) + ERRMSG("Can't close the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); +} - if ((ret == FALSE) && info->flag_nospace) - return NOSPACE; - else - return ret; +void +close_dump_memory(void) +{ + if ((info->fd_memory = close(info->fd_memory)) < 0) + ERRMSG("Can't close the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); } -int -setup_splitting(void) +void +close_dump_file(void) { - int i; - unsigned long long j, pfn_per_dumpfile; - unsigned long long start_pfn, end_pfn; - unsigned long long num_dumpable = get_num_dumpable(); - struct dump_bitmap bitmap2; + if (info->flag_flatten) + return; - if (info->num_dumpfile <= 1) - return FALSE; + if ((info->fd_dumpfile = close(info->fd_dumpfile)) < 0) + ERRMSG("Can't close the dump file(%s). %s\n", + info->name_dumpfile, strerror(errno)); +} - initialize_2nd_bitmap(&bitmap2); +void +close_dump_bitmap(void) +{ + if ((info->fd_bitmap = close(info->fd_bitmap)) < 0) + ERRMSG("Can't close the bitmap file(%s). %s\n", + info->name_bitmap, strerror(errno)); + free(info->name_bitmap); + info->name_bitmap = NULL; +} - pfn_per_dumpfile = num_dumpable / info->num_dumpfile; - start_pfn = end_pfn = 0; - for (i = 0; i < info->num_dumpfile; i++) { - start_pfn = end_pfn; - if (i == (info->num_dumpfile - 1)) { - end_pfn = info->max_mapnr; - } else { - for (j = 0; j < pfn_per_dumpfile; end_pfn++) { - if (is_dumpable(&bitmap2, end_pfn)) - j++; - } +void +close_kernel_file(void) +{ + if (info->name_vmlinux) { + if ((info->fd_vmlinux = close(info->fd_vmlinux)) < 0) { + ERRMSG("Can't close the kernel file(%s). %s\n", + info->name_vmlinux, strerror(errno)); + } + } + if (info->name_xen_syms) { + if ((info->fd_xen_syms = close(info->fd_xen_syms)) < 0) { + ERRMSG("Can't close the kernel file(%s). %s\n", + info->name_xen_syms, strerror(errno)); } - SPLITTING_START_PFN(i) = start_pfn; - SPLITTING_END_PFN(i) = end_pfn; } - - return TRUE; } /* - * This function is for creating split dumpfiles by multiple - * processes. Each child process should re-open a /proc/vmcore - * file, because it prevents each other from affectting the file - * offset due to read(2) call. + * Close the following files when it generates the vmcoreinfo file. + * - vmlinux + * - vmcoreinfo file */ int -reopen_dump_memory() +close_files_for_generating_vmcoreinfo(void) { - close_dump_memory(); + close_kernel_file(); + + close_vmcoreinfo(); - if ((info->fd_memory = open(info->name_memory, O_RDONLY)) < 0) { - ERRMSG("Can't open the dump memory(%s). %s\n", - info->name_memory, strerror(errno)); - return FALSE; - } return TRUE; } +/* + * Close the following file when it rearranges the dump data. + * - dump file + */ int -get_next_dump_level(int index) +close_files_for_rearranging_dumpdata(void) { - if (info->num_dump_level <= index) - return -1; + close_dump_file(); - return info->array_dump_level[index]; + return TRUE; } +/* + * Close the following files when it creates the dump file. + * - dump mem + * - bit map + * if it reads the vmcoreinfo file + * - vmcoreinfo file + * else + * - vmlinux + */ int -delete_dumpfile(void) +close_files_for_creating_dumpfile(void) { - int i; - - if (info->flag_flatten) - return TRUE; + if (info->max_dump_level > DL_EXCLUDE_ZERO) + close_kernel_file(); - if (info->flag_split) { - for (i = 0; i < info->num_dumpfile; i++) - unlink(SPLITTING_DUMPFILE(i)); - } else { - unlink(info->name_dumpfile); + /* free name for vmcoreinfo */ + if (has_vmcoreinfo()) { + free(info->name_vmcoreinfo); + info->name_vmcoreinfo = NULL; } + close_dump_memory(); + + close_dump_bitmap(); + return TRUE; } +/* + * for Xen extraction + */ int -writeout_multiple_dumpfiles(void) +get_symbol_info_xen(void) { - int i, status, ret = TRUE; - pid_t pid; - pid_t array_pid[info->num_dumpfile]; - - if (!setup_splitting()) - return FALSE; - - for (i = 0; i < info->num_dumpfile; i++) { - if ((pid = fork()) < 0) { - return FALSE; - - } else if (pid == 0) { /* Child */ - info->name_dumpfile = SPLITTING_DUMPFILE(i); - info->fd_bitmap = SPLITTING_FD_BITMAP(i); - info->split_start_pfn = SPLITTING_START_PFN(i); - info->split_end_pfn = SPLITTING_END_PFN(i); - - if (!reopen_dump_memory()) - exit(1); - if ((status = writeout_dumpfile()) == FALSE) - exit(1); - else if (status == NOSPACE) - exit(2); - exit(0); - } - array_pid[i] = pid; - } - for (i = 0; i < info->num_dumpfile; i++) { - waitpid(array_pid[i], &status, WUNTRACED); - if (!WIFEXITED(status) || WEXITSTATUS(status) == 1) { - ERRMSG("Child process(%d) finished imcompletely.(%d)\n", - array_pid[i], status); - ret = FALSE; - } else if ((ret == TRUE) && (WEXITSTATUS(status) == 2)) - ret = NOSPACE; - } - return ret; -} + /* + * Common symbol + */ + SYMBOL_INIT(dom_xen, "dom_xen"); + SYMBOL_INIT(dom_io, "dom_io"); + SYMBOL_INIT(domain_list, "domain_list"); + SYMBOL_INIT(frame_table, "frame_table"); + SYMBOL_INIT(alloc_bitmap, "alloc_bitmap"); + SYMBOL_INIT(max_page, "max_page"); + SYMBOL_INIT(xenheap_phys_end, "xenheap_phys_end"); -static unsigned int -get_num_modules(unsigned long head, unsigned int *num) -{ - unsigned long cur; - unsigned int num_modules = 0; + /* + * Architecture specific + */ + SYMBOL_INIT(pgd_l2, "idle_pg_table_l2"); /* x86 */ + SYMBOL_INIT(pgd_l3, "idle_pg_table_l3"); /* x86-PAE */ + if (SYMBOL(pgd_l3) == NOT_FOUND_SYMBOL) + SYMBOL_INIT(pgd_l3, "idle_pg_table"); /* x86-PAE */ + SYMBOL_INIT(pgd_l4, "idle_pg_table_4"); /* x86_64 */ + if (SYMBOL(pgd_l4) == NOT_FOUND_SYMBOL) + SYMBOL_INIT(pgd_l4, "idle_pg_table"); /* x86_64 */ - if (!num) - return FALSE; + SYMBOL_INIT(xen_heap_start, "xen_heap_start"); /* ia64 */ + SYMBOL_INIT(xen_pstart, "xen_pstart"); /* ia64 */ + SYMBOL_INIT(frametable_pg_dir, "frametable_pg_dir"); /* ia64 */ - if (!readmem(VADDR, head + OFFSET(list_head.next), &cur, sizeof cur)) { - ERRMSG("Can't get next list_head.\n"); - return FALSE; - } - while (cur != head) { - num_modules++; - if (!readmem(VADDR, cur + OFFSET(list_head.next), - &cur, sizeof cur)) { - ERRMSG("Can't get next list_head.\n"); - return FALSE; - } - } - *num = num_modules; return TRUE; } -static void -free_symbol_info(struct module_info *module) -{ - int i; - - if (module->num_syms) { - for (i = 1; i < module->num_syms; i++) - if (module->sym_info[i].name) - free(module->sym_info[i].name); - free(module->sym_info); - } -} - -static void -clean_module_symbols(void) +int +get_structure_info_xen(void) { - int i; + SIZE_INIT(page_info, "page_info"); + OFFSET_INIT(page_info.count_info, "page_info", "count_info"); + OFFSET_INIT(page_info._domain, "page_info", "_domain"); - for (i = 0; i < mod_st.num_modules; i++) - free_symbol_info(&mod_st.modules[i]); + SIZE_INIT(domain, "domain"); + OFFSET_INIT(domain.domain_id, "domain", "domain_id"); + OFFSET_INIT(domain.next_in_list, "domain", "next_in_list"); - if (mod_st.num_modules) { - free(mod_st.modules); - mod_st.modules = NULL; - mod_st.num_modules = 0; - } + return TRUE; } -static int -__load_module_symbol(struct module_info *modules, unsigned long addr_module) +int +init_xen_crash_info(void) { - int ret = FALSE; - unsigned int nsym; - unsigned long symtab, strtab; - unsigned long mod_base, mod_init; - unsigned int mod_size, mod_init_size; - unsigned char *module_struct_mem = NULL; - unsigned char *module_core_mem = NULL; - unsigned char *module_init_mem = NULL; - unsigned char *symtab_mem; - char *module_name, *strtab_mem, *nameptr; - unsigned int num_symtab; - - /* Allocate buffer to read struct module data from vmcore. */ - if ((module_struct_mem = calloc(1, SIZE(module))) == NULL) { - ERRMSG("Failed to allocate buffer for module\n"); - return FALSE; - } - if (!readmem(VADDR, addr_module, module_struct_mem, - SIZE(module))) { - ERRMSG("Can't get module info.\n"); - goto out; - } - - module_name = (char *)(module_struct_mem + OFFSET(module.name)); - if (strlen(module_name) < MOD_NAME_LEN) - strcpy(modules->name, module_name); - else - strncpy(modules->name, module_name, MOD_NAME_LEN-1); - - mod_init = ULONG(module_struct_mem + - OFFSET(module.module_init)); - mod_init_size = UINT(module_struct_mem + - OFFSET(module.init_size)); - mod_base = ULONG(module_struct_mem + - OFFSET(module.module_core)); - mod_size = UINT(module_struct_mem + - OFFSET(module.core_size)); - - DEBUG_MSG("Module: %s, Base: 0x%lx, Size: %u\n", - module_name, mod_base, mod_size); - if (mod_init_size > 0) { - module_init_mem = calloc(1, mod_init_size); - if (module_init_mem == NULL) { - ERRMSG("Can't allocate memory for module " - "init\n"); - goto out; - } - if (!readmem(VADDR, mod_init, module_init_mem, - mod_init_size)) { - ERRMSG("Can't access module init in memory.\n"); - goto out; - } - } + off_t offset_xen_crash_info; + unsigned long size_xen_crash_info; + void *buf; - if ((module_core_mem = calloc(1, mod_size)) == NULL) { - ERRMSG("Can't allocate memory for module\n"); - goto out; - } - if (!readmem(VADDR, mod_base, module_core_mem, mod_size)) { - ERRMSG("Can't access module in memory.\n"); - goto out; + get_xen_crash_info(&offset_xen_crash_info, &size_xen_crash_info); + if (!size_xen_crash_info) { + info->xen_crash_info_v = -1; + return TRUE; /* missing info is non-fatal */ } - num_symtab = UINT(module_struct_mem + - OFFSET(module.num_symtab)); - if (!num_symtab) { - ERRMSG("%s: Symbol info not available\n", module_name); - goto out; + if (size_xen_crash_info < sizeof(xen_crash_info_com_t)) { + ERRMSG("Xen crash info too small (%lu bytes).\n", + size_xen_crash_info); + return FALSE; } - modules->num_syms = num_symtab; - DEBUG_MSG("num_sym: %d\n", num_symtab); - - symtab = ULONG(module_struct_mem + OFFSET(module.symtab)); - strtab = ULONG(module_struct_mem + OFFSET(module.strtab)); - /* check if symtab and strtab are inside the module space. */ - if (!IN_RANGE(symtab, mod_base, mod_size) && - !IN_RANGE(symtab, mod_init, mod_init_size)) { - ERRMSG("%s: module symtab is outseide of module " - "address space\n", module_name); - goto out; + buf = malloc(size_xen_crash_info); + if (!buf) { + ERRMSG("Can't allocate note (%lu bytes). %s\n", + size_xen_crash_info, strerror(errno)); + return FALSE; } - if (IN_RANGE(symtab, mod_base, mod_size)) - symtab_mem = module_core_mem + (symtab - mod_base); - else - symtab_mem = module_init_mem + (symtab - mod_init); - if (!IN_RANGE(strtab, mod_base, mod_size) && - !IN_RANGE(strtab, mod_init, mod_init_size)) { - ERRMSG("%s: module strtab is outseide of module " - "address space\n", module_name); - goto out; + if (lseek(info->fd_memory, offset_xen_crash_info, SEEK_SET) < 0) { + ERRMSG("Can't seek the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + return FALSE; } - if (IN_RANGE(strtab, mod_base, mod_size)) - strtab_mem = (char *)(module_core_mem - + (strtab - mod_base)); - else - strtab_mem = (char *)(module_init_mem - + (strtab - mod_init)); - - modules->sym_info = calloc(num_symtab, sizeof(struct symbol_info)); - if (modules->sym_info == NULL) { - ERRMSG("Can't allocate memory to store sym info\n"); - goto out; + if (read(info->fd_memory, buf, size_xen_crash_info) + != size_xen_crash_info) { + ERRMSG("Can't read the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + return FALSE; } - /* symbols starts from 1 */ - for (nsym = 1; nsym < num_symtab; nsym++) { - Elf32_Sym *sym32; - Elf64_Sym *sym64; - /* If case of ELF vmcore then the word size can be - * determined using info->flag_elf64_memory flag. - * But in case of kdump-compressed dump, kdump header - * does not carry word size info. May be in future - * this info will be available in kdump header. - * Until then, in order to make this logic work on both - * situation we depend on pointer_size that is - * extracted from vmlinux dwarf information. - */ - if ((get_pointer_size() * 8) == 64) { - sym64 = (Elf64_Sym *) (symtab_mem - + (nsym * sizeof(Elf64_Sym))); - modules->sym_info[nsym].value = - (unsigned long long) sym64->st_value; - nameptr = strtab_mem + sym64->st_name; - } else { - sym32 = (Elf32_Sym *) (symtab_mem - + (nsym * sizeof(Elf32_Sym))); - modules->sym_info[nsym].value = - (unsigned long long) sym32->st_value; - nameptr = strtab_mem + sym32->st_name; - } - if (strlen(nameptr)) - modules->sym_info[nsym].name = strdup(nameptr); - DEBUG_MSG("\t[%d] %llx %s\n", nsym, - modules->sym_info[nsym].value, nameptr); - } - ret = TRUE; -out: - free(module_struct_mem); - free(module_core_mem); - free(module_init_mem); + info->xen_crash_info.com = buf; + if (size_xen_crash_info >= sizeof(xen_crash_info_v2_t)) + info->xen_crash_info_v = 2; + else if (size_xen_crash_info >= sizeof(xen_crash_info_t)) + info->xen_crash_info_v = 1; + else + info->xen_crash_info_v = 0; - return ret; + return TRUE; } -static int -load_module_symbols(void) +int +get_xen_info(void) { - unsigned long head, cur, cur_module; - struct module_info *modules = NULL; - unsigned int i = 0; + unsigned long domain; + unsigned int domain_id; + int num_domain; - head = SYMBOL(modules); - if (!get_num_modules(head, &mod_st.num_modules) || - !mod_st.num_modules) { - ERRMSG("Can't get module count\n"); + /* + * Get architecture specific basic data + */ + if (!get_xen_basic_info_arch()) return FALSE; + + if (!info->xen_crash_info.com || + info->xen_crash_info.com->xen_major_version < 4) { + if (SYMBOL(alloc_bitmap) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of alloc_bitmap.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(alloc_bitmap), &info->alloc_bitmap, + sizeof(info->alloc_bitmap))) { + ERRMSG("Can't get the value of alloc_bitmap.\n"); + return FALSE; + } + if (SYMBOL(max_page) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of max_page.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(max_page), &info->max_page, + sizeof(info->max_page))) { + ERRMSG("Can't get the value of max_page.\n"); + return FALSE; + } } - mod_st.modules = calloc(mod_st.num_modules, - sizeof(struct module_info)); - if (!mod_st.modules) { - ERRMSG("Can't allocate memory for module info\n"); + + /* + * Walk through domain_list + */ + if (SYMBOL(domain_list) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of domain_list.\n"); return FALSE; } - modules = mod_st.modules; - - if (!readmem(VADDR, head + OFFSET(list_head.next), &cur, sizeof cur)) { - ERRMSG("Can't get next list_head.\n"); + if (!readmem(VADDR_XEN, SYMBOL(domain_list), &domain, sizeof(domain))){ + ERRMSG("Can't get the value of domain_list.\n"); return FALSE; } - /* Travese the list and read module symbols */ - while (cur != head) { - cur_module = cur - OFFSET(module.list); - - if (!__load_module_symbol(&modules[i], cur_module)) - return FALSE; - - if (!readmem(VADDR, cur + OFFSET(list_head.next), - &cur, sizeof cur)) { - ERRMSG("Can't get next list_head.\n"); + /* + * Get numbers of domain first + */ + num_domain = 0; + while (domain) { + num_domain++; + if (!readmem(VADDR_XEN, domain + OFFSET(domain.next_in_list), + &domain, sizeof(domain))) { + ERRMSG("Can't get through the domain_list.\n"); return FALSE; } - i++; - } while (cur != head); - return TRUE; -} - -void -free_config_entry(struct config_entry *ce) -{ - struct config_entry *p; - - while(ce) { - p = ce; - ce = p->next; - if (p->name) - free(p->name); - if (p->type_name) - free(p->type_name); - if (p->symbol_expr) - free(p->symbol_expr); - free(p); } -} -void -free_config(struct config *config) -{ - int i; - if (config) { - if (config->module_name) - free(config->module_name); - for (i = 0; i < config->num_filter_symbols; i++) { - if (config->filter_symbol[i]) - free_config_entry(config->filter_symbol[i]); - if (config->size_symbol[i]) - free_config_entry(config->size_symbol[i]); - } - if (config->filter_symbol) - free(config->filter_symbol); - if (config->size_symbol) - free(config->size_symbol); - free(config); + if ((info->domain_list = (struct domain_list *) + malloc(sizeof(struct domain_list) * (num_domain + 2))) == NULL) { + ERRMSG("Can't allocate memory for domain_list.\n"); + return FALSE; } -} -void -print_config_entry(struct config_entry *ce) -{ - while (ce) { - DEBUG_MSG("Name: %s\n", ce->name); - DEBUG_MSG("Type Name: %s, ", ce->type_name); - DEBUG_MSG("flag: %x, ", ce->flag); - DEBUG_MSG("Type flag: %lx, ", ce->type_flag); - DEBUG_MSG("sym_addr: %llx, ", ce->sym_addr); - DEBUG_MSG("addr: %lx, ", ce->addr); - DEBUG_MSG("offset: %lx, ", ce->offset); - DEBUG_MSG("size: %zd\n", ce->size); + info->num_domain = num_domain + 2; - ce = ce->next; + if (!readmem(VADDR_XEN, SYMBOL(domain_list), &domain, sizeof(domain))) { + ERRMSG("Can't get the value of domain_list.\n"); + return FALSE; } -} - -/* - * Read the non-terminal's which are in the form of [.member[...]] - */ -struct config_entry * -create_config_entry(const char *token, unsigned short flag, int line) -{ - struct config_entry *ce = NULL, *ptr, *prev_ce; - char *str, *cur, *next; - long len; - int depth = 0; - - if (!token) - return NULL; - - cur = str = strdup(token); - prev_ce = ptr = NULL; - while (cur != NULL) { - if ((next = strchr(cur, '.')) != NULL) { - *next++ = '\0'; - } - if (!strlen(cur)) { - cur = next; - continue; + num_domain = 0; + while (domain) { + if (!readmem(VADDR_XEN, domain + OFFSET(domain.domain_id), + &domain_id, sizeof(domain_id))) { + ERRMSG("Can't get the domain_id.\n"); + return FALSE; } + info->domain_list[num_domain].domain_addr = domain; + info->domain_list[num_domain].domain_id = domain_id; + /* + * pickled_id is set by architecture specific + */ + num_domain++; - if ((ptr = calloc(1, sizeof(struct config_entry))) == NULL) { - ERRMSG("Can't allocate memory for config_entry\n"); - goto err_out; - } - ptr->line = line; - ptr->flag |= flag; - if (depth == 0) { - /* First node is always a symbol name */ - ptr->flag |= SYMBOL_ENTRY; - } - if (flag & ITERATION_ENTRY) { - /* Max depth for iteration entry is 1 */ - if (depth > 0) { - ERRMSG("Config error at %d: Invalid iteration " - "variable entry.\n", line); - goto err_out; - } - ptr->name = strdup(cur); - } - if (flag & (FILTER_ENTRY | LIST_ENTRY)) { - ptr->name = strdup(cur); - } - if (flag & SIZE_ENTRY) { - char ch = '\0'; - int n = 0; - /* See if absolute length is provided */ - if ((depth == 0) && - ((n = sscanf(cur, "%zd%c", &len, &ch)) > 0)) { - if (len < 0) { - ERRMSG("Config error at %d: size " - "value must be positive.\n", - line); - goto err_out; - } - ptr->size = len; - ptr->flag |= ENTRY_RESOLVED; - if (n == 2) { - /* Handle suffix. - * K = Kilobytes - * M = Megabytes - */ - switch (ch) { - case 'M': - case 'm': - ptr->size *= 1024; - case 'K': - case 'k': - ptr->size *= 1024; - break; - } - } - } - else - ptr->name = strdup(cur); - } - if (prev_ce) { - prev_ce->next = ptr; - prev_ce = ptr; + if (!readmem(VADDR_XEN, domain + OFFSET(domain.next_in_list), + &domain, sizeof(domain))) { + ERRMSG("Can't get through the domain_list.\n"); + return FALSE; } - else - ce = prev_ce = ptr; - cur = next; - depth++; - ptr = NULL; } - free(str); - return ce; -err_out: - if (ce) - free_config_entry(ce); - if (ptr) - free_config_entry(ptr); - free(str); - return NULL; -} - -int -is_module_loaded(char *mod_name) -{ - if (!strcmp(mod_name, "vmlinux") || get_loaded_module(mod_name)) - return TRUE; - return FALSE; -} - -/* - * read filter config file and return each string token. If the parameter - * expected_token is non-NULL, then return the current token if it matches - * with expected_token otherwise save the current token and return NULL. - * At start of every module section filter_config.new_section is set to 1 and - * subsequent function invocations return NULL untill filter_config.new_section - * is reset to 0 by passing @flag = CONFIG_NEW_CMD (0x02). - * - * Parameters: - * @expected_token INPUT - * Token string to match with currnet token. - * =NULL - return the current available token. - * - * @flag INPUT - * =0x01 - Skip to next module section. - * =0x02 - Treat the next token as next filter command and reset. - * - * @line OUTPUT - * Line number of current token in filter config file. - * - * @cur_mod OUTPUT - * Points to current module section name on non-NULL return value. - * - * @eof OUTPUT - * set to -1 when end of file is reached. - * set to -2 when end of section is reached. - */ -static char * -get_config_token(char *expected_token, unsigned char flag, int *line, - char **cur_mod, int *eof) -{ - char *p; - struct filter_config *fc = &filter_config; - int skip = flag & CONFIG_SKIP_SECTION; - - if (!fc->file_filterconfig) - return NULL; - - if (eof) - *eof = 0; - - /* - * set token and saved_token to NULL if skip module section is set - * to 1. - */ - if (skip) { - fc->token = NULL; - fc->saved_token = NULL; - } - - if (fc->saved_token) { - fc->token = fc->saved_token; - fc->saved_token = NULL; - } - else if (fc->token) - fc->token = strtok(NULL, " "); - - /* Read next line if we are done all tokens from previous line */ - while (!fc->token && fgets(config_buf, sizeof(config_buf), - fc->file_filterconfig)) { - if ((p = strchr(config_buf, '\n'))) { - *p = '\0'; - fc->line_count++; - } - if ((p = strchr(config_buf, '#'))) { - *p = '\0'; - } - /* replace all tabs with spaces */ - for (p = config_buf; *p != '\0'; p++) - if (*p == '\t') - *p = ' '; - if (config_buf[0] == '[') { - /* module section entry */ - p = strchr(config_buf, ']'); - if (!p) { - ERRMSG("Config error at %d: Invalid module " - "section entry.\n", fc->line_count); - /* skip to next valid module section */ - skip = 1; - } - else { - /* - * Found the valid module section. Reset the - * skip flag. - */ - *p = '\0'; - if (fc->cur_module) - free(fc->cur_module); - fc->cur_module = strdup(&config_buf[1]); - skip = 0; - fc->new_section = 1; - } - continue; - } - /* - * If symbol info for current module is not loaded then - * skip to next module section. - */ - if (skip || - (fc->cur_module && !is_module_loaded(fc->cur_module))) - continue; - - fc->token = strtok(config_buf, " "); + /* + * special domains + */ + if (SYMBOL(dom_xen) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of dom_xen.\n"); + return FALSE; } - if (!fc->token) { - if (eof) - *eof = -1; - return NULL; - } - if (fc->new_section && !(flag & CONFIG_NEW_CMD)) { - fc->saved_token = fc->token; - if (eof) - *eof = -2; - return NULL; + if (!readmem(VADDR_XEN, SYMBOL(dom_xen), &domain, sizeof(domain))) { + ERRMSG("Can't get the value of dom_xen.\n"); + return FALSE; } - else - fc->new_section = 0; + if (!readmem(VADDR_XEN, domain + OFFSET(domain.domain_id), &domain_id, + sizeof(domain_id))) { + ERRMSG( "Can't get the value of dom_xen domain_id.\n"); + return FALSE; + } + info->domain_list[num_domain].domain_addr = domain; + info->domain_list[num_domain].domain_id = domain_id; + num_domain++; - if (cur_mod) - *cur_mod = fc->cur_module; + if (SYMBOL(dom_io) == NOT_FOUND_SYMBOL) { + ERRMSG("Can't get the symbol of dom_io.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, SYMBOL(dom_io), &domain, sizeof(domain))) { + ERRMSG("Can't get the value of dom_io.\n"); + return FALSE; + } + if (!readmem(VADDR_XEN, domain + OFFSET(domain.domain_id), &domain_id, + sizeof(domain_id))) { + ERRMSG( "Can't get the value of dom_io domain_id.\n"); + return FALSE; + } + info->domain_list[num_domain].domain_addr = domain; + info->domain_list[num_domain].domain_id = domain_id; - if (line) - *line = fc->line_count; + /* + * Get architecture specific data + */ + if (!get_xen_info_arch()) + return FALSE; - if (expected_token && strcmp(fc->token, expected_token)) { - fc->saved_token = fc->token; - return NULL; - } - return fc->token; + return TRUE; } -static int -read_size_entry(struct config *config, int line) +void +show_data_xen(void) { - int idx = config->num_filter_symbols - 1; - char *token = get_config_token(NULL, 0, &line, NULL, NULL); + int i; + + /* + * Show data for debug + */ + MSG("\n"); + MSG("SYMBOL(dom_xen): %llx\n", SYMBOL(dom_xen)); + MSG("SYMBOL(dom_io): %llx\n", SYMBOL(dom_io)); + MSG("SYMBOL(domain_list): %llx\n", SYMBOL(domain_list)); + MSG("SYMBOL(xen_heap_start): %llx\n", SYMBOL(xen_heap_start)); + MSG("SYMBOL(frame_table): %llx\n", SYMBOL(frame_table)); + MSG("SYMBOL(alloc_bitmap): %llx\n", SYMBOL(alloc_bitmap)); + MSG("SYMBOL(max_page): %llx\n", SYMBOL(max_page)); + MSG("SYMBOL(pgd_l2): %llx\n", SYMBOL(pgd_l2)); + MSG("SYMBOL(pgd_l3): %llx\n", SYMBOL(pgd_l3)); + MSG("SYMBOL(pgd_l4): %llx\n", SYMBOL(pgd_l4)); + MSG("SYMBOL(xenheap_phys_end): %llx\n", SYMBOL(xenheap_phys_end)); + MSG("SYMBOL(xen_pstart): %llx\n", SYMBOL(xen_pstart)); + MSG("SYMBOL(frametable_pg_dir): %llx\n", SYMBOL(frametable_pg_dir)); + + MSG("SIZE(page_info): %ld\n", SIZE(page_info)); + MSG("OFFSET(page_info.count_info): %ld\n", OFFSET(page_info.count_info)); + MSG("OFFSET(page_info._domain): %ld\n", OFFSET(page_info._domain)); + MSG("SIZE(domain): %ld\n", SIZE(domain)); + MSG("OFFSET(domain.domain_id): %ld\n", OFFSET(domain.domain_id)); + MSG("OFFSET(domain.next_in_list): %ld\n", OFFSET(domain.next_in_list)); - if (!token || IS_KEYWORD(token)) { - ERRMSG("Config error at %d: expected size symbol after" - " 'size' keyword.\n", line); - return FALSE; - } - config->size_symbol[idx] = create_config_entry(token, SIZE_ENTRY, line); - if (!config->size_symbol[idx]) { - ERRMSG("Error at line %d: Failed to read size symbol\n", - line); - return FALSE; + MSG("\n"); + if (info->xen_crash_info.com) { + MSG("xen_major_version: %lx\n", + info->xen_crash_info.com->xen_major_version); + MSG("xen_minor_version: %lx\n", + info->xen_crash_info.com->xen_minor_version); } - if (config->iter_entry && config->size_symbol[idx]->name && - (!strcmp(config->size_symbol[idx]->name, - config->iter_entry->name))) { - config->size_symbol[idx]->flag &= ~SYMBOL_ENTRY; - config->size_symbol[idx]->flag |= VAR_ENTRY; - config->size_symbol[idx]->refer_to = config->iter_entry; + MSG("xen_phys_start: %lx\n", info->xen_phys_start); + MSG("frame_table_vaddr: %lx\n", info->frame_table_vaddr); + MSG("xen_heap_start: %lx\n", info->xen_heap_start); + MSG("xen_heap_end:%lx\n", info->xen_heap_end); + MSG("alloc_bitmap: %lx\n", info->alloc_bitmap); + MSG("max_page: %lx\n", info->max_page); + MSG("num_domain: %d\n", info->num_domain); + for (i = 0; i < info->num_domain; i++) { + MSG(" %u: %x: %lx\n", info->domain_list[i].domain_id, + info->domain_list[i].pickled_id, + info->domain_list[i].domain_addr); } - return TRUE; } -/* - * Read erase command entry. The erase command syntax is: - * - * erase [.member[...]] [size [K|M]] - * erase [.member[...]] [size ] - * erase [.member[...]] [nullify] - */ -static int -read_filter_entry(struct config *config, int line) +int +generate_vmcoreinfo_xen(void) { - int size, idx; - char *token = get_config_token(NULL, 0, &line, NULL, NULL); - - if (!token || IS_KEYWORD(token)) { - ERRMSG("Config error at %d: expected kernel symbol after" - " 'erase' command.\n", line); + if ((info->page_size = sysconf(_SC_PAGE_SIZE)) <= 0) { + ERRMSG("Can't get the size of page.\n"); return FALSE; } + set_dwarf_debuginfo("xen-syms", NULL, + info->name_xen_syms, info->fd_xen_syms); - idx = config->num_filter_symbols; - config->num_filter_symbols++; - size = config->num_filter_symbols * sizeof(struct config_entry *); - config->filter_symbol = realloc(config->filter_symbol, size); - config->size_symbol = realloc(config->size_symbol, size); - - if (!config->filter_symbol || !config->size_symbol) { - ERRMSG("Can't get memory to read config symbols.\n"); + if (!get_symbol_info_xen()) return FALSE; - } - config->filter_symbol[idx] = NULL; - config->size_symbol[idx] = NULL; - config->filter_symbol[idx] = - create_config_entry(token, FILTER_ENTRY, line); - if (!config->filter_symbol[idx]) { - ERRMSG("Error at line %d: Failed to read filter symbol\n", - line); + if (!get_structure_info_xen()) return FALSE; - } /* - * Save the symbol expression string for generation of eraseinfo data - * later while writing dumpfile. + * write 1st kernel's PAGESIZE */ - config->filter_symbol[idx]->symbol_expr = strdup(token); - - if (config->iter_entry) { - if (strcmp(config->filter_symbol[idx]->name, - config->iter_entry->name)) { - ERRMSG("Config error at %d: unused iteration" - " variable '%s'.\n", line, - config->iter_entry->name); - return FALSE; - } - config->filter_symbol[idx]->flag &= ~SYMBOL_ENTRY; - config->filter_symbol[idx]->flag |= VAR_ENTRY; - config->filter_symbol[idx]->refer_to = config->iter_entry; - } - if (get_config_token("nullify", 0, &line, NULL, NULL)) { - config->filter_symbol[idx]->nullify = 1; - } - else if (get_config_token("size", 0, &line, NULL, NULL)) { - if (!read_size_entry(config, line)) - return FALSE; - } - return TRUE; -} + fprintf(info->file_vmcoreinfo, "%s%ld\n", STR_PAGESIZE, + info->page_size); -static int -add_traversal_entry(struct config_entry *ce, char *member, int line) -{ - if (!ce) - return FALSE; + /* + * write the symbol of 1st kernel + */ + WRITE_SYMBOL("dom_xen", dom_xen); + WRITE_SYMBOL("dom_io", dom_io); + WRITE_SYMBOL("domain_list", domain_list); + WRITE_SYMBOL("xen_heap_start", xen_heap_start); + WRITE_SYMBOL("frame_table", frame_table); + WRITE_SYMBOL("alloc_bitmap", alloc_bitmap); + WRITE_SYMBOL("max_page", max_page); + WRITE_SYMBOL("pgd_l2", pgd_l2); + WRITE_SYMBOL("pgd_l3", pgd_l3); + WRITE_SYMBOL("pgd_l4", pgd_l4); + WRITE_SYMBOL("xenheap_phys_end", xenheap_phys_end); + WRITE_SYMBOL("xen_pstart", xen_pstart); + WRITE_SYMBOL("frametable_pg_dir", frametable_pg_dir); - while (ce->next) - ce = ce->next; + /* + * write the structure size of 1st kernel + */ + WRITE_STRUCTURE_SIZE("page_info", page_info); + WRITE_STRUCTURE_SIZE("domain", domain); - ce->next = create_config_entry(member, LIST_ENTRY, line); - if (ce->next == NULL) { - ERRMSG("Error at line %d: Failed to read 'via' member\n", - line); - return FALSE; - } + /* + * write the member offset of 1st kernel + */ + WRITE_MEMBER_OFFSET("page_info.count_info", page_info.count_info); + WRITE_MEMBER_OFFSET("page_info._domain", page_info._domain); + WRITE_MEMBER_OFFSET("domain.domain_id", domain.domain_id); + WRITE_MEMBER_OFFSET("domain.next_in_list", domain.next_in_list); - ce->next->flag |= TRAVERSAL_ENTRY; - ce->next->flag &= ~SYMBOL_ENTRY; return TRUE; } -static int -read_list_entry(struct config *config, int line) +int +read_vmcoreinfo_basic_info_xen(void) { - char *token = get_config_token(NULL, 0, &line, NULL, NULL); + long page_size = FALSE; + char buf[BUFSIZE_FGETS], *endp; + unsigned int i; - if (!token || IS_KEYWORD(token)) { - ERRMSG("Config error at %d: expected list symbol after" - " 'in' keyword.\n", line); - return FALSE; - } - config->list_entry = create_config_entry(token, LIST_ENTRY, line); - if (!config->list_entry) { - ERRMSG("Error at line %d: Failed to read list symbol\n", - line); + if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) { + ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n", + info->name_vmcoreinfo, strerror(errno)); return FALSE; } - /* Check if user has provided 'via' or 'within' keyword */ - if (get_config_token("via", 0, &line, NULL, NULL)) { - /* next token is traversal member NextMember */ - token = get_config_token(NULL, 0, &line, NULL, NULL); - if (!token) { - ERRMSG("Config error at %d: expected member name after" - " 'via' keyword.\n", line); - return FALSE; - } - if (!add_traversal_entry(config->list_entry, token, line)) - return FALSE; - } - else if (get_config_token("within", 0, &line, NULL, NULL)) { - char *s_name, *lh_member; - /* next value is StructName:ListHeadMember */ - s_name = get_config_token(NULL, 0, &line, NULL, NULL); - if (!s_name || IS_KEYWORD(s_name)) { - ERRMSG("Config error at %d: expected struct name after" - " 'within' keyword.\n", line); - return FALSE; - } - lh_member = strchr(s_name, ':'); - if (lh_member) { - *lh_member++ = '\0'; - if (!strlen(lh_member)) { - ERRMSG("Config error at %d: expected list_head" - " member after ':'.\n", line); + + while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) { + i = strlen(buf); + if (!i) + break; + if (buf[i - 1] == '\n') + buf[i - 1] = '\0'; + if (strncmp(buf, STR_PAGESIZE, strlen(STR_PAGESIZE)) == 0) { + page_size = strtol(buf+strlen(STR_PAGESIZE),&endp,10); + if ((!page_size || page_size == LONG_MAX) + || strlen(endp) != 0) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); return FALSE; } - config->iter_entry->next = - create_config_entry(lh_member, - ITERATION_ENTRY, line); - if (!config->iter_entry->next) - return FALSE; - config->iter_entry->next->flag &= ~SYMBOL_ENTRY; - } - if (!strlen(s_name)) { - ERRMSG("Config error at %d: Invalid token found " - "after 'within' keyword.\n", line); - return FALSE; - } - config->iter_entry->type_name = strdup(s_name); - } - return TRUE; -} - -/* - * Read the iteration entry (LoopConstruct). The syntax is: - * - * for in { | - * via | - * within :} - * erase [.MemberExpression] [size |nullify] - * [erase ...] - * [...] - * endfor - */ -static int -read_iteration_entry(struct config *config, int line) -{ - int eof = 0; - char *token = get_config_token(NULL, 0, &line, NULL, NULL); - - if (!token || IS_KEYWORD(token)) { - ERRMSG("Config error at %d: expected iteration VAR entry after" - " 'for' keyword.\n", line); - return FALSE; - } - config->iter_entry = - create_config_entry(token, ITERATION_ENTRY, line); - if (!config->iter_entry) { - ERRMSG("Error at line %d: " - "Failed to read iteration VAR entry.\n", line); - return FALSE; - } - if (!get_config_token("in", 0, &line, NULL, NULL)) { - char *token; - token = get_config_token(NULL, 0, &line, NULL, NULL); - if (token) - ERRMSG("Config error at %d: Invalid token '%s'.\n", - line, token); - ERRMSG("Config error at %d: expected token 'in'.\n", line); - return FALSE; - } - if (!read_list_entry(config, line)) - return FALSE; - - while (!get_config_token("endfor", 0, &line, NULL, &eof) && !eof) { - if (get_config_token("erase", 0, &line, NULL, NULL)) { - if (!read_filter_entry(config, line)) + if (!set_page_size(page_size)) { + ERRMSG("Invalid data in %s: %s", + info->name_vmcoreinfo, buf); return FALSE; - } - else { - token = get_config_token(NULL, 0, &line, NULL, NULL); - ERRMSG("Config error at %d: " - "Invalid token '%s'.\n", line, token); - return FALSE; + } + break; } } - if (eof) { - ERRMSG("Config error at %d: No matching 'endfor' found.\n", - line); + if (!info->page_size) { + ERRMSG("Invalid format in %s", info->name_vmcoreinfo); return FALSE; } return TRUE; } -/* - * Configuration file 'makedumpfile.conf' contains filter commands. - * Every individual filter command is considered as a config entry. A config - * entry can be provided on a single line or multiple lines. - */ -struct config * -get_config(int skip) +int +read_vmcoreinfo_xen(void) { - struct config *config; - char *token = NULL; - static int line_count = 0; - char *cur_module = NULL; - int eof = 0; - unsigned char flag = CONFIG_NEW_CMD; - - if (skip) - flag |= CONFIG_SKIP_SECTION; - - if ((config = calloc(1, sizeof(struct config))) == NULL) - return NULL; - - if (get_config_token("erase", flag, &line_count, &cur_module, &eof)) { - if (cur_module) - config->module_name = strdup(cur_module); - - if (!read_filter_entry(config, line_count)) - goto err_out; - } - else if (get_config_token("for", 0, &line_count, &cur_module, &eof)) { - if (cur_module) - config->module_name = strdup(cur_module); - - if (!read_iteration_entry(config, line_count)) - goto err_out; - } - else { - if (!eof) { - token = get_config_token(NULL, 0, &line_count, - NULL, NULL); - ERRMSG("Config error at %d: Invalid token '%s'.\n", - line_count, token); - } - goto err_out; - } - return config; -err_out: - if (config) - free_config(config); - return NULL; -} + if (!read_vmcoreinfo_basic_info_xen()) + return FALSE; -static unsigned long -read_pointer_value(unsigned long long addr) -{ - unsigned long val; + READ_SYMBOL("dom_xen", dom_xen); + READ_SYMBOL("dom_io", dom_io); + READ_SYMBOL("domain_list", domain_list); + READ_SYMBOL("xen_heap_start", xen_heap_start); + READ_SYMBOL("frame_table", frame_table); + READ_SYMBOL("alloc_bitmap", alloc_bitmap); + READ_SYMBOL("max_page", max_page); + READ_SYMBOL("pgd_l2", pgd_l2); + READ_SYMBOL("pgd_l3", pgd_l3); + READ_SYMBOL("pgd_l4", pgd_l4); + READ_SYMBOL("xenheap_phys_end", xenheap_phys_end); + READ_SYMBOL("xen_pstart", xen_pstart); + READ_SYMBOL("frametable_pg_dir", frametable_pg_dir); - if (!readmem(VADDR, addr, &val, sizeof(val))) { - ERRMSG("Can't read pointer value\n"); - return 0; - } - return val; -} + READ_STRUCTURE_SIZE("page_info", page_info); + READ_STRUCTURE_SIZE("domain", domain); -static long -get_strlen(unsigned long long vaddr) -{ - char buf[BUFSIZE + 1]; - long len = 0; + READ_MEMBER_OFFSET("page_info.count_info", page_info.count_info); + READ_MEMBER_OFFSET("page_info._domain", page_info._domain); + READ_MEMBER_OFFSET("domain.domain_id", domain.domain_id); + READ_MEMBER_OFFSET("domain.next_in_list", domain.next_in_list); - /* - * Determine the string length for 'char' pointer. - * BUFSIZE(1024) is the upper limit for string length. - */ - if (readmem(VADDR, vaddr, buf, BUFSIZE)) { - buf[BUFSIZE] = '\0'; - len = strlen(buf); - } - return len; + return TRUE; } int -resolve_config_entry(struct config_entry *ce, unsigned long long base_addr, - char *base_struct_name) +allocated_in_map(unsigned long long pfn) { + static unsigned long long cur_idx = -1; + static unsigned long cur_word; + unsigned long long idx; - if (ce->flag & SYMBOL_ENTRY) { - /* find the symbol info */ - if (!ce->name) - return FALSE; - - ce->sym_addr = get_symbol_addr(ce->name); - if (!ce->sym_addr) { - ERRMSG("Config error at %d: Can't find symbol '%s'.\n", - ce->line, ce->name); - return FALSE; - } - ce->type_name = get_symbol_type_name(ce->name, - DWARF_INFO_GET_SYMBOL_TYPE, - &ce->size, &ce->type_flag); - if (ce->type_flag & TYPE_ARRAY) { - ce->array_length = get_array_length(ce->name, NULL, - DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH); - if (ce->array_length < 0) - ce->array_length = 0; - } - } - else if (ce->flag & VAR_ENTRY) { - /* iteration variable. - * read the value from ce->refer_to - */ - ce->addr = ce->refer_to->addr; - ce->sym_addr = ce->refer_to->sym_addr; - ce->size = ce->refer_to->size; - ce->type_flag = ce->refer_to->type_flag; - if (!ce->type_name) - ce->type_name = strdup(ce->refer_to->type_name); - - /* This entry has been changed hence next entry needs to - * be resolved accordingly. - */ - if (ce->next) - ce->next->flag &= ~ENTRY_RESOLVED; - return TRUE; - } - else { - /* find the member offset */ - ce->offset = get_member_offset(base_struct_name, - ce->name, DWARF_INFO_GET_MEMBER_OFFSET); - ce->sym_addr = base_addr + ce->offset; - ce->type_name = get_member_type_name(base_struct_name, - ce->name, DWARF_INFO_GET_MEMBER_TYPE, - &ce->size, &ce->type_flag); - if (ce->type_flag & TYPE_ARRAY) { - ce->array_length = get_array_length(base_struct_name, - ce->name, - DWARF_INFO_GET_MEMBER_ARRAY_LENGTH); - if (ce->array_length < 0) - ce->array_length = 0; - } - } - if (ce->type_name == NULL) { - if (!(ce->flag & SYMBOL_ENTRY)) - ERRMSG("Config error at %d: struct '%s' has no member" - " with name '%s'.\n", - ce->line, base_struct_name, ce->name); - return FALSE; - } - if (!strcmp(ce->type_name, "list_head")) { - ce->type_flag |= TYPE_LIST_HEAD; - /* If this list head expression is a LIST entry then - * mark the next entry as TRAVERSAL_ENTRY, if any. - * Error out if next entry is not a last node. - */ - if ((ce->flag & LIST_ENTRY) && ce->next) { - if (ce->next->next) { - ERRMSG("Config error at %d: Only one traversal" - " entry is allowed for list_head type" - " LIST entry", ce->line); - return FALSE; - } - ce->next->flag |= TRAVERSAL_ENTRY; - } - } - ce->addr = ce->sym_addr; - if (ce->size < 0) - ce->size = 0; - if ((ce->flag & LIST_ENTRY) && !ce->next) { - /* This is the last node of LIST entry. - * For the list entry symbol, the allowed data types are: - * Array, Structure Pointer (with 'next' member) and list_head. - * - * If this is a struct or list_head data type then - * create a leaf node entry with 'next' member. - */ - if (((ce->type_flag & (TYPE_BASE | TYPE_ARRAY)) == TYPE_BASE) - && (strcmp(ce->type_name, "void"))) - return FALSE; - - if ((ce->type_flag & TYPE_LIST_HEAD) - || ((ce->type_flag & (TYPE_STRUCT | TYPE_ARRAY)) - == TYPE_STRUCT)) { - if (!(ce->flag & TRAVERSAL_ENTRY)) { - ce->next = create_config_entry("next", - LIST_ENTRY, ce->line); - if (ce->next == NULL) - return FALSE; - - ce->next->flag |= TRAVERSAL_ENTRY; - ce->next->flag &= ~SYMBOL_ENTRY; - } - } - if (ce->flag & TRAVERSAL_ENTRY) { - /* type name of traversal entry should match with - * that of parent node. - */ - if (strcmp(base_struct_name, ce->type_name)) - return FALSE; + idx = pfn / PAGES_PER_MAPWORD; + if (idx != cur_idx) { + if (!readmem(VADDR_XEN, + info->alloc_bitmap + idx * sizeof(unsigned long), + &cur_word, sizeof(cur_word))) { + ERRMSG("Can't access alloc_bitmap.\n"); + return 0; } + cur_idx = idx; } - if ((ce->type_flag & (TYPE_ARRAY | TYPE_PTR)) == TYPE_PTR) { - /* If it's a pointer variable (not array) then read the - * pointer value. */ - ce->addr = read_pointer_value(ce->sym_addr); - - /* - * if it is a void pointer then reset the size to 0 - * User need to provide a size to filter data referenced - * by 'void *' pointer or nullify option. - */ - if (!strcmp(ce->type_name, "void")) - ce->size = 0; - - } - if ((ce->type_flag & TYPE_BASE) && (ce->type_flag & TYPE_PTR) - && !(ce->type_flag & TYPE_ARRAY)) { - /* - * Determine the string length for 'char' pointer. - * BUFSIZE(1024) is the upper limit for string length. - */ - if (!strcmp(ce->type_name, "char")) - ce->size = get_strlen(ce->addr); - } - if (!ce->next && (ce->flag & SIZE_ENTRY)) { - void *val; - - /* leaf node of size entry */ - /* If it is size argument then update the size with data - * value of this symbol/member. - * Check if current symbol/member is of base data type. - */ - - if (((ce->type_flag & (TYPE_ARRAY | TYPE_BASE)) != TYPE_BASE) - || (ce->size > sizeof(long))) { - ERRMSG("Config error at %d: size symbol/member '%s' " - "is not of base type.\n", ce->line, ce->name); - return FALSE; - } - if ((val = calloc(1, ce->size)) == NULL) { - ERRMSG("Can't get memory for size parameter\n"); - return FALSE; - } - if (!readmem(VADDR, ce->addr, val, ce->size)) { - ERRMSG("Can't read symbol/member data value\n"); - return FALSE; - } - switch (ce->size) { - case 1: - ce->size = (long)(*((uint8_t *)val)); - break; - case 2: - ce->size = (long)(*((uint16_t *)val)); - break; - case 4: - ce->size = (long)(*((uint32_t *)val)); - break; - case 8: - ce->size = (long)(*((uint64_t *)val)); - break; - } - free(val); - } - ce->flag |= ENTRY_RESOLVED; - if (ce->next) - ce->next->flag &= ~ENTRY_RESOLVED; - return TRUE; + return !!(cur_word & (1UL << (pfn & (PAGES_PER_MAPWORD - 1)))); } -unsigned long long -get_config_symbol_addr(struct config_entry *ce, - unsigned long long base_addr, - char *base_struct_name) +int +is_select_domain(unsigned int id) { - if (!(ce->flag & ENTRY_RESOLVED)) { - if (!resolve_config_entry(ce, base_addr, base_struct_name)) - return 0; - } + int i; - if (ce->next && ce->addr) { - /* Populate nullify flag down the list */ - ce->next->nullify = ce->nullify; - return get_config_symbol_addr(ce->next, ce->addr, - ce->type_name); - } - else if (!ce->next && ce->nullify) { - /* nullify is applicable to pointer type */ - if (ce->type_flag & TYPE_PTR) - return ce->sym_addr; - else - return 0; - } - else - return ce->addr; -} + /* selected domain is fix to dom0 only now !! + (yes... domain_list is not necessary right now, + it can get from "dom0" directly) */ -long -get_config_symbol_size(struct config_entry *ce, - unsigned long long base_addr, - char *base_struct_name) -{ - if (!(ce->flag & ENTRY_RESOLVED)) { - if (!resolve_config_entry(ce, base_addr, base_struct_name)) - return 0; + for (i = 0; i < info->num_domain; i++) { + if (info->domain_list[i].domain_id == 0 && + info->domain_list[i].pickled_id == id) + return TRUE; } - if (ce->next && ce->addr) - return get_config_symbol_size(ce->next, ce->addr, - ce->type_name); - else { - if (ce->type_flag & TYPE_ARRAY) { - if (ce->type_flag & TYPE_PTR) - return ce->array_length * get_pointer_size(); - else - return ce->array_length * ce->size; - } - return ce->size; - } + return FALSE; } int -get_next_list_entry(struct config_entry *ce, unsigned long long base_addr, - char *base_struct_name, struct config_entry *out_ce) +exclude_xen3_user_domain(void) { - unsigned long addr = 0; + int i; + unsigned int count_info, _domain; + unsigned int num_pt_loads = get_num_pt_loads(); + unsigned long page_info_addr; + unsigned long long phys_start, phys_end; + unsigned long long pfn, pfn_end; + unsigned long long j, size; - /* This function only deals with LIST_ENTRY config entry. */ - if (!(ce->flag & LIST_ENTRY)) - return FALSE; + /* + * NOTE: the first half of bitmap is not used for Xen extraction + */ + for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) { - if (!(ce->flag & ENTRY_RESOLVED)) { - if (!resolve_config_entry(ce, base_addr, base_struct_name)) - return FALSE; - } + print_progress(PROGRESS_XEN_DOMAIN, i, num_pt_loads); - if (!ce->next) { - /* leaf node. */ - if (ce->type_flag & TYPE_ARRAY) { - if (ce->index == ce->array_length) - return FALSE; + pfn = paddr_to_pfn(phys_start); + pfn_end = paddr_to_pfn(phys_end); + size = pfn_end - pfn; - if (ce->type_flag & TYPE_PTR) { - /* Array of pointers. - * - * Array may contain NULL pointers at some - * indexes. Hence jump to the next non-null - * address value. - */ - while (ce->index < ce->array_length) { - addr = read_pointer_value(ce->addr + - (ce->index * get_pointer_size())); - if (addr) - break; - ce->index++; - } - if (ce->index == ce->array_length) - return FALSE; - out_ce->sym_addr = ce->addr + (ce->index * - get_pointer_size()); - out_ce->addr = addr; - if (!strcmp(ce->type_name, "char")) - out_ce->size = get_strlen(addr); - else - out_ce->size = ce->size; + for (j = 0; pfn < pfn_end; pfn++, j++) { + print_progress(PROGRESS_XEN_DOMAIN, j + (size * i), + size * num_pt_loads); + + if (!allocated_in_map(pfn)) { + clear_bit_on_2nd_bitmap(pfn); + continue; } - else { - out_ce->sym_addr = ce->addr + - (ce->index * ce->size); - out_ce->addr = out_ce->sym_addr; - out_ce->size = ce->size; + + page_info_addr = info->frame_table_vaddr + pfn * SIZE(page_info); + if (!readmem(VADDR_XEN, + page_info_addr + OFFSET(page_info.count_info), + &count_info, sizeof(count_info))) { + clear_bit_on_2nd_bitmap(pfn); + continue; /* page_info may not exist */ } - ce->index++; - } - else { - if (ce->addr == ce->cmp_addr) + if (!readmem(VADDR_XEN, + page_info_addr + OFFSET(page_info._domain), + &_domain, sizeof(_domain))) { + ERRMSG("Can't get page_info._domain.\n"); return FALSE; - - out_ce->addr = ce->addr; - /* Set the leaf node as unresolved, so that - * it will be resolved every time when - * get_next_list_entry is called untill - * it hits the exit condiftion. + } + /* + * select: + * - anonymous (_domain == 0), or + * - xen heap area, or + * - selected domain page */ - ce->flag &= ~ENTRY_RESOLVED; + if (_domain == 0) + continue; + if (info->xen_heap_start <= pfn && pfn < info->xen_heap_end) + continue; + if ((count_info & 0xffff) && is_select_domain(_domain)) + continue; + clear_bit_on_2nd_bitmap(pfn); } - return TRUE; } - else if ((ce->next->next == NULL) && - !(ce->next->type_flag & TYPE_ARRAY)) { - /* the next node is leaf node. for non-array element - * Set the sym_addr and addr of this node with that of - * leaf node. - */ - if (!(ce->type_flag & TYPE_LIST_HEAD)) { - if (!ce->addr || ce->addr == ce->next->cmp_addr) - return FALSE; - if (!ce->next->cmp_addr) { - /* safeguard against circular - * link-list - */ - ce->next->cmp_addr = ce->addr; + return TRUE; +} + +int +exclude_xen4_user_domain(void) +{ + int i; + unsigned long count_info; + unsigned int _domain; + unsigned int num_pt_loads = get_num_pt_loads(); + unsigned long page_info_addr; + unsigned long long phys_start, phys_end; + unsigned long long pfn, pfn_end; + unsigned long long j, size; + + /* + * NOTE: the first half of bitmap is not used for Xen extraction + */ + for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) { + + print_progress(PROGRESS_XEN_DOMAIN, i, num_pt_loads); + + pfn = paddr_to_pfn(phys_start); + pfn_end = paddr_to_pfn(phys_end); + size = pfn_end - pfn; + + for (j = 0; pfn < pfn_end; pfn++, j++) { + print_progress(PROGRESS_XEN_DOMAIN, j + (size * i), + size * num_pt_loads); + + page_info_addr = info->frame_table_vaddr + pfn * SIZE(page_info); + if (!readmem(VADDR_XEN, + page_info_addr + OFFSET(page_info.count_info), + &count_info, sizeof(count_info))) { + clear_bit_on_2nd_bitmap(pfn); + continue; /* page_info may not exist */ } - out_ce->addr = ce->addr; - out_ce->sym_addr = ce->sym_addr; - out_ce->size = ce->size; + /* always keep Xen heap pages */ + if (count_info & PGC_xen_heap) + continue; + + /* delete free, offlined and broken pages */ + if (page_state_is(count_info, free) || + page_state_is(count_info, offlined) || + count_info & PGC_broken) { + clear_bit_on_2nd_bitmap(pfn); + continue; + } - ce->sym_addr = ce->next->sym_addr; - ce->addr = ce->next->addr; + /* keep inuse pages not allocated to any domain + * this covers e.g. Xen static data + */ + if (! (count_info & PGC_allocated)) + continue; - /* Force resolution of traversal node */ - if (ce->addr && !resolve_config_entry(ce->next, - ce->addr, ce->type_name)) + /* Need to check the domain + * keep: + * - anonymous (_domain == 0), or + * - selected domain page + */ + if (!readmem(VADDR_XEN, + page_info_addr + OFFSET(page_info._domain), + &_domain, sizeof(_domain))) { + ERRMSG("Can't get page_info._domain.\n"); return FALSE; + } - return TRUE; - } - else { - ce->sym_addr = ce->next->sym_addr; - ce->addr = ce->next->addr; + if (_domain == 0) + continue; + if (is_select_domain(_domain)) + continue; + clear_bit_on_2nd_bitmap(pfn); } } - if (ce->next && ce->addr) - return get_next_list_entry(ce->next, ce->addr, - ce->type_name, out_ce); - return FALSE; + return TRUE; } -static int -resolve_list_entry(struct config_entry *ce, unsigned long long base_addr, - char *base_struct_name, char **out_type_name, - unsigned char *out_type_flag) +int +exclude_xen_user_domain(void) { - if (!(ce->flag & ENTRY_RESOLVED)) { - if (!resolve_config_entry(ce, base_addr, base_struct_name)) - return FALSE; - } + struct timeval tv_start; + int ret; - if (ce->next && (ce->next->flag & TRAVERSAL_ENTRY) && - (ce->type_flag & TYPE_ARRAY)) { - /* - * We are here because user has provided - * traversal member for ArrayVar using 'via' keyword. - * - * Print warning and continue. - */ - ERRMSG("Warning: line %d: 'via' keyword not required " - "for ArrayVar.\n", ce->next->line); - free_config_entry(ce->next); - ce->next = NULL; - } - if ((ce->type_flag & TYPE_LIST_HEAD) && ce->next && - (ce->next->flag & TRAVERSAL_ENTRY)) { - /* set cmp_addr for list empty condition. */ - ce->next->cmp_addr = ce->sym_addr; - } - if (ce->next && ce->addr) { - return resolve_list_entry(ce->next, ce->addr, - ce->type_name, out_type_name, out_type_flag); - } - else { - ce->index = 0; - if (out_type_name) - *out_type_name = ce->type_name; - if (out_type_flag) - *out_type_flag = ce->type_flag; - } - return TRUE; + gettimeofday(&tv_start, NULL); + + if (info->xen_crash_info.com && + info->xen_crash_info.com->xen_major_version >= 4) + ret = exclude_xen4_user_domain(); + else + ret = exclude_xen3_user_domain(); + + /* + * print [100 %] + */ + print_progress(PROGRESS_XEN_DOMAIN, 1, 1); + print_execution_time(PROGRESS_XEN_DOMAIN, &tv_start); + + return ret; } -/* - * Insert the filter info node using insertion sort. - * If filter node for a given paddr is aready present then update the size - * and delete the fl_info node passed. - * - * Return 1 on successfull insertion. - * Return 0 if filter node with same paddr is found. - */ int -insert_filter_info(struct filter_info *fl_info) +initial_xen(void) { - struct filter_info *prev = NULL; - struct filter_info *ptr = filter_info; - - if (!ptr) { - filter_info = fl_info; - return 1; - } + off_t offset; + unsigned long size; - while (ptr) { - if (fl_info->paddr <= ptr->paddr) - break; - prev = ptr; - ptr = ptr->next; +#if defined(__powerpc64__) || defined(__powerpc32__) + MSG("\n"); + MSG("Xen is not supported on powerpc.\n"); + return FALSE; +#else + if(!info->flag_elf_dumpfile) { + MSG("Specify '-E' option for Xen.\n"); + MSG("Commandline parameter is invalid.\n"); + MSG("Try `makedumpfile --help' for more information.\n"); + return FALSE; } - if (ptr && (fl_info->paddr == ptr->paddr)) { - if (fl_info->size > ptr->size) - ptr->size = fl_info->size; - free(fl_info); - return 0; +#ifndef __x86_64__ + if (DL_EXCLUDE_ZERO < info->max_dump_level) { + MSG("Dump_level is invalid. It should be 0 or 1.\n"); + MSG("Commandline parameter is invalid.\n"); + MSG("Try `makedumpfile --help' for more information.\n"); + return FALSE; } +#endif + if (!init_xen_crash_info()) + return FALSE; + if (!fallback_to_current_page_size()) + return FALSE; + /* + * Get the debug information for analysis from the vmcoreinfo file + */ + if (info->flag_read_vmcoreinfo) { + if (!read_vmcoreinfo_xen()) + return FALSE; + close_vmcoreinfo(); + /* + * Get the debug information for analysis from the xen-syms file + */ + } else if (info->name_xen_syms) { + set_dwarf_debuginfo("xen-syms", NULL, + info->name_xen_syms, info->fd_xen_syms); - if (prev) { - fl_info->next = ptr; - prev->next = fl_info; - } - else { - fl_info->next = filter_info; - filter_info = fl_info; + if (!get_symbol_info_xen()) + return FALSE; + if (!get_structure_info_xen()) + return FALSE; + /* + * Get the debug information for analysis from /proc/vmcore + */ + } else { + /* + * Check whether /proc/vmcore contains vmcoreinfo, + * and get both the offset and the size. + */ + if (!has_vmcoreinfo_xen()){ + if (!info->flag_exclude_xen_dom) + goto out; + + MSG("%s doesn't contain a vmcoreinfo for Xen.\n", + info->name_memory); + MSG("Specify '--xen-syms' option or '--xen-vmcoreinfo' option.\n"); + MSG("Commandline parameter is invalid.\n"); + MSG("Try `makedumpfile --help' for more information.\n"); + return FALSE; + } + /* + * Get the debug information from /proc/vmcore + */ + get_vmcoreinfo_xen(&offset, &size); + if (!read_vmcoreinfo_from_vmcore(offset, size, TRUE)) + return FALSE; } - return 1; + if (!get_xen_info()) + return FALSE; + + if (message_level & ML_PRINT_DEBUG_MSG) + show_data_xen(); +out: + if (!get_max_mapnr()) + return FALSE; + + return TRUE; +#endif } -/* - * Create an erase info node for each erase command. One node per erase - * command even if it is part of loop construct. - * For erase commands that are not part of loop construct, the num_sizes will - * always be 1 - * For erase commands that are part of loop construct, the num_sizes may be - * 1 or >1 depending on number iterations. This function will called multiple - * times depending on iterations. At first invokation create a node and - * increment num_sizes for subsequent invokations. - * - * The valid erase info node starts from index value 1. (index 0 is invalid - * index). - * - * Index 0 1 2 3 - * +------+--------+--------+--------+ - * erase_info->|Unused| | | |...... - * +------+--------+--------+--------+ - * | . . ..... - * V - * +---------+ - * | char* |----> Original erase command string - * +---------+ - * |num_sizes| - * +---------+ +--+--+--+ - * | sizes |----> | | | |... Sizes array of num_sizes - * +---------+ +--+--+--+ - * - * On success, return the index value of erase node for given erase command. - * On failure, return 0. - */ -static int -add_erase_info_node(struct config_entry *filter_symbol) +void +print_vtop(void) { - int idx = filter_symbol->erase_info_idx; + unsigned long long paddr; - /* - * Check if node is already created, if yes, increment the num_sizes. - */ - if (idx) { - erase_info[idx].num_sizes++; - return idx; - } + if (!info->vaddr_for_vtop) + return; - /* Allocate a new node. */ - DEBUG_MSG("Allocating new erase info node for command \"%s\"\n", - filter_symbol->symbol_expr); - idx = num_erase_info++; - erase_info = realloc(erase_info, - sizeof(struct erase_info) * num_erase_info); - if (!erase_info) { - ERRMSG("Can't get memory to create erase information.\n"); - return 0; - } + MSG("\n"); + MSG("Translating virtual address %lx to physical address.\n", info->vaddr_for_vtop); + + paddr = vaddr_to_paddr(info->vaddr_for_vtop); - memset(&erase_info[idx], 0, sizeof(struct erase_info)); - erase_info[idx].symbol_expr = filter_symbol->symbol_expr; - erase_info[idx].num_sizes = 1; + MSG("VIRTUAL PHYSICAL\n"); + MSG("%16lx %llx\n", info->vaddr_for_vtop, paddr); + MSG("\n"); - filter_symbol->symbol_expr = NULL; - filter_symbol->erase_info_idx = idx; + info->vaddr_for_vtop = 0; - return idx; + return; } -/* Return the index value in sizes array for given erase command index. */ -static inline int -get_size_index(int ei_idx) +void +print_report(void) { - if (ei_idx) - return erase_info[ei_idx].num_sizes - 1; - return 0; + unsigned long long pfn_original, pfn_excluded, shrinking; + + /* + * /proc/vmcore doesn't contain the memory hole area. + */ + pfn_original = info->max_mapnr - pfn_memhole; + + pfn_excluded = pfn_zero + pfn_cache + pfn_cache_private + + pfn_user + pfn_free + pfn_hwpoison; + shrinking = (pfn_original - pfn_excluded) * 100; + shrinking = shrinking / pfn_original; + + REPORT_MSG("\n"); + REPORT_MSG("Original pages : 0x%016llx\n", pfn_original); + REPORT_MSG(" Excluded pages : 0x%016llx\n", pfn_excluded); + REPORT_MSG(" Pages filled with zero : 0x%016llx\n", pfn_zero); + REPORT_MSG(" Cache pages : 0x%016llx\n", pfn_cache); + REPORT_MSG(" Cache pages + private : 0x%016llx\n", + pfn_cache_private); + REPORT_MSG(" User process data pages : 0x%016llx\n", pfn_user); + REPORT_MSG(" Free pages : 0x%016llx\n", pfn_free); + REPORT_MSG(" Hwpoison pages : 0x%016llx\n", pfn_hwpoison); + REPORT_MSG(" Remaining pages : 0x%016llx\n", + pfn_original - pfn_excluded); + REPORT_MSG(" (The number of pages is reduced to %lld%%.)\n", + shrinking); + REPORT_MSG("Memory Hole : 0x%016llx\n", pfn_memhole); + REPORT_MSG("--------------------------------------------------\n"); + REPORT_MSG("Total pages : 0x%016llx\n", info->max_mapnr); + REPORT_MSG("\n"); } int -update_filter_info(struct config_entry *filter_symbol, - struct config_entry *size_symbol) +writeout_dumpfile(void) { - unsigned long long addr; - long size; - struct filter_info *fl_info; + int ret = FALSE; + struct cache_data cd_header, cd_page; - addr = get_config_symbol_addr(filter_symbol, 0, NULL); - if (message_level & ML_PRINT_DEBUG_MSG) - print_config_entry(filter_symbol); - if (!addr) + info->flag_nospace = FALSE; + + if (!open_dump_file()) return FALSE; - if (filter_symbol->nullify) - size = get_pointer_size(); - else if (size_symbol) { - size = get_config_symbol_size(size_symbol, 0, NULL); - if (message_level & ML_PRINT_DEBUG_MSG) - print_config_entry(size_symbol); + if (info->flag_flatten) { + if (!write_start_flat_header()) + return FALSE; } - else - size = get_config_symbol_size(filter_symbol, 0, NULL); - - if (size <= 0) + if (!prepare_cache_data(&cd_header)) return FALSE; - if ((fl_info = calloc(1, sizeof(struct filter_info))) == NULL) { - ERRMSG("Can't allocate filter info\n"); + if (!prepare_cache_data(&cd_page)) { + free_cache_data(&cd_header); return FALSE; } - fl_info->address = addr; - fl_info->paddr = vaddr_to_paddr(addr); - fl_info->size = size; - fl_info->nullify = filter_symbol->nullify; - - if (insert_filter_info(fl_info)) { - fl_info->erase_info_idx = add_erase_info_node(filter_symbol); - fl_info->size_idx = get_size_index(fl_info->erase_info_idx); + if (info->flag_elf_dumpfile) { + if (!write_elf_header(&cd_header)) + goto out; + if (info->flag_cyclic) { + if (!write_elf_pages_cyclic(&cd_header, &cd_page)) + goto out; + } else { + if (!write_elf_pages(&cd_header, &cd_page)) + goto out; + } + if (!write_elf_eraseinfo(&cd_header)) + goto out; + } else if (info->flag_cyclic) { + if (!write_kdump_header()) + goto out; + if (!write_kdump_pages_and_bitmap_cyclic(&cd_header, &cd_page)) + goto out; + if (!write_kdump_eraseinfo(&cd_page)) + goto out; + } else { + if (!write_kdump_header()) + goto out; + if (!write_kdump_pages(&cd_header, &cd_page)) + goto out; + if (!write_kdump_eraseinfo(&cd_page)) + goto out; + if (!write_kdump_bitmap()) + goto out; } - return TRUE; + if (info->flag_flatten) { + if (!write_end_flat_header()) + goto out; + } + + ret = TRUE; +out: + free_cache_data(&cd_header); + free_cache_data(&cd_page); + + close_dump_file(); + + if ((ret == FALSE) && info->flag_nospace) + return NOSPACE; + else + return ret; } int -initialize_iteration_entry(struct config_entry *ie, - char *type_name, unsigned char type_flag) +setup_splitting(void) { - if (!(ie->flag & ITERATION_ENTRY)) - return FALSE; + int i; + unsigned long long j, pfn_per_dumpfile; + unsigned long long start_pfn, end_pfn; + unsigned long long num_dumpable = get_num_dumpable(); + struct dump_bitmap bitmap2; - if (type_flag & TYPE_LIST_HEAD) { - if (!ie->type_name) { - ERRMSG("Config error at %d: Use 'within' keyword " - "to specify StructName:ListHeadMember.\n", - ie->line); - return FALSE; - } - /* - * If the LIST entry is of list_head type and user has not - * specified the member name where iteration entry is hooked - * on to list_head, then we default to member name 'list'. - */ - if (!ie->next) { - ie->next = create_config_entry("list", ITERATION_ENTRY, - ie->line); - ie->next->flag &= ~SYMBOL_ENTRY; - } + if (info->num_dumpfile <= 1) + return FALSE; - /* - * For list_head find out the size of the StructName and - * populate ie->size now. For array and link list we get the - * size info from config entry returned by - * get_next_list_entry(). - */ - ie->size = get_structure_size(ie->type_name, 0); - if (ie->size == FAILED_DWARFINFO) { - ERRMSG("Config error at %d: " - "Can't get size for type: %s.\n", - ie->line, ie->type_name); - return FALSE; - } - else if (ie->size == NOT_FOUND_STRUCTURE) { - ERRMSG("Config error at %d: " - "Can't find structure: %s.\n", - ie->line, ie->type_name); - return FALSE; + if (info->flag_cyclic) { + for (i = 0; i < info->num_dumpfile; i++) { + SPLITTING_START_PFN(i) = divideup(info->max_mapnr, info->num_dumpfile) * i; + SPLITTING_END_PFN(i) = divideup(info->max_mapnr, info->num_dumpfile) * (i + 1); } + if (SPLITTING_END_PFN(i-1) > info->max_mapnr) + SPLITTING_END_PFN(i-1) = info->max_mapnr; + } else { + initialize_2nd_bitmap(&bitmap2); - if (!resolve_config_entry(ie->next, 0, ie->type_name)) - return FALSE; - - if (strcmp(ie->next->type_name, "list_head")) { - ERRMSG("Config error at %d: " - "Member '%s' is not of 'list_head' type.\n", - ie->next->line, ie->next->name); - return FALSE; - } - ie->type_flag = TYPE_STRUCT; - } - else { - if (ie->type_name) { - /* looks like user has used 'within' keyword for - * non-list_head VAR. Print the warning and continue. - */ - ERRMSG("Warning: line %d: 'within' keyword not " - "required for ArrayVar/StructVar.\n", ie->line); - free(ie->type_name); - - /* remove the next list_head member from iteration - * entry that would have added as part of 'within' - * keyword processing. - */ - if (ie->next) { - free_config_entry(ie->next); - ie->next = NULL; + pfn_per_dumpfile = num_dumpable / info->num_dumpfile; + start_pfn = end_pfn = 0; + for (i = 0; i < info->num_dumpfile; i++) { + start_pfn = end_pfn; + if (i == (info->num_dumpfile - 1)) { + end_pfn = info->max_mapnr; + } else { + for (j = 0; j < pfn_per_dumpfile; end_pfn++) { + if (is_dumpable(&bitmap2, end_pfn)) + j++; + } } + SPLITTING_START_PFN(i) = start_pfn; + SPLITTING_END_PFN(i) = end_pfn; } - /* - * Set type flag for iteration entry. The iteration entry holds - * individual element from array/list, hence strip off the - * array type flag bit. - */ - ie->type_name = strdup(type_name); - ie->type_flag = type_flag; - ie->type_flag &= ~TYPE_ARRAY; - } - return TRUE; -} - -int -list_entry_empty(struct config_entry *le, struct config_entry *ie) -{ - struct config_entry ce; - - /* Error out if arguments are not correct */ - if (!(le->flag & LIST_ENTRY) || !(ie->flag & ITERATION_ENTRY)) { - ERRMSG("Invalid arguments\n"); - return TRUE; } - memset(&ce, 0, sizeof(struct config_entry)); - /* get next available entry from LIST entry. */ - if (!get_next_list_entry(le, 0, NULL, &ce)) - return TRUE; - - if (ie->next) { - /* we are dealing with list_head */ - ie->next->addr = ce.addr; - ie->addr = ce.addr - ie->next->offset; - } - else { - ie->addr = ce.addr; - ie->sym_addr = ce.sym_addr; - ie->size = ce.size; - } - return FALSE; + return TRUE; } /* - * Process the config entry that has been read by get_config. - * return TRUE on success + * This function is for creating split dumpfiles by multiple + * processes. Each child process should re-open a /proc/vmcore + * file, because it prevents each other from affectting the file + * offset due to read(2) call. */ int -process_config(struct config *config) +reopen_dump_memory() { - int i; - if (config->list_entry) { - unsigned char type_flag; - char *type_name = NULL; - /* - * We are dealing with 'for' command. - * - First resolve list entry. - * - Initialize iteration entry for iteration. - * - Populate iteration entry untill list entry empty. - */ - if (!resolve_list_entry(config->list_entry, 0, NULL, - &type_name, &type_flag)) { - return FALSE; - } - if (!initialize_iteration_entry(config->iter_entry, - type_name, type_flag)) { - return FALSE; - } + close_dump_memory(); - while (!list_entry_empty(config->list_entry, - config->iter_entry)) { - for (i = 0; i < config->num_filter_symbols; i++) - update_filter_info(config->filter_symbol[i], - config->size_symbol[i]); - } + if ((info->fd_memory = open(info->name_memory, O_RDONLY)) < 0) { + ERRMSG("Can't open the dump memory(%s). %s\n", + info->name_memory, strerror(errno)); + return FALSE; } - else - update_filter_info(config->filter_symbol[0], - config->size_symbol[0]); - return TRUE; } -void -print_filter_info() +int +get_next_dump_level(int index) { - struct filter_info *fl_info = filter_info; - - DEBUG_MSG("\n"); - while (fl_info) { - DEBUG_MSG("filter address: paddr (%llx), sym_addr (%llx)," - " Size (%ld)\n", - fl_info->paddr, fl_info->address, fl_info->size); - fl_info = fl_info->next; - } -} + if (info->num_dump_level <= index) + return -1; -void -init_filter_config() -{ - filter_config.name_filterconfig = info->name_filterconfig; - filter_config.file_filterconfig = info->file_filterconfig; - filter_config.saved_token = NULL; - filter_config.token = NULL; - filter_config.cur_module = NULL; - filter_config.new_section = 0; - filter_config.line_count = 0; + return info->array_dump_level[index]; } -/* - * Read and process each config entry (filter commands) from filter config - * file. If no module debuginfo found for specified module section then skip - * to next module section. - */ int -process_config_file(const char *name_config) +delete_dumpfile(void) { - struct config *config; - int skip_section = 0; - - if (!name_config) - return FALSE; - - if ((info->file_filterconfig = fopen(name_config, "r")) == NULL) { - ERRMSG("Can't open config file(%s). %s\n", - name_config, strerror(errno)); - return FALSE; - } + int i; - init_filter_config(); + if (info->flag_flatten) + return TRUE; - while((config = get_config(skip_section)) != NULL) { - skip_section = 0; - if (config->module_name && - strcmp(config->module_name, "vmlinux")) { - /* - * if Module debuginfo is not available, then skip to - * next module section. - */ - if (!set_dwarf_debuginfo(config->module_name, - NULL, -1)) { - ERRMSG("Skipping to next Module section\n"); - skip_section = 1; - free_config(config); - continue; - } - } - else { - set_dwarf_debuginfo("vmlinux", info->name_vmlinux, - info->fd_vmlinux); - } - process_config(config); - free_config(config); + if (info->flag_split) { + for (i = 0; i < info->num_dumpfile; i++) + unlink(SPLITTING_DUMPFILE(i)); + } else { + unlink(info->name_dumpfile); } - - fclose(info->file_filterconfig); - print_filter_info(); return TRUE; } int -gather_filter_info() +writeout_multiple_dumpfiles(void) { - int ret; + int i, status, ret = TRUE; + pid_t pid; + pid_t array_pid[info->num_dumpfile]; - /* - * Before processing filter config file, load the symbol data of - * loaded modules from vmcore. - */ - set_dwarf_debuginfo("vmlinux", info->name_vmlinux, info->fd_vmlinux); - if (!load_module_symbols()) + if (!setup_splitting()) return FALSE; - ret = process_config_file(info->name_filterconfig); - - /* - * Remove modules symbol information, we dont need now. - * Reset the dwarf debuginfo to vmlinux to close open file - * descripter of module debuginfo file, if any. - */ - clean_module_symbols(); - set_dwarf_debuginfo("vmlinux", info->name_vmlinux, info->fd_vmlinux); - return ret; -} + for (i = 0; i < info->num_dumpfile; i++) { + if ((pid = fork()) < 0) { + return FALSE; -void -clear_filter_info(void) -{ - struct filter_info *prev, *fi = filter_info; - int i; + } else if (pid == 0) { /* Child */ + info->name_dumpfile = SPLITTING_DUMPFILE(i); + info->fd_bitmap = SPLITTING_FD_BITMAP(i); + info->split_start_pfn = SPLITTING_START_PFN(i); + info->split_end_pfn = SPLITTING_END_PFN(i); - /* Delete filter_info nodes that are left out. */ - while (fi) { - prev = fi; - fi = fi->next; - free(prev); - } - filter_info = NULL; - if (erase_info) { - for (i = 1; i < num_erase_info; i++) { - free(erase_info[i].symbol_expr); - free(erase_info[i].sizes); + if (!reopen_dump_memory()) + exit(1); + if ((status = writeout_dumpfile()) == FALSE) + exit(1); + else if (status == NOSPACE) + exit(2); + exit(0); } - free(erase_info); + array_pid[i] = pid; + } + for (i = 0; i < info->num_dumpfile; i++) { + waitpid(array_pid[i], &status, WUNTRACED); + if (!WIFEXITED(status) || WEXITSTATUS(status) == 1) { + ERRMSG("Child process(%d) finished imcompletely.(%d)\n", + array_pid[i], status); + ret = FALSE; + } else if ((ret == TRUE) && (WEXITSTATUS(status) == 2)) + ret = NOSPACE; } + return ret; } int @@ -9810,11 +7504,7 @@ create_dumpfile(void) return FALSE; if (!info->flag_refiltering && !info->flag_sadump) { - if (!get_elf_info()) - return FALSE; - } - if (vt.mem_flags & MEMORY_XEN) { - if (!initial_xen()) + if (!get_elf_info(info->fd_memory, info->name_memory)) return FALSE; } if (!initial()) @@ -9836,7 +7526,8 @@ retry: } } - if (info->name_filterconfig && !gather_filter_info()) + if ((info->name_filterconfig || info->name_eppic_config) + && !gather_filter_info()) return FALSE; if (!create_dump_bitmap()) @@ -10086,7 +7777,7 @@ copy_same_data(int src_fd, int dst_fd, o char *buf = NULL; if ((buf = malloc(size)) == NULL) { - ERRMSG("Can't allcate memory.\n"); + ERRMSG("Can't allocate memory.\n"); return FALSE; } if (lseek(src_fd, offset, SEEK_SET) < 0) { @@ -10165,18 +7856,16 @@ reassemble_kdump_header(void) SPLITTING_DUMPFILE(0), strerror(errno)); return FALSE; } - if (info->offset_note && info->size_note) { - offset = info->offset_note; - size = info->size_note; + if (has_pt_note()) { + get_pt_note(&offset, &size); if (!copy_same_data(fd, info->fd_dumpfile, offset, size)) { ERRMSG("Can't copy pt_note data to %s.\n", info->name_dumpfile); goto out; } } - if (info->offset_vmcoreinfo && info->size_vmcoreinfo) { - offset = info->offset_vmcoreinfo; - size = info->size_vmcoreinfo; + if (has_vmcoreinfo()) { + get_vmcoreinfo(&offset, &size); if (!copy_same_data(fd, info->fd_dumpfile, offset, size)) { ERRMSG("Can't copy vmcoreinfo data to %s.\n", info->name_dumpfile); @@ -10190,7 +7879,7 @@ reassemble_kdump_header(void) offset = (DISKDUMP_HEADER_BLOCKS + dh.sub_hdr_size) * dh.block_size; info->len_bitmap = dh.bitmap_blocks * dh.block_size; if ((buf_bitmap = malloc(info->len_bitmap)) == NULL) { - ERRMSG("Can't allcate memory for bitmap.\n"); + ERRMSG("Can't allocate memory for bitmap.\n"); goto out; } if (lseek(fd, offset, SEEK_SET) < 0) { @@ -10241,14 +7930,16 @@ int reassemble_kdump_pages(void) { int i, fd = 0, ret = FALSE; - off_t offset_first_ph, offset_ph_org; + off_t offset_first_ph, offset_ph_org, offset_eraseinfo; off_t offset_data_new, offset_zero_page = 0; unsigned long long pfn, start_pfn, end_pfn; - unsigned long long num_dumpable, num_dumped; + unsigned long long num_dumpable; + unsigned long size_eraseinfo; struct dump_bitmap bitmap2; struct disk_dump_header dh; struct page_desc pd, pd_zero; struct cache_data cd_pd, cd_data; + struct timeval tv_start; char *data = NULL; unsigned long data_buf_size = info->page_size; @@ -10265,7 +7956,7 @@ reassemble_kdump_pages(void) return FALSE; } if ((data = malloc(data_buf_size)) == NULL) { - ERRMSG("Can't allcate memory for page data.\n"); + ERRMSG("Can't allocate memory for page data.\n"); free_cache_data(&cd_pd); free_cache_data(&cd_data); return FALSE; @@ -10283,6 +7974,7 @@ reassemble_kdump_pages(void) /* * Write page header of zero-filled page. */ + gettimeofday(&tv_start, NULL); if (info->dump_level & DL_EXCLUDE_ZERO) { /* * makedumpfile outputs the data of zero-filled page at first @@ -10300,6 +7992,7 @@ reassemble_kdump_pages(void) goto out; offset_data_new += pd_zero.size; } + for (i = 0; i < info->num_dumpfile; i++) { if ((fd = open(SPLITTING_DUMPFILE(i), O_RDONLY)) < 0) { ERRMSG("Can't open a file(%s). %s\n", @@ -10367,8 +8060,8 @@ reassemble_kdump_pages(void) if (!write_cache_bufsz(&cd_data)) goto out; - info->offset_eraseinfo = cd_data.offset; - info->size_eraseinfo = 0; + offset_eraseinfo = cd_data.offset; + size_eraseinfo = 0; /* Copy eraseinfo from split dumpfiles to o/p dumpfile */ for (i = 0; i < info->num_dumpfile; i++) { if (!SPLITTING_SIZE_EI(i)) @@ -10377,7 +8070,7 @@ reassemble_kdump_pages(void) if (SPLITTING_SIZE_EI(i) > data_buf_size) { data_buf_size = SPLITTING_SIZE_EI(i); if ((data = realloc(data, data_buf_size)) == NULL) { - ERRMSG("Can't allcate memory for eraseinfo" + ERRMSG("Can't allocate memory for eraseinfo" " data.\n"); goto out; } @@ -10400,19 +8093,22 @@ reassemble_kdump_pages(void) } if (!write_cache(&cd_data, data, SPLITTING_SIZE_EI(i))) goto out; - info->size_eraseinfo += SPLITTING_SIZE_EI(i); + size_eraseinfo += SPLITTING_SIZE_EI(i); close(fd); fd = 0; } - if (info->size_eraseinfo) { + if (size_eraseinfo) { if (!write_cache_bufsz(&cd_data)) goto out; - if (!update_sub_header()) + if (!update_eraseinfo_of_sub_header(offset_eraseinfo, + size_eraseinfo)) goto out; } print_progress(PROGRESS_COPY, num_dumpable, num_dumpable); + print_execution_time(PROGRESS_COPY, &tv_start); + ret = TRUE; out: free_cache_data(&cd_pd); @@ -10653,6 +8349,68 @@ out: return ret; } +/* + * Get the amount of free memory from /proc/meminfo. + */ +unsigned long long +get_free_memory_size(void) { + char buf[BUFSIZE_FGETS]; + char unit[4]; + unsigned long long free_size = 0; + char *name_meminfo = "/proc/meminfo"; + FILE *file_meminfo; + + if ((file_meminfo = fopen(name_meminfo, "r")) == NULL) { + ERRMSG("Can't open the %s. %s\n", name_meminfo, strerror(errno)); + return FALSE; + } + + while (fgets(buf, BUFSIZE_FGETS, file_meminfo) != NULL) { + if (sscanf(buf, "MemFree: %llu %s", &free_size, unit) == 2) { + if (strcmp(unit, "kB") == 0) { + free_size *= 1024; + goto out; + } + } + } + + ERRMSG("Can't get free memory size.\n"); + free_size = 0; +out: + if (fclose(file_meminfo) < 0) + ERRMSG("Can't close the %s. %s\n", name_meminfo, strerror(errno)); + + return free_size; +} + + +/* + * Choose the lesser value of the two below as the size of cyclic buffer. + * - the size enough for storing the 1st/2nd bitmap for the whole of vmcore + * - 80% of free memory (as safety limit) + */ +int +calculate_cyclic_buffer_size(void) { + unsigned long long free_size, needed_size; + + if (info->max_mapnr <= 0) { + ERRMSG("Invalid max_mapnr(%llu).\n", info->max_mapnr); + return FALSE; + } + + /* + * free_size will be used to allocate 1st and 2nd bitmap, so it + * should be 40% of free memory to keep the size of cyclic buffer + * within 80% of free memory. + */ + free_size = get_free_memory_size() * 0.4; + needed_size = (info->max_mapnr * 2) / BITPERBYTE; + + info->bufsize_cyclic = (free_size <= needed_size) ? free_size : needed_size; + + return TRUE; +} + static struct option longopts[] = { {"split", no_argument, NULL, 's'}, {"reassemble", no_argument, NULL, 'r'}, @@ -10665,6 +8423,9 @@ static struct option longopts[] = { {"config", required_argument, NULL, 'C'}, {"help", no_argument, NULL, 'h'}, {"diskset", required_argument, NULL, 'k'}, + {"non-cyclic", no_argument, NULL, 'Y'}, + {"cyclic-buffer", required_argument, NULL, 'Z'}, + {"eppic", required_argument, NULL, 'S'}, {0, 0, 0, 0} }; @@ -10686,9 +8447,14 @@ main(int argc, char *argv[]) } initialize_tables(); + /* + * By default, makedumpfile works in constant memory space. + */ + info->flag_cyclic = TRUE; + info->block_order = DEFAULT_ORDER; message_level = DEFAULT_MSG_LEVEL; - while ((opt = getopt_long(argc, argv, "b:cDd:EFfg:hi:MRrsvXx:", longopts, + while ((opt = getopt_long(argc, argv, "b:cDd:EFfg:hi:lMpRrsvXx:", longopts, NULL)) != -1) { switch (opt) { case 'b': @@ -10698,7 +8464,7 @@ main(int argc, char *argv[]) info->name_filterconfig = optarg; break; case 'c': - info->flag_compress = 1; + info->flag_compress = DUMP_DH_COMPRESSED_ZLIB; break; case 'D': flag_debug = TRUE; @@ -10712,6 +8478,11 @@ main(int argc, char *argv[]) break; case 'F': info->flag_flatten = 1; + /* + * All messages are output to STDERR because STDOUT is + * used for outputting dump data. + */ + flag_strerr_message = TRUE; break; case 'f': info->flag_force = 1; @@ -10732,12 +8503,18 @@ main(int argc, char *argv[]) goto out; info->flag_sadump_diskset = 1; break; + case 'l': + info->flag_compress = DUMP_DH_COMPRESSED_LZO; + break; case 'm': message_level = atoi(optarg); break; case 'M': info->flag_dmesg = 1; break; + case 'p': + info->flag_compress = DUMP_DH_COMPRESSED_SNAPPY; + break; case 'P': info->xen_phys_start = strtoul(optarg, NULL, 0); break; @@ -10747,6 +8524,9 @@ main(int argc, char *argv[]) case 's': info->flag_split = 1; break; + case 'S': + info->name_eppic_config = optarg; + break; case 'r': info->flag_reassemble = 1; break; @@ -10765,10 +8545,16 @@ main(int argc, char *argv[]) case 'y': info->name_xen_syms = optarg; break; + case 'Y': + info->flag_cyclic = FALSE; + break; case 'z': info->flag_read_vmcoreinfo = 1; info->name_vmcoreinfo = optarg; break; + case 'Z': + info->bufsize_cyclic = atoi(optarg); + break; case '?': MSG("Commandline parameter is invalid.\n"); MSG("Try `makedumpfile --help' for more information.\n"); @@ -10901,8 +8687,6 @@ out: close(info->fd_dumpfile); if (info->fd_bitmap) close(info->fd_bitmap); - if (info->pt_load_segments != NULL) - free(info->pt_load_segments); if (vt.node_online_map != NULL) free(vt.node_online_map); if (info->mem_map_data != NULL) @@ -10913,7 +8697,13 @@ out: free(info->splitting_info); if (info->p2m_mfn_frame_list != NULL) free(info->p2m_mfn_frame_list); + if (info->partial_bitmap1 != NULL) + free(info->partial_bitmap1); + if (info->partial_bitmap2 != NULL) + free(info->partial_bitmap2); free(info); } + free_elf_info(); + return retcd; } diff -Nupr makedumpfile-1.3.5/makedumpfile.conf makedumpfile-1.5.3/makedumpfile.conf --- makedumpfile-1.3.5/makedumpfile.conf 2013-07-03 15:18:37.804089017 +0800 +++ makedumpfile-1.5.3/makedumpfile.conf 2013-02-18 16:47:26.000000000 +0800 @@ -6,7 +6,7 @@ ## it's members of any data type. In case of filtering of data pointed by ## void * pointer, user needs to provide size to filter out. ## -## Please refer to manpage makedumpfile.conf(8) for more details. +## Please refer to manpage makedumpfile.conf(5) for more details. ## ## ## - Module section diff -Nupr makedumpfile-1.3.5/makedumpfile.h makedumpfile-1.5.3/makedumpfile.h --- makedumpfile-1.3.5/makedumpfile.h 2013-07-03 15:18:37.900089017 +0800 +++ makedumpfile-1.5.3/makedumpfile.h 2013-02-18 16:47:26.000000000 +0800 @@ -1,7 +1,7 @@ /* * makedumpfile.h * - * Copyright (C) 2006, 2007, 2008, 2009 NEC Corporation + * Copyright (C) 2006, 2007, 2008, 2009, 2011 NEC Corporation * * 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 @@ -28,12 +28,17 @@ #include #include #include -#include -#include #include -#include #include #include +#ifdef USELZO +#include +#endif +#ifdef USESNAPPY +#include +#endif +#include "common.h" +#include "dwarf_info.h" #include "diskdump_mod.h" #include "sadump_mod.h" @@ -66,9 +71,15 @@ int get_mem_type(void); * The following values are for linux-2.6.25 or former. */ #define PG_lru_ORIGINAL (5) +#define PG_slab_ORIGINAL (7) #define PG_private_ORIGINAL (11) /* Has something at ->private */ #define PG_swapcache_ORIGINAL (15) /* Swap page: swp_entry_t in private */ +#define PAGE_BUDDY_MAPCOUNT_VALUE_v2_6_38 (-2) +#define PAGE_BUDDY_MAPCOUNT_VALUE_v2_6_39_to_latest_version (-128) + +#define PAGE_FLAGS_SIZE_v2_6_27_to_latest_version (4) + #define PAGE_MAPPING_ANON (1) #define LSEEKED_BITMAP (1) @@ -76,12 +87,35 @@ int get_mem_type(void); #define LSEEKED_PDATA (3) /* + * Xen page flags + */ +#define BITS_PER_LONG (BITPERBYTE * sizeof(long)) +#define PG_shift(idx) (BITS_PER_LONG - (idx)) +#define PG_mask(x, idx) (x ## UL << PG_shift(idx)) + /* Cleared when the owning guest 'frees' this page. */ +#define PGC_allocated PG_mask(1, 1) + /* Page is Xen heap? */ +#define PGC_xen_heap PG_mask(1, 2) + /* Page is broken? */ +#define PGC_broken PG_mask(1, 7) + /* Mutually-exclusive page states: { inuse, offlining, offlined, free }. */ +#define PGC_state PG_mask(3, 9) +#define PGC_state_inuse PG_mask(0, 9) +#define PGC_state_offlining PG_mask(1, 9) +#define PGC_state_offlined PG_mask(2, 9) +#define PGC_state_free PG_mask(3, 9) +#define page_state_is(ci, st) (((ci)&PGC_state) == PGC_state_##st) + + /* Count of references to this frame. */ +#define PGC_count_width PG_shift(9) +#define PGC_count_mask ((1UL<page_size) #define PAGESHIFT() (info->page_shift) -#define PAGEOFFSET(X) (((unsigned long)(X)) & (PAGESIZE() - 1)) -#define PAGEBASE(X) (((unsigned long)(X)) & ~(PAGESIZE() - 1)) -#define _2MB_PAGE_MASK (~((2*1048576)-1)) -#define paddr_to_pfn(X) ((unsigned long long)(X) >> PAGESHIFT()) -#define pfn_to_paddr(X) ((unsigned long long)(X) << PAGESHIFT()) +#define PAGEOFFSET(X) (((unsigned long long)(X)) & (PAGESIZE() - 1)) +#define PAGEBASE(X) (((unsigned long long)(X)) & ~(PAGESIZE() - 1)) /* * for SPARSEMEM @@ -141,13 +174,6 @@ isAnon(unsigned long mapping) #define NR_MEM_SECTIONS() (1UL << SECTIONS_SHIFT()) /* - * Incorrect address - */ -#define NOT_MEMMAP_ADDR (0x0) -#define NOT_KV_ADDR (0x0) -#define NOT_PADDR (ULONGLONG_MAX) - -/* * Dump Level */ #define MIN_DUMP_LEVEL (0) @@ -162,67 +188,6 @@ isAnon(unsigned long mapping) #define DL_EXCLUDE_USER_DATA (0x008) /* Exclude UserProcessData Pages */ #define DL_EXCLUDE_FREE (0x010) /* Exclude Free Pages */ -/* - * Message Level - */ -#define MIN_MSG_LEVEL (0) -#define MAX_MSG_LEVEL (31) -#define DEFAULT_MSG_LEVEL (7) /* Print the progress indicator, the - common message, the error message */ -#define ML_PRINT_PROGRESS (0x001) /* Print the progress indicator */ -#define ML_PRINT_COMMON_MSG (0x002) /* Print the common message */ -#define ML_PRINT_ERROR_MSG (0x004) /* Print the error message */ -#define ML_PRINT_DEBUG_MSG (0x008) /* Print the debugging message */ -#define ML_PRINT_REPORT_MSG (0x010) /* Print the report message */ -extern int message_level; -extern int flag_ignore_r_char; - -#define MSG(x...) \ -do { \ - if (message_level & ML_PRINT_COMMON_MSG) { \ - if (info->flag_flatten) \ - fprintf(stderr, x); \ - else \ - fprintf(stdout, x); \ - } \ -} while (0) - -#define ERRMSG(x...) \ -do { \ - if (message_level & ML_PRINT_ERROR_MSG) { \ - fprintf(stderr, __FUNCTION__); \ - fprintf(stderr, ": "); \ - fprintf(stderr, x); \ - } \ -} while (0) - -#define PROGRESS_MSG(x...) \ -do { \ - if (message_level & ML_PRINT_PROGRESS) { \ - fprintf(stderr, x); \ - } \ -} while (0) - -#define DEBUG_MSG(x...) \ -do { \ - if (message_level & ML_PRINT_DEBUG_MSG) { \ - if (info->flag_flatten) \ - fprintf(stderr, x); \ - else \ - fprintf(stdout, x); \ - } \ -} while (0) - -#define REPORT_MSG(x...) \ -do { \ - if (message_level & ML_PRINT_REPORT_MSG) { \ - if (info->flag_flatten) \ - fprintf(stderr, x); \ - else \ - fprintf(stdout, x); \ - } \ -} while (0) - /* * For parse_line() @@ -241,6 +206,7 @@ do { \ #define FILENAME_BITMAP "kdump_bitmapXXXXXX" #define FILENAME_STDOUT "STDOUT" + /* * Minimam vmcore has 2 ProgramHeaderTables(PT_NOTE and PT_LOAD). */ @@ -250,17 +216,20 @@ do { \ sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)+sizeof(Elf64_Phdr) #define MIN_ELF_HEADER_SIZE \ MAX(MIN_ELF32_HEADER_SIZE, MIN_ELF64_HEADER_SIZE) -#define STRNEQ(A, B) (A && B && \ +static inline int string_exists(char *s) { return (s ? TRUE : FALSE); } +#define STRNEQ(A, B)(string_exists((char *)(A)) && \ + string_exists((char *)(B)) && \ (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0)) #define USHORT(ADDR) *((unsigned short *)(ADDR)) #define UINT(ADDR) *((unsigned int *)(ADDR)) #define ULONG(ADDR) *((unsigned long *)(ADDR)) +#define ULONGLONG(ADDR) *((unsigned long long *)(ADDR)) + /* * for symbol */ -#define NOT_FOUND_SYMBOL (0) #define INVALID_SYMBOL_DATA (ULONG_MAX) #define SYMBOL(X) (symbol_table.X) #define SYMBOL_INIT(symbol, str_symbol) \ @@ -290,34 +259,31 @@ do { \ /* * for structure */ -#define NOT_FOUND_LONG_VALUE (-1) -#define NOT_FOUND_STRUCTURE (NOT_FOUND_LONG_VALUE) -#define FAILED_DWARFINFO (-2) -#define INVALID_STRUCTURE_DATA (-3) -#define FOUND_ARRAY_TYPE (LONG_MAX - 1) - #define SIZE(X) (size_table.X) #define OFFSET(X) (offset_table.X) #define ARRAY_LENGTH(X) (array_table.X) #define SIZE_INIT(X, Y) \ do { \ - if ((SIZE(X) = get_structure_size(Y, 0)) == FAILED_DWARFINFO) \ + if ((SIZE(X) = get_structure_size(Y, DWARF_INFO_GET_STRUCT_SIZE)) \ + == FAILED_DWARFINFO) \ return FALSE; \ } while (0) #define TYPEDEF_SIZE_INIT(X, Y) \ do { \ - if ((SIZE(X) = get_structure_size(Y, 1)) == FAILED_DWARFINFO) \ + if ((SIZE(X) = get_structure_size(Y, DWARF_INFO_GET_TYPEDEF_SIZE)) \ + == FAILED_DWARFINFO) \ return FALSE; \ } while (0) -#define OFFSET_INIT(X, Y, Z) \ +#define ENUM_TYPE_SIZE_INIT(X, Y) \ do { \ - if ((OFFSET(X) = get_member_offset(Y, Z, DWARF_INFO_GET_MEMBER_OFFSET)) \ - == FAILED_DWARFINFO) \ - return FALSE; \ + if ((SIZE(X) = get_structure_size(Y, \ + DWARF_INFO_GET_ENUMERATION_TYPE_SIZE)) \ + == FAILED_DWARFINFO) \ + return FALSE; \ } while (0) -#define OFFSET_IN_UNION_INIT(X, Y, Z) \ +#define OFFSET_INIT(X, Y, Z) \ do { \ - if ((OFFSET(X) = get_member_offset(Y, Z, DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION)) \ + if ((OFFSET(X) = get_member_offset(Y, Z, DWARF_INFO_GET_MEMBER_OFFSET)) \ == FAILED_DWARFINFO) \ return FALSE; \ } while (0) @@ -386,7 +352,6 @@ do { \ /* * for number */ -#define NOT_FOUND_NUMBER (NOT_FOUND_LONG_VALUE) #define NUMBER(X) (number_table.X) #define ENUM_NUMBER_INIT(number, str_number) \ @@ -460,17 +425,13 @@ do { \ #define KVER_MIN_SHIFT 16 #define KERNEL_VERSION(x,y,z) (((x) << KVER_MAJ_SHIFT) | ((y) << KVER_MIN_SHIFT) | (z)) #define OLDEST_VERSION KERNEL_VERSION(2, 6, 15)/* linux-2.6.15 */ -#define LATEST_VERSION KERNEL_VERSION(2, 6, 32)/* linux-2.6.32 */ +#define LATEST_VERSION KERNEL_VERSION(3, 6, 7)/* linux-3.6.7 */ /* * vmcoreinfo in /proc/vmcore */ #define VMCOREINFO_BYTES (4096) -#define VMCOREINFO_NOTE_NAME "VMCOREINFO" -#define VMCOREINFO_NOTE_NAME_BYTES (sizeof(VMCOREINFO_NOTE_NAME)) #define FILENAME_VMCOREINFO "/tmp/vmcoreinfoXXXXXX" -#define VMCOREINFO_XEN_NOTE_NAME "VMCOREINFO_XEN" -#define VMCOREINFO_XEN_NOTE_NAME_BYTES (sizeof(VMCOREINFO_XEN_NOTE_NAME)) /* * field name of vmcoreinfo file @@ -491,30 +452,12 @@ do { \ /* * common value */ -#define TRUE (1) -#define FALSE (0) -#define ERROR (-1) #define NOSPACE (-1) /* code of write-error due to nospace */ -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define LONG_MAX ((long)(~0UL>>1)) -#define ULONG_MAX (~0UL) -#define ULONGLONG_MAX (~0ULL) #define DEFAULT_ORDER (4) #define TIMEOUT_STDIN (600) #define SIZE_BUF_STDIN (4096) -#define ELF32 (1) -#define ELF64 (2) #define STRLEN_OSRELEASE (65) /* same length as diskdump.h */ -#define XEN_ELFNOTE_CRASH_INFO (0x1000001) -#define SIZE_XEN_CRASH_INFO_V2 (sizeof(unsigned long) * 10) - -#define MAX_SIZE_STR_LEN (26) - -#define ERASEINFO_NOTE_NAME "ERASEINFO" -#define ERASEINFO_NOTE_NAME_BYTES (sizeof(ERASEINFO_NOTE_NAME)) - /* * The value of dependence on machine */ @@ -524,6 +467,23 @@ do { \ #define VMEMMAP_START (info->vmemmap_start) #define VMEMMAP_END (info->vmemmap_end) +#ifdef __arm__ +#define KVBASE_MASK (0xffff) +#define KVBASE (SYMBOL(_stext) & ~KVBASE_MASK) +#define _SECTION_SIZE_BITS (28) +#define _MAX_PHYSMEM_BITS (32) +#define ARCH_PFN_OFFSET (info->phys_base >> PAGESHIFT()) + +#define PTRS_PER_PTE (512) +#define PGDIR_SHIFT (21) +#define PMD_SHIFT (21) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE - 1)) + +#define _PAGE_PRESENT (1 << 0) + +#endif /* arm */ + #ifdef __x86__ #define __PAGE_OFFSET (0xc0000000) #define __VMALLOC_RESERVE (128 << 20) @@ -551,7 +511,10 @@ do { \ #define _PAGE_PRESENT (0x001) #define _PAGE_PSE (0x080) -#define ENTRY_MASK (~0x8000000000000fffULL) +/* Physical addresses are up to 52 bits (AMD64). + * Mask off bits 52-62 (reserved) and bit 63 (NX). + */ +#define ENTRY_MASK (~0xfff0000000000fffULL) #endif /* x86 */ @@ -584,8 +547,12 @@ do { \ #define PML4_SHIFT (39) #define PTRS_PER_PML4 (512) #define PGDIR_SHIFT (30) +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE - 1)) #define PTRS_PER_PGD (512) #define PMD_SHIFT (21) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE - 1)) #define PTRS_PER_PMD (512) #define PTRS_PER_PTE (512) #define PTE_SHIFT (12) @@ -596,21 +563,29 @@ do { \ #define pte_index(address) (((address) >> PTE_SHIFT) & (PTRS_PER_PTE - 1)) #define _PAGE_PRESENT (0x001) -#define _PAGE_PSE (0x080) /* 2MB page */ - -#define __PHYSICAL_MASK_SHIFT (40) -#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) -#define PHYSICAL_PAGE_MASK (~(PAGESIZE()-1) & (__PHYSICAL_MASK << PAGESHIFT())) +#define _PAGE_PSE (0x080) /* 2MB or 1GB page */ #endif /* x86_64 */ -#ifdef __powerpc__ +#ifdef __powerpc64__ #define __PAGE_OFFSET (0xc000000000000000) #define KERNELBASE PAGE_OFFSET #define VMALLOCBASE (0xD000000000000000) #define KVBASE (SYMBOL(_stext)) #define _SECTION_SIZE_BITS (24) +#define _MAX_PHYSMEM_BITS_ORIG (44) +#define _MAX_PHYSMEM_BITS_3_7 (46) +#endif + +#ifdef __powerpc32__ + +#define __PAGE_OFFSET (0xc0000000) +#define KERNELBASE PAGE_OFFSET +#define VMALL_START (info->vmalloc_start) +#define KVBASE (SYMBOL(_stext)) +#define _SECTION_SIZE_BITS (24) #define _MAX_PHYSMEM_BITS (44) + #endif #ifdef __s390x__ @@ -618,7 +593,8 @@ do { \ #define KERNELBASE (0) #define KVBASE KERNELBASE #define _SECTION_SIZE_BITS (28) -#define _MAX_PHYSMEM_BITS (42) +#define _MAX_PHYSMEM_BITS_ORIG (42) +#define _MAX_PHYSMEM_BITS_3_3 (46) /* Bits in the segment/region table address-space-control-element */ #define _ASCE_TYPE_MASK 0x0c @@ -632,6 +608,7 @@ do { \ #define _REGION_ENTRY_TYPE_MASK 0x0c /* region table type mask */ #define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */ #define _REGION_ENTRY_LENGTH 0x03 /* region table length */ +#define _REGION_ENTRY_LARGE 0x400 #define _REGION_OFFSET_MASK 0x7ffUL /* region/segment table offset mask */ #define RSG_TABLE_LEVEL(x) (((x) & _REGION_ENTRY_TYPE_MASK) >> 2) @@ -644,7 +621,6 @@ do { \ #define _SEGMENT_INDEX_SHIFT 20 /* Hardware bits in the page table entry */ -#define _PAGE_CO 0x100 /* HW Change-bit override */ #define _PAGE_ZERO 0x800 /* Bit pos 52 must conatin zero */ #define _PAGE_INVALID 0x400 /* HW invalid bit */ #define _PAGE_INDEX_SHIFT 12 @@ -710,6 +686,16 @@ do { \ /* * The function of dependence on machine */ +#ifdef __arm__ +int get_phys_base_arm(void); +int get_machdep_info_arm(void); +unsigned long long vaddr_to_paddr_arm(unsigned long vaddr); +#define get_phys_base() get_phys_base_arm() +#define get_machdep_info() get_machdep_info_arm() +#define get_versiondep_info() TRUE +#define vaddr_to_paddr(X) vaddr_to_paddr_arm(X) +#endif /* arm */ + #ifdef __x86__ int get_machdep_info_x86(void); int get_versiondep_info_x86(void); @@ -731,14 +717,23 @@ unsigned long long vaddr_to_paddr_x86_64 #define vaddr_to_paddr(X) vaddr_to_paddr_x86_64(X) #endif /* x86_64 */ -#ifdef __powerpc__ /* powerpc */ +#ifdef __powerpc64__ /* powerpc64 */ int get_machdep_info_ppc64(void); unsigned long long vaddr_to_paddr_ppc64(unsigned long vaddr); #define get_phys_base() TRUE #define get_machdep_info() get_machdep_info_ppc64() #define get_versiondep_info() TRUE #define vaddr_to_paddr(X) vaddr_to_paddr_ppc64(X) -#endif /* powerpc */ +#endif /* powerpc64 */ + +#ifdef __powerpc32__ /* powerpc32 */ +int get_machdep_info_ppc(void); +unsigned long long vaddr_to_paddr_ppc(unsigned long vaddr); +#define get_phys_base() TRUE +#define get_machdep_info() get_machdep_info_ppc() +#define get_versiondep_info() TRUE +#define vaddr_to_paddr(X) vaddr_to_paddr_ppc(X) +#endif /* powerpc32 */ #ifdef __s390x__ /* s390x */ int get_machdep_info_s390x(void); @@ -760,13 +755,50 @@ unsigned long long vaddr_to_paddr_ia64(u #define VADDR_REGION(X) (((unsigned long)(X)) >> REGION_SHIFT) #endif /* ia64 */ -struct pt_load_segment { - off_t file_offset; - unsigned long long phys_start; - unsigned long long phys_end; - unsigned long long virt_start; - unsigned long long virt_end; -}; +#ifndef ARCH_PFN_OFFSET +#define ARCH_PFN_OFFSET 0 +#endif +#define paddr_to_pfn(X) \ + (((unsigned long long)(X) >> PAGESHIFT()) - ARCH_PFN_OFFSET) +#define pfn_to_paddr(X) \ + (((unsigned long long)(X) + ARCH_PFN_OFFSET) << PAGESHIFT()) + +/* Format of Xen crash info ELF note */ +typedef struct { + unsigned long xen_major_version; + unsigned long xen_minor_version; + unsigned long xen_extra_version; + unsigned long xen_changeset; + unsigned long xen_compiler; + unsigned long xen_compile_date; + unsigned long xen_compile_time; + unsigned long tainted; +} xen_crash_info_com_t; + +typedef struct { + xen_crash_info_com_t com; +#if defined(__x86__) || defined(__x86_64__) + /* added by changeset 2b43fb3afb3e: */ + unsigned long dom0_pfn_to_mfn_frame_list_list; +#endif +#if defined(__ia64__) + /* added by changeset d7c3b12014b3: */ + unsigned long dom0_mm_pgd_mfn; +#endif +} xen_crash_info_t; + +/* changeset 439a3e9459f2 added xen_phys_start + * to the middle of the struct... */ +typedef struct { + xen_crash_info_com_t com; +#if defined(__x86__) || defined(__x86_64__) + unsigned long xen_phys_start; + unsigned long dom0_pfn_to_mfn_frame_list_list; +#endif +#if defined(__ia64__) + unsigned long dom0_mm_pgd_mfn; +#endif +} xen_crash_info_v2_t; struct mem_map_data { unsigned long long pfn_start; @@ -790,6 +822,8 @@ struct cache_data { size_t cache_size; off_t offset; }; +typedef unsigned long int ulong; +typedef unsigned long long int ulonglong; /* * makedumpfile header @@ -839,7 +873,7 @@ struct DumpInfo { int num_dump_level; /* number of dump level */ int array_dump_level[NUM_ARRAY_DUMP_LEVEL]; int flag_compress; /* flag of compression */ - int flag_elf64_memory; /* flag of ELF64 memory */ + int flag_lzo_support; /* flag of LZO compression support */ int flag_elf_dumpfile; /* flag of creating ELF dumpfile */ int flag_generate_vmcoreinfo;/* flag of generating vmcoreinfo file */ int flag_read_vmcoreinfo; /* flag of reading vmcoreinfo file */ @@ -850,6 +884,7 @@ struct DumpInfo { int flag_rearrange; /* flag of creating dumpfile from flattened format */ int flag_split; /* splitting vmcore */ + int flag_cyclic; /* cyclic processing to keep memory consumption */ int flag_reassemble; /* reassemble multiple dumpfiles into one */ int flag_refiltering; /* refilter from kdump-compressed file */ int flag_force; /* overwrite existing stuff */ @@ -859,7 +894,6 @@ struct DumpInfo { unsigned long vaddr_for_vtop; /* virtual address for debugging */ long page_size; /* size of page */ long page_shift; - int nr_cpus; /* number of cpu */ unsigned long long max_mapnr; /* number of page descriptor */ unsigned long page_offset; unsigned long section_size_bits; @@ -880,6 +914,12 @@ struct DumpInfo { FILE *file_filterconfig; /* + * Filter config file containing eppic language filtering rules + * to filter out kernel data from vmcore + */ + char *name_eppic_config; + + /* * diskdimp info: */ int block_order; @@ -893,11 +933,8 @@ struct DumpInfo { /* * ELF header info: */ - unsigned int num_load_memory; unsigned int num_load_dumpfile; - size_t offset_load_memory; size_t offset_load_dumpfile; - struct pt_load_segment *pt_load_segments; /* * mem_map info: @@ -943,31 +980,28 @@ struct DumpInfo { char release[STRLEN_OSRELEASE]; /* - * vmcoreinfo in dump memory image info: - */ - off_t offset_vmcoreinfo; - unsigned long size_vmcoreinfo; - off_t offset_vmcoreinfo_xen; - unsigned long size_vmcoreinfo_xen; - - /* * ELF NOTE section in dump memory image info: */ - off_t offset_note; off_t offset_note_dumpfile; - unsigned long size_note; /* * erased information in dump memory image info: */ - off_t offset_eraseinfo; - unsigned long size_eraseinfo; + unsigned long size_elf_eraseinfo; /* * for Xen extraction */ - off_t offset_xen_crash_info; - unsigned long size_xen_crash_info; + union { /* Both versions of Xen crash info: */ + xen_crash_info_com_t *com; /* common fields */ + xen_crash_info_t *v1; /* without xen_phys_start */ + xen_crash_info_v2_t *v2; /* changeset 439a3e9459f2 */ + } xen_crash_info; + int xen_crash_info_v; /* Xen crash info version: + * 0 .. xen_crash_info_com_t + * 1 .. xen_crash_info_t + * 2 .. xen_crash_info_v2_t */ + unsigned long long dom0_mapnr; /* The number of page in domain-0. * Different from max_mapnr. * max_mapnr is the number of page @@ -980,10 +1014,13 @@ struct DumpInfo { unsigned long alloc_bitmap; unsigned long dom0; unsigned long p2m_frames; - unsigned long p2m_mfn; unsigned long *p2m_mfn_frame_list; int num_domain; struct domain_list *domain_list; +#if defined(__x86_64__) + unsigned long xen_virt_start; + unsigned long directmap_virt_end; +#endif /* * for splitting @@ -992,10 +1029,26 @@ struct DumpInfo { unsigned long long split_end_pfn; /* + * for cyclic processing + */ + char *partial_bitmap1; + char *partial_bitmap2; + unsigned long long cyclic_start_pfn; + unsigned long long cyclic_end_pfn; + unsigned long long num_dumpable; + unsigned long bufsize_cyclic; + unsigned long pfn_cyclic; + + /* * sadump info: */ int flag_sadump_diskset; enum sadump_format_type flag_sadump; /* sadump format type */ + /* + * for filtering free pages managed by buddy system: + */ + int (*page_is_buddy)(unsigned long flags, unsigned int _mapcount, + unsigned long private, unsigned int _count); }; extern struct DumpInfo *info; @@ -1029,13 +1082,6 @@ struct module_info { struct symbol_info *sym_info; }; -struct module_sym_table { - unsigned int num_modules; - unsigned int current_mod; - struct module_info *modules; -}; - -extern struct module_sym_table mod_st; struct symbol_table { unsigned long long mem_map; @@ -1059,7 +1105,12 @@ struct symbol_table { unsigned long long log_buf; unsigned long long log_buf_len; unsigned long long log_end; + unsigned long long log_first_idx; + unsigned long long log_next_idx; unsigned long long max_pfn; + unsigned long long node_remap_start_vaddr; + unsigned long long node_remap_end_vaddr; + unsigned long long node_remap_start_pfn; /* * for Xen extraction @@ -1135,6 +1186,9 @@ struct size_table { long cpumask_t; long kexec_segment; long elf64_hdr; + long log; + + long pageflags; }; struct offset_table { @@ -1143,6 +1197,8 @@ struct offset_table { long _count; long mapping; long lru; + long _mapcount; + long private; } page; struct mem_section { long section_mem_map; @@ -1264,6 +1320,13 @@ struct offset_table { long p_paddr; long p_memsz; } elf64_phdr; + + struct log_s { + long ts_nsec; + long len; + long text_len; + } log; + }; /* @@ -1278,6 +1341,7 @@ struct array_table { long mem_section; long node_memblk; long __per_cpu_offset; + long node_remap_start_pfn; /* * Structure @@ -1303,9 +1367,13 @@ struct number_table { long PG_lru; long PG_private; long PG_swapcache; + long PG_buddy; + long PG_slab; + long PG_hwpoison; + + long PAGE_BUDDY_MAPCOUNT_VALUE; }; -#define LEN_SRCFILE (100) struct srcfile_table { /* * typedef @@ -1320,152 +1388,9 @@ extern struct array_table array_table; extern struct number_table number_table; extern struct srcfile_table srcfile_table; -/* - * Debugging information - */ -#define DEFAULT_DEBUGINFO_PATH "/usr/lib/debug" - -enum { - DWARF_INFO_GET_STRUCT_SIZE, - DWARF_INFO_GET_MEMBER_OFFSET, - DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION, - DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION, - DWARF_INFO_GET_MEMBER_ARRAY_LENGTH, - DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH, - DWARF_INFO_GET_TYPEDEF_SIZE, - DWARF_INFO_GET_TYPEDEF_SRCNAME, - DWARF_INFO_GET_ENUM_NUMBER, - DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE, - DWARF_INFO_GET_SYMBOL_TYPE, - DWARF_INFO_GET_MEMBER_TYPE, -}; - -struct dwarf_info { - unsigned int cmd; /* IN */ - int fd_debuginfo; /* IN */ - char *name_debuginfo; /* IN */ - char *module_name; /* IN */ - char *struct_name; /* IN */ - char *symbol_name; /* IN */ - char *member_name; /* IN */ - char *enum_name; /* IN */ - Elf *elfd; /* OUT */ - Dwarf *dwarfd; /* OUT */ - Dwfl *dwfl; /* OUT */ - char *type_name; /* OUT */ - long struct_size; /* OUT */ - long member_offset; /* OUT */ - long array_length; /* OUT */ - long enum_number; /* OUT */ - unsigned char type_flag; /* OUT */ - char src_name[LEN_SRCFILE]; /* OUT */ -}; - -/* flags for dwarf_info.type_flag */ -#define TYPE_BASE 0x01 -#define TYPE_ARRAY 0x02 -#define TYPE_PTR 0x04 -#define TYPE_STRUCT 0x08 -#define TYPE_LIST_HEAD 0x10 - -extern struct dwarf_info dwarf_info; - -/* - * Erase information, original symbol expressions. - */ -struct erase_info { - char *symbol_expr; - int num_sizes; - long *sizes; - int erased; /* 1= erased, 0= Not erased */ -}; - -/* - * Filtering information - */ -struct filter_info { - unsigned long long address; - unsigned long long paddr; - long size; - - /* direct access to update erase information node */ - int erase_info_idx; /* 0= invalid index */ - int size_idx; - - struct filter_info *next; - unsigned short nullify; -}; - -struct config_entry { - char *name; - char *type_name; - char *symbol_expr; /* original symbol expression */ - unsigned short flag; - unsigned short nullify; - unsigned long long sym_addr; /* Symbol address */ - unsigned long addr; /* Symbol address or - value pointed by sym_addr */ - unsigned long long cmp_addr; /* for LIST_ENTRY */ - unsigned long offset; - unsigned long type_flag; - long array_length; - long index; - long size; - int line; /* Line number in config file. */ - int erase_info_idx; /* 0= invalid index */ - struct config_entry *refer_to; - struct config_entry *next; -}; - -/* flags for config_entry.flag */ -#define FILTER_ENTRY 0x0001 -#define SIZE_ENTRY 0x0002 -#define ITERATION_ENTRY 0x0004 -#define LIST_ENTRY 0x0008 -#define SYMBOL_ENTRY 0x0010 -#define VAR_ENTRY 0x0020 -#define TRAVERSAL_ENTRY 0x0040 -#define ENTRY_RESOLVED 0x8000 - -/* - * Filter config information - */ -struct filter_config { - char *name_filterconfig; - FILE *file_filterconfig; - char *cur_module; - char *saved_token; - char *token; - int new_section; - int line_count; -}; - -#define CONFIG_SKIP_SECTION 0x01 -#define CONFIG_NEW_CMD 0x02 - -struct config { - char *module_name; - struct config_entry *iter_entry; - struct config_entry *list_entry; - int num_filter_symbols; - struct config_entry **filter_symbol; - struct config_entry **size_symbol; -}; - -#define IS_KEYWORD(tkn) \ - (!strcmp(tkn, "erase") || !strcmp(tkn, "size") || \ - !strcmp(tkn, "nullify") || !strcmp(tkn, "for") || \ - !strcmp(tkn, "in") || !strcmp(tkn, "within") || \ - !strcmp(tkn, "endfor")) int readmem(int type_addr, unsigned long long addr, void *bufptr, size_t size); -off_t paddr_to_offset(unsigned long long paddr); -unsigned long long vaddr_to_paddr_general(unsigned long long vaddr); -int check_elf_format(int fd, char *filename, int *phnum, int *num_load); -int get_elf64_phdr(int fd, char *filename, int num, Elf64_Phdr *phdr); -int get_elf32_phdr(int fd, char *filename, int num, Elf32_Phdr *phdr); int get_str_osrelease_from_vmlinux(void); -int get_pt_note_info(off_t off_note, unsigned long sz_note); int read_vmcoreinfo_xen(void); int exclude_xen_user_domain(void); unsigned long long get_num_dumpable(void); @@ -1488,12 +1413,19 @@ struct domain_list { #define PAGES_PER_MAPWORD (sizeof(unsigned long) * 8) #define MFNS_PER_FRAME (info->page_size / sizeof(unsigned long)) +#ifdef __arm__ +#define kvtop_xen(X) FALSE +#define get_xen_basic_info_arch(X) FALSE +#define get_xen_info_arch(X) FALSE +#endif /* arm */ + #ifdef __x86__ #define HYPERVISOR_VIRT_START_PAE (0xF5800000UL) #define HYPERVISOR_VIRT_START (0xFC000000UL) #define HYPERVISOR_VIRT_END (0xFFFFFFFFUL) #define DIRECTMAP_VIRT_START (0xFF000000UL) #define DIRECTMAP_VIRT_END (0xFFC00000UL) +#define FRAMETABLE_VIRT_START (0xF6800000UL) #define is_xen_vaddr(x) \ ((x) >= HYPERVISOR_VIRT_START_PAE && (x) < HYPERVISOR_VIRT_END) @@ -1503,6 +1435,8 @@ struct domain_list { unsigned long long kvtop_xen_x86(unsigned long kvaddr); #define kvtop_xen(X) kvtop_xen_x86(X) +int get_xen_basic_info_x86(void); +#define get_xen_basic_info_arch(X) get_xen_basic_info_x86(X) int get_xen_info_x86(void); #define get_xen_info_arch(X) get_xen_info_x86(X) @@ -1510,26 +1444,37 @@ int get_xen_info_x86(void); #ifdef __x86_64__ -#define ENTRY_MASK (~0x8000000000000fffULL) +/* The architectural limit for physical addresses is 52 bits. + * Mask off bits 52-62 (available for OS use) and bit 63 (NX). + */ +#define ENTRY_MASK (~0xfff0000000000fffULL) #define MAX_X86_64_FRAMES (info->page_size / sizeof(unsigned long)) #define PAGE_OFFSET_XEN_DOM0 (0xffff880000000000) /* different from linux */ #define HYPERVISOR_VIRT_START (0xffff800000000000) #define HYPERVISOR_VIRT_END (0xffff880000000000) #define DIRECTMAP_VIRT_START (0xffff830000000000) -#define DIRECTMAP_VIRT_END (0xffff840000000000) -#define XEN_VIRT_START (0xffff828c80000000) +#define DIRECTMAP_VIRT_END_V3 (0xffff840000000000) +#define DIRECTMAP_VIRT_END_V4 (0xffff880000000000) +#define DIRECTMAP_VIRT_END (info->directmap_virt_end) +#define XEN_VIRT_START_V3 (0xffff828c80000000) +#define XEN_VIRT_START_V4 (0xffff82c480000000) +#define XEN_VIRT_START (info->xen_virt_start) +#define XEN_VIRT_END (XEN_VIRT_START + (1UL << 30)) +#define FRAMETABLE_VIRT_START 0xffff82f600000000 #define is_xen_vaddr(x) \ ((x) >= HYPERVISOR_VIRT_START && (x) < HYPERVISOR_VIRT_END) #define is_direct(x) \ ((x) >= DIRECTMAP_VIRT_START && (x) < DIRECTMAP_VIRT_END) #define is_xen_text(x) \ - ((x) >= XEN_VIRT_START && (x) < DIRECTMAP_VIRT_START) + ((x) >= XEN_VIRT_START && (x) < XEN_VIRT_END) unsigned long long kvtop_xen_x86_64(unsigned long kvaddr); #define kvtop_xen(X) kvtop_xen_x86_64(X) +int get_xen_basic_info_x86_64(void); +#define get_xen_basic_info_arch(X) get_xen_basic_info_x86_64(X) int get_xen_info_x86_64(void); #define get_xen_info_arch(X) get_xen_info_x86_64(X) @@ -1565,18 +1510,22 @@ int get_xen_info_x86_64(void); unsigned long long kvtop_xen_ia64(unsigned long kvaddr); #define kvtop_xen(X) kvtop_xen_ia64(X) +int get_xen_basic_info_ia64(void); +#define get_xen_basic_info_arch(X) get_xen_basic_info_ia64(X) int get_xen_info_ia64(void); #define get_xen_info_arch(X) get_xen_info_ia64(X) #endif /* __ia64 */ -#ifdef __powerpc__ /* powerpc */ +#if defined(__powerpc64__) || defined(__powerpc32__) /* powerpcXX */ #define kvtop_xen(X) FALSE +#define get_xen_basic_info_arch(X) FALSE #define get_xen_info_arch(X) FALSE -#endif /* powerpc */ +#endif /* powerpcXX */ #ifdef __s390x__ /* s390x */ #define kvtop_xen(X) FALSE +#define get_xen_basic_info_arch(X) FALSE #define get_xen_info_arch(X) FALSE #endif /* s390x */ @@ -1603,6 +1552,24 @@ is_dumpable(struct dump_bitmap *bitmap, } static inline int +is_dumpable_cyclic(char *bitmap, unsigned long long pfn) +{ + if (pfn < info->cyclic_start_pfn || info->cyclic_end_pfn <= pfn) + return FALSE; + else + return is_on(bitmap, pfn - info->cyclic_start_pfn); +} + +static inline int +is_cyclic_region(unsigned long long pfn) +{ + if (pfn < info->cyclic_start_pfn || info->cyclic_end_pfn <= pfn) + return FALSE; + else + return TRUE; +} + +static inline int is_zero_page(unsigned char *buf, long page_size) { size_t i; @@ -1687,4 +1654,13 @@ struct elf_prstatus { #endif +/* + * Function Prototype. + */ +unsigned long long get_num_dumpable_cyclic(void); +int get_loads_dumpfile_cyclic(void); +int initial_xen(void); +unsigned long long get_free_memory_size(void); +int calculate_cyclic_buffer_size(void); + #endif /* MAKEDUMPFILE_H */ diff -Nupr makedumpfile-1.3.5/makedumpfile.spec makedumpfile-1.5.3/makedumpfile.spec --- makedumpfile-1.3.5/makedumpfile.spec 2009-11-11 08:44:51.000000000 +0800 +++ makedumpfile-1.5.3/makedumpfile.spec 2013-07-03 15:21:33.772088910 +0800 @@ -7,7 +7,7 @@ License: GPL Source: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-root Distribution: Linux 2.6 or greater -Packager: Ken'ichi Ohmichi +Packager: Atsushi Kumagai ExclusiveOS: Linux ExclusiveArch: i386 ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 Buildroot: %{_tmppath}/%{name}-root @@ -25,6 +25,8 @@ make %install rm -rf %{buildroot} mkdir -p %{buildroot}/bin +mkdir -p %{buildroot}/etc +mkdir -p %{buildroot}/usr/share/man/man5 mkdir -p %{buildroot}/usr/share/man/man8 make install DESTDIR=%{buildroot} @@ -32,11 +34,12 @@ make install DESTDIR=%{buildroot} rm -rf %{buildroot} %files +/etc/makedumpfile.conf.sample /bin/makedumpfile /bin/makedumpfile-R.pl +/usr/share/man/man5/makedumpfile.conf.5.gz /usr/share/man/man8/makedumpfile.8.gz %changelog * Fri Aug 21 2008 Ken'ichi Ohmichi - initial release. - diff -Nupr makedumpfile-1.3.5/Makefile makedumpfile-1.5.3/Makefile --- makedumpfile-1.3.5/Makefile 2013-07-03 15:18:37.854089017 +0800 +++ makedumpfile-1.5.3/Makefile 2013-07-03 16:54:24.883085541 +0800 @@ -3,36 +3,73 @@ VERSION=1.3.5 DATE=11 November 2009 +# Honour the environment variable CC +ifeq ($(strip $CC),) CC = gcc +endif + CFLAGS = -g -O2 -Wall -D_FILE_OFFSET_BITS=64 \ -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE \ -DVERSION='"$(VERSION)"' -DRELEASE_DATE='"$(DATE)"' CFLAGS_ARCH = -g -O2 -Wall -D_FILE_OFFSET_BITS=64 \ -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE +# LDFLAGS = -L/usr/local/lib -I/usr/local/include + +# Use TARGET as the target architecture if specified. +# Defaults to uname -m +ifeq ($(strip($TARGET)),) +TARGET := $(shell uname -m) +endif -ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ \ +ARCH := $(shell echo ${TARGET} | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ - -e s/ppc64/powerpc/ ) + -e s/ppc64/powerpc64/ -e s/ppc/powerpc32/) + CFLAGS += -D__$(ARCH)__ CFLAGS_ARCH += -D__$(ARCH)__ -ifeq ($(ARCH), powerpc) +ifeq ($(ARCH), powerpc64) CFLAGS += -m64 CFLAGS_ARCH += -m64 endif +ifeq ($(ARCH), powerpc32) +CFLAGS += -m32 +CFLAGS_ARCH += -m32 +endif + SRC = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info.h -SRC_ARCH = x86.c x86_64.c ia64.c ppc64.c s390x.c sadump_info.c -OBJ_ARCH = x86.o x86_64.o ia64.o ppc64.o s390x.o sadump_info.o +SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c +OBJ_PART = print_info.o dwarf_info.o elf_info.o erase_info.o sadump_info.o cache.o +SRC_ARCH = arch/arm.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c +OBJ_ARCH = arch/arm.o arch/x86.o arch/x86_64.o arch/ia64.o arch/ppc64.o arch/s390x.o arch/ppc.o + +LIBS = -ldw -lbz2 -lebl -ldl -lelf -lz +ifneq ($(LINKTYPE), dynamic) +LIBS := -static $(LIBS) +endif + +ifeq ($(USELZO), on) +LIBS := -llzo2 $(LIBS) +CFLAGS += -DUSELZO +endif + +ifeq ($(USESNAPPY), on) +LIBS := -lsnappy $(LIBS) +CFLAGS += -DUSESNAPPY +endif all: makedumpfile +$(OBJ_PART): $(SRC_PART) + $(CC) $(CFLAGS) -c -o ./$@ ./$(@:.o=.c) + $(OBJ_ARCH): $(SRC_ARCH) $(CC) $(CFLAGS_ARCH) -c -o ./$@ ./$(@:.o=.c) -makedumpfile: $(SRC) $(OBJ_ARCH) - $(CC) $(CFLAGS) $(OBJ_ARCH) -o $@ $< -ldw -lelf -lz +makedumpfile: $(SRC) $(OBJ_PART) $(OBJ_ARCH) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJ_PART) $(OBJ_ARCH) -rdynamic -o $@ $< $(LIBS) echo .TH MAKEDUMPFILE 8 \"$(DATE)\" \"makedumpfile v$(VERSION)\" \"Linux System Administrator\'s Manual\" > temp.8 grep -v "^.TH MAKEDUMPFILE 8" makedumpfile.8 >> temp.8 mv temp.8 makedumpfile.8 @@ -42,14 +79,15 @@ makedumpfile: $(SRC) $(OBJ_ARCH) mv temp.5 makedumpfile.conf.5 gzip -c ./makedumpfile.conf.5 > ./makedumpfile.conf.5.gz +eppic_makedumpfile.so: extension_eppic.c + $(CC) $(CFLAGS) -shared -rdynamic -o $@ extension_eppic.c -fPIC -leppic -ltinfo + clean: - rm -f $(OBJ) $(OBJ_ARCH) makedumpfile makedumpfile.8.gz makedumpfile.conf.5.gz + rm -f $(OBJ) $(OBJ_PART) $(OBJ_ARCH) makedumpfile makedumpfile.8.gz makedumpfile.conf.5.gz install: cp makedumpfile ${DESTDIR}/bin cp makedumpfile-R.pl ${DESTDIR}/bin cp makedumpfile.8.gz ${DESTDIR}/usr/share/man/man8 - cp makedumpfile.conf.8.gz ${DESTDIR}/usr/share/man/man8 cp makedumpfile.conf.5.gz ${DESTDIR}/usr/share/man/man5 cp makedumpfile.conf ${DESTDIR}/etc/makedumpfile.conf.sample - diff -Nupr makedumpfile-1.3.5/ppc64.c makedumpfile-1.5.3/ppc64.c --- makedumpfile-1.3.5/ppc64.c 2009-10-09 09:51:18.000000000 +0800 +++ makedumpfile-1.5.3/ppc64.c 1970-01-01 08:00:00.000000000 +0800 @@ -1,94 +0,0 @@ -/* - * ppc64.c - * - * Created by: Sachin Sant (sachinp@in.ibm.com) - * Copyright (C) IBM Corporation, 2006. All rights reserved - * - * 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 (version 2 of the License). - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifdef __powerpc__ - -#include "makedumpfile.h" - -int -get_machdep_info_ppc64(void) -{ - unsigned long vmlist, vmalloc_start; - - info->section_size_bits = _SECTION_SIZE_BITS; - info->max_physmem_bits = _MAX_PHYSMEM_BITS; - info->page_offset = __PAGE_OFFSET; - - if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of _stext.\n"); - return FALSE; - } - info->kernel_start = SYMBOL(_stext); - DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); - - /* - * For the compatibility, makedumpfile should run without the symbol - * vmlist and the offset of vm_struct.addr if they are not necessary. - */ - if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) - || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { - return TRUE; - } - if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) { - ERRMSG("Can't get vmlist.\n"); - return FALSE; - } - if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start, - sizeof(vmalloc_start))) { - ERRMSG("Can't get vmalloc_start.\n"); - return FALSE; - } - info->vmalloc_start = vmalloc_start; - DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); - - return TRUE; -} - -int -is_vmalloc_addr_ppc64(unsigned long vaddr) -{ - return (info->vmalloc_start && vaddr >= info->vmalloc_start); -} - -unsigned long long -vaddr_to_paddr_ppc64(unsigned long vaddr) -{ - unsigned long long paddr; - - paddr = vaddr_to_paddr_general(vaddr); - if (paddr != NOT_PADDR) - return paddr; - - if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) - || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { - ERRMSG("Can't get necessary information for vmalloc translation.\n"); - return NOT_PADDR; - } - if (!is_vmalloc_addr_ppc64(vaddr)) - return (vaddr - info->kernel_start); - - /* - * TODO: Support vmalloc translation. - */ - ERRMSG("This makedumpfile does not support vmalloc translation.\n"); - return NOT_PADDR; -} - -#endif /* powerpc */ diff -Nupr makedumpfile-1.3.5/print_info.c makedumpfile-1.5.3/print_info.c --- makedumpfile-1.3.5/print_info.c 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/print_info.c 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,327 @@ +/* + * print_info.c + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "print_info.h" +#include + +#define PROGRESS_MAXLEN "35" + +int message_level; +int flag_strerr_message; +int flag_ignore_r_char; /* 0: '\r' is effective. 1: not effective. */ + +void +show_version(void) +{ + MSG("makedumpfile: version " VERSION " (released on " RELEASE_DATE ")\n"); + MSG("\n"); +} + +void +print_usage(void) +{ + MSG("\n"); + MSG("LZO support:\n"); +#ifdef USELZO + MSG(" enabled\n"); +#else + MSG(" disabled ('-l' option will be ignored.)\n"); +#endif + MSG("snappy support:\n"); +#ifdef USESNAPPY + MSG(" enabled\n"); +#else + MSG(" disabled ('-p' option will be ignored.)\n"); +#endif + MSG("\n"); + MSG("Usage:\n"); + MSG(" Creating DUMPFILE:\n"); + MSG(" # makedumpfile [-c|-l|-E] [-d DL] [-x VMLINUX|-i VMCOREINFO] VMCORE\n"); + MSG(" DUMPFILE\n"); + MSG("\n"); + MSG(" Creating DUMPFILE with filtered kernel data specified through filter config\n"); + MSG(" file or eppic macro:\n"); + MSG(" # makedumpfile [-c|-l|-E] [-d DL] -x VMLINUX [--config FILTERCONFIGFILE]\n"); + MSG(" [--eppic EPPICMACRO] VMCORE DUMPFILE\n"); + MSG("\n"); + MSG(" Outputting the dump data in the flattened format to the standard output:\n"); + MSG(" # makedumpfile -F [-c|-l|-E] [-d DL] [-x VMLINUX|-i VMCOREINFO] VMCORE\n"); + MSG("\n"); + MSG(" Rearranging the dump data in the flattened format to a readable DUMPFILE:\n"); + MSG(" # makedumpfile -R DUMPFILE\n"); + MSG("\n"); + MSG(" Split the dump data to multiple DUMPFILEs in parallel:\n"); + MSG(" # makedumpfile --split [OPTION] [-x VMLINUX|-i VMCOREINFO] VMCORE DUMPFILE1\n"); + MSG(" DUMPFILE2 [DUMPFILE3 ..]\n"); + MSG("\n"); + MSG(" Reassemble multiple DUMPFILEs:\n"); + MSG(" # makedumpfile --reassemble DUMPFILE1 DUMPFILE2 [DUMPFILE3 ..] DUMPFILE\n"); + MSG("\n"); + MSG(" Generating VMCOREINFO:\n"); + MSG(" # makedumpfile -g VMCOREINFO -x VMLINUX\n"); + MSG("\n"); + MSG(" Extracting the dmesg log from a VMCORE:\n"); + MSG(" # makedumpfile --dump-dmesg [-x VMLINUX|-i VMCOREINFO] VMCORE LOGFILE\n"); + MSG("\n"); + MSG("\n"); + MSG(" Creating DUMPFILE of Xen:\n"); + MSG(" # makedumpfile -E [--xen-syms XEN-SYMS|--xen-vmcoreinfo VMCOREINFO] VMCORE DUMPFILE\n"); + MSG("\n"); + MSG(" Generating VMCOREINFO of Xen:\n"); + MSG(" # makedumpfile -g VMCOREINFO --xen-syms XEN-SYMS\n"); + MSG("\n"); + MSG("\n"); + MSG(" Creating DUMPFILE from multiple VMCOREs generated on sadump diskset configuration:\n"); + MSG(" # makedumpfile [-c|-l] [-d DL] -x VMLINUX --diskset=VMCORE1 --diskset=VMCORE2\n"); + MSG(" [--diskset=VMCORE3 ..] DUMPFILE\n"); + MSG("\n"); + MSG("\n"); + MSG("Available options:\n"); + MSG(" [-c|-l|-p]:\n"); + MSG(" Compress dump data by each page using zlib for -c option, lzo for -l option\n"); + MSG(" or snappy for -p option. A user cannot specify either of these options with\n"); + MSG(" -E option, because the ELF format does not support compressed data.\n"); + MSG(" THIS IS ONLY FOR THE CRASH UTILITY.\n"); + MSG("\n"); + MSG(" [-d DL]:\n"); + MSG(" Specify the type of unnecessary page for analysis.\n"); + MSG(" Pages of the specified type are not copied to DUMPFILE. The page type\n"); + MSG(" marked in the following table is excluded. A user can specify multiple\n"); + MSG(" page types by setting the sum of each page type for Dump_Level (DL).\n"); + MSG(" The maximum of Dump_Level is 31.\n"); + MSG(" Note that Dump_Level for Xen dump filtering is 0 or 1.\n"); + MSG("\n"); + MSG(" | cache cache\n"); + MSG(" Dump | zero without with user free\n"); + MSG(" Level | page private private data page\n"); + MSG(" -------+---------------------------------------\n"); + MSG(" 0 |\n"); + MSG(" 1 | X\n"); + MSG(" 2 | X\n"); + MSG(" 4 | X X\n"); + MSG(" 8 | X\n"); + MSG(" 16 | X\n"); + MSG(" 31 | X X X X X\n"); + MSG("\n"); + MSG(" [-E]:\n"); + MSG(" Create DUMPFILE in the ELF format.\n"); + MSG(" This option cannot be specified with either of -c option or -l option,\n"); + MSG(" because the ELF format does not support compressed data.\n"); + MSG("\n"); + MSG(" [-x VMLINUX]:\n"); + MSG(" Specify the first kernel's VMLINUX to analyze the first kernel's\n"); + MSG(" memory usage.\n"); + MSG(" The page size of the first kernel and the second kernel should match.\n"); + MSG("\n"); + MSG(" [-i VMCOREINFO]:\n"); + MSG(" Specify VMCOREINFO instead of VMLINUX for analyzing the first kernel's\n"); + MSG(" memory usage.\n"); + MSG(" VMCOREINFO should be made beforehand by makedumpfile with -g option,\n"); + MSG(" and it contains the first kernel's information. This option is necessary\n"); + MSG(" if VMCORE does not contain VMCOREINFO, [-x VMLINUX] is not specified,\n"); + MSG(" and dump_level is 2 or more.\n"); + MSG("\n"); + MSG(" [-g VMCOREINFO]:\n"); + MSG(" Generate VMCOREINFO from the first kernel's VMLINUX.\n"); + MSG(" VMCOREINFO must be generated on the system that is running the first\n"); + MSG(" kernel. With -i option, a user can specify VMCOREINFO generated on the\n"); + MSG(" other system that is running the same first kernel. [-x VMLINUX] must\n"); + MSG(" be specified.\n"); + MSG("\n"); + MSG(" [--config FILTERCONFIGFILE]:\n"); + MSG(" Used in conjunction with -x VMLINUX option, to specify the filter config\n"); + MSG(" file that contains filter commands to filter out desired kernel data\n"); + MSG(" from vmcore while creating DUMPFILE.\n"); + MSG("\n"); + MSG(" [--eppic EPPICMACRO]:\n"); + MSG(" Used in conjunction with -x VMLINUX option, to specify the eppic macro\n"); + MSG(" file that contains filter rules or directory that contains eppic macro\n"); + MSG(" files to filter out desired kernel data from vmcore while creating DUMPFILE.\n"); + MSG(" When directory is specified, all the eppic macros in the directory are\n"); + MSG(" processed\n"); + MSG("\n"); + MSG(" [-F]:\n"); + MSG(" Output the dump data in the flattened format to the standard output\n"); + MSG(" for transporting the dump data by SSH.\n"); + MSG(" Analysis tools cannot read the flattened format directly. For analysis,\n"); + MSG(" the dump data in the flattened format should be rearranged to a readable\n"); + MSG(" DUMPFILE by -R option.\n"); + MSG("\n"); + MSG(" [-R]:\n"); + MSG(" Rearrange the dump data in the flattened format from the standard input\n"); + MSG(" to a readable DUMPFILE.\n"); + MSG("\n"); + MSG(" [--split]:\n"); + MSG(" Split the dump data to multiple DUMPFILEs in parallel. If specifying\n"); + MSG(" DUMPFILEs on different storage devices, a device can share I/O load with\n"); + MSG(" other devices and it reduces time for saving the dump data. The file size\n"); + MSG(" of each DUMPFILE is smaller than the system memory size which is divided\n"); + MSG(" by the number of DUMPFILEs.\n"); + MSG(" This feature supports only the kdump-compressed format.\n"); + MSG("\n"); + MSG(" [--reassemble]:\n"); + MSG(" Reassemble multiple DUMPFILEs, which are created by --split option,\n"); + MSG(" into one DUMPFILE. dumpfile1 and dumpfile2 are reassembled into dumpfile.\n"); + MSG("\n"); + MSG(" [--cyclic-buffer BUFFER_SIZE]:\n"); + MSG(" Specify the buffer size in kilo bytes for analysis in the cyclic mode.\n"); + MSG(" Actually, the double of BUFFER_SIZE kilo bytes will be allocated in memory.\n"); + MSG(" In the cyclic mode, the number of cycles is represented as:\n"); + MSG("\n"); + MSG(" num_of_cycles = system_memory / \n"); + MSG(" (BUFFER_SIZE * 1024 * bit_per_bytes * page_size)\n"); + MSG("\n"); + MSG(" The lesser number of cycles, the faster working speed is expected.\n"); + MSG(" By default, BUFFER_SIZE will be calculated automatically depending on\n"); + MSG(" system memory size, so ordinary users don't need to specify this option.\n"); + MSG("\n"); + MSG(" [--non-cyclic]:\n"); + MSG(" Running in the non-cyclic mode, this mode uses the old filtering logic\n"); + MSG(" same as v1.4.4 or before.\n"); + MSG(" If you feel the cyclic mode is too slow, please try this mode.\n"); + MSG("\n"); + MSG(" [--xen-syms XEN-SYMS]:\n"); + MSG(" Specify the XEN-SYMS to analyze Xen's memory usage.\n"); + MSG("\n"); + MSG(" [--xen-vmcoreinfo VMCOREINFO]:\n"); + MSG(" Specify the VMCOREINFO of Xen to analyze Xen's memory usage.\n"); + MSG("\n"); + MSG(" [--xen_phys_start XEN_PHYS_START_ADDRESS]:\n"); + MSG(" This option is only for x86_64.\n"); + MSG(" Specify the XEN_PHYS_START_ADDRESS, if the xen code/data is relocatable\n"); + MSG(" and VMCORE does not contain XEN_PHYS_START_ADDRESS in the CRASHINFO.\n"); + MSG("\n"); + MSG(" [-X]:\n"); + MSG(" Exclude all the user domain pages from Xen kdump's VMCORE, and extract\n"); + MSG(" the part of Xen and domain-0.\n"); + MSG("\n"); + MSG(" [--diskset=VMCORE]:\n"); + MSG(" Specify multiple VMCOREs created on sadump diskset configuration the same\n"); + MSG(" number of times as the number of VMCOREs in increasing order from left to\n"); + MSG(" right.\n"); + MSG("\n"); + MSG(" [--message-level ML]:\n"); + MSG(" Specify the message types.\n"); + MSG(" Users can restrict output printed by specifying Message_Level (ML) with\n"); + MSG(" this option. The message type marked with an X in the following table is\n"); + MSG(" printed. For example, according to the table, specifying 7 as ML means\n"); + MSG(" progress indicator, common message, and error message are printed, and\n"); + MSG(" this is a default value.\n"); + MSG(" Note that the maximum value of message_level is 31.\n"); + MSG("\n"); + MSG(" Message | progress common error debug report\n"); + MSG(" Level | indicator message message message message\n"); + MSG(" ---------+------------------------------------------------------\n"); + MSG(" 0 |\n"); + MSG(" 1 | X\n"); + MSG(" 2 | X\n"); + MSG(" 4 | X\n"); + MSG(" * 7 | X X X\n"); + MSG(" 8 | X\n"); + MSG(" 16 | X\n"); + MSG(" 31 | X X X X X\n"); + MSG("\n"); + MSG(" [--vtop VIRTUAL_ADDRESS]:\n"); + MSG(" This option is useful, when user debugs the translation problem\n"); + MSG(" of virtual address. If specifing the VIRTUAL_ADDRESS, its physical\n"); + MSG(" address is printed.\n"); + MSG("\n"); + MSG(" [--dump-dmesg]:\n"); + MSG(" This option overrides the normal behavior of makedumpfile. Instead of\n"); + MSG(" compressing and filtering a VMCORE to make it smaller, it simply\n"); + MSG(" extracts the dmesg log from a VMCORE and writes it to the specified\n"); + MSG(" LOGFILE. If a VMCORE does not contain VMCOREINFO for dmesg, it is\n"); + MSG(" necessary to specfiy [-x VMLINUX] or [-i VMCOREINFO].\n"); + MSG("\n"); + MSG(" [-D]:\n"); + MSG(" Print debugging message.\n"); + MSG("\n"); + MSG(" [-f]:\n"); + MSG(" Overwrite DUMPFILE even if it already exists.\n"); + MSG("\n"); + MSG(" [-h]:\n"); + MSG(" Show help message and LZO/snappy support status (enabled/disabled).\n"); + MSG("\n"); + MSG(" [-b ]\n"); + MSG(" Specify the cache 2^order pages in ram when generating vmcore info\n"); + MSG(" before writing to output\n"); + MSG("\n"); + MSG(" [-v]:\n"); + MSG(" Show the version of makedumpfile.\n"); + MSG("\n"); + MSG(" VMLINUX:\n"); + MSG(" This is a pathname to the first kernel's vmlinux.\n"); + MSG(" This file must have the debug information of the first kernel to analyze\n"); + MSG(" the first kernel's memory usage.\n"); + MSG("\n"); + MSG(" VMCORE:\n"); + MSG(" This is a pathname to the first kernel's memory core image.\n"); + MSG(" This argument is generally /proc/vmcore.\n"); + MSG("\n"); + MSG(" DUMPFILE:\n"); + MSG(" This is a pathname to a file created by this command.\n"); + MSG("\n"); + MSG(" XEN-SYMS:\n"); + MSG(" This is a pathname to the xen-syms.\n"); + MSG(" This file must have the debug information of Xen to analyze\n"); + MSG(" Xen's memory usage.\n"); + MSG("\n"); +} + +void +print_progress(const char *msg, unsigned long current, unsigned long end) +{ + int progress; + time_t tm; + static time_t last_time = 0; + + if (current < end) { + tm = time(NULL); + if (tm - last_time < 1) + return; + last_time = tm; + progress = current * 100 / end; + } else + progress = 100; + + if (flag_ignore_r_char) { + PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3d %%]\n", + msg, progress); + } else { + PROGRESS_MSG("\r"); + PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3d %%] ", + msg, progress); + } +} + +void +print_execution_time(char *step_name, struct timeval *tv_start) +{ + struct timeval tv_end; + time_t diff_sec; + suseconds_t diff_usec; + + gettimeofday(&tv_end, NULL); + + diff_sec = tv_end.tv_sec - tv_start->tv_sec; + diff_usec = tv_end.tv_usec - tv_start->tv_usec; + if (diff_usec < 0) { + diff_sec--; + diff_usec += 1000000; + } + REPORT_MSG("STEP [%s] : %ld.%06ld seconds\n", + step_name, diff_sec, diff_usec); +} + diff -Nupr makedumpfile-1.3.5/print_info.h makedumpfile-1.5.3/print_info.h --- makedumpfile-1.3.5/print_info.h 1970-01-01 08:00:00.000000000 +0800 +++ makedumpfile-1.5.3/print_info.h 2013-02-18 16:47:26.000000000 +0800 @@ -0,0 +1,101 @@ +/* + * print_info.h + * + * Copyright (C) 2011 NEC Corporation + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _PRINT_INFO_H +#define _PRINT_INFO_H + +#include +#include + +extern int message_level; +extern int flag_strerr_message; +extern int flag_ignore_r_char; + +void show_version(void); +void print_usage(void); +void print_progress(const char *msg, unsigned long current, unsigned long end); +void print_execution_time(char *step_name, struct timeval *tv_start); + +/* + * Message texts + */ +#define PROGRESS_COPY "Copying data " +#define PROGRESS_HOLES "Checking for memory holes " +#define PROGRESS_UNN_PAGES "Excluding unnecessary pages" +#define PROGRESS_FREE_PAGES "Excluding free pages " +#define PROGRESS_ZERO_PAGES "Excluding zero pages " +#define PROGRESS_XEN_DOMAIN "Excluding xen user domain " + +/* + * Message Level + */ +#define MIN_MSG_LEVEL (0) +#define MAX_MSG_LEVEL (31) +#define DEFAULT_MSG_LEVEL (7) /* Print the progress indicator, the + common message, the error message */ +#define ML_PRINT_PROGRESS (0x001) /* Print the progress indicator */ +#define ML_PRINT_COMMON_MSG (0x002) /* Print the common message */ +#define ML_PRINT_ERROR_MSG (0x004) /* Print the error message */ +#define ML_PRINT_DEBUG_MSG (0x008) /* Print the debugging message */ +#define ML_PRINT_REPORT_MSG (0x010) /* Print the report message */ + +#define MSG(x...) \ +do { \ + if (message_level & ML_PRINT_COMMON_MSG) { \ + if (flag_strerr_message) \ + fprintf(stderr, x); \ + else \ + fprintf(stdout, x); \ + } \ +} while (0) + +#define ERRMSG(x...) \ +do { \ + if (message_level & ML_PRINT_ERROR_MSG) { \ + fprintf(stderr, __FUNCTION__); \ + fprintf(stderr, ": "); \ + fprintf(stderr, x); \ + } \ +} while (0) + +#define PROGRESS_MSG(x...) \ +do { \ + if (message_level & ML_PRINT_PROGRESS) { \ + fprintf(stderr, x); \ + } \ +} while (0) + +#define DEBUG_MSG(x...) \ +do { \ + if (message_level & ML_PRINT_DEBUG_MSG) { \ + if (flag_strerr_message) \ + fprintf(stderr, x); \ + else \ + fprintf(stdout, x); \ + } \ +} while (0) + +#define REPORT_MSG(x...) \ +do { \ + if (message_level & ML_PRINT_REPORT_MSG) { \ + if (flag_strerr_message) \ + fprintf(stderr, x); \ + else \ + fprintf(stdout, x); \ + } \ +} while (0) + +#endif /* PRINT_INFO_H */ + diff -Nupr makedumpfile-1.3.5/README makedumpfile-1.5.3/README --- makedumpfile-1.3.5/README 2009-11-11 08:44:51.000000000 +0800 +++ makedumpfile-1.5.3/README 2013-02-18 16:47:26.000000000 +0800 @@ -6,13 +6,13 @@ * REQUIREMENTS Please download the following library file and install it exactly as below; do NOT use "make install". - - elfutils-0.125.tar.gz + - elfutils-0.142.tar.gz The "make install" of elfutils installs some commands (ld, readelf, etc.), and compiling problems sometimes happen due to using the installed commands. To install only the library & header files, use the following method: - # tar -zxvf elfutils-0.125.tar.gz - # cd elfutils-0.125 + # tar -zxvf elfutils-0.142.tar.gz + # cd elfutils-0.142 # ./configure # make # @@ -37,33 +37,63 @@ # cd makedumpfile-x.y.z 4.Build, and install: # make; make install + 5.Build for a different architecture than the host : + # make TARGET= ; make install + where is the 'uname -m' of the target architecture. + The user has to set the environment variable CC to appropriate + compiler for the target architecture. + 6.Build with lzo support: + # make USELZO=on ; make install + The user has to prepare lzo library. + 7.Build with snappy support: + # make USESNAPPY=on ; make install + The user has to prepare snappy library. + 8.Build the extension module for --eppic option. + # make eppic_makedumpfile.so + The user has to prepare eppic library from the following site: + http://code.google.com/p/eppic/ * SUPPORTED KERNELS This makedumpfile supports the following kernels. - | FLATMEM | DISCONTIGMEM | SPARSEMEM - |-------------------+-------------------+------------------- - Kernel| | x86| | PPC| | x86| | PPC| | x86| | PPC - Version| x86| _64|ia64| 64| x86| _64|ia64| 64| x86| _64|ia64| 64 - -------+----+----+----+----+----+----+----+----+----+----+----+---- - 2.6.15 | OK | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- - 2.6.16 | OK | OK | -- | | -- | OK | OK | -- | -- | | -- | - 2.6.17 | OK | OK | -- | | -- | OK | -- | -- | -- | OK | -- | - 2.6.18 | OK | OK | -- | OK | -- | OK | OK | -- | -- | OK | OK | OK - 2.6.19 | OK | OK | -- | OK | OK | OK | | -- | OK | OK | OK | OK - 2.6.20 | OK | OK | -- | #1 | OK | OK | OK | -- | OK | OK | OK | #1 - 21-rc5 | OK | OK | -- | OK | OK | OK | OK | -- | OK | OK | OK | OK - 2.6.21 | OK | OK | -- | | OK | OK | OK | -- | OK | OK | OK | - 2.6.22 | OK | OK | -- | | OK | OK | OK | -- | OK | OK | OK | - 2.6.23 | OK | OK | -- | | OK | OK | OK | -- | OK | OK | OK | - 2.6.24 | OK | OK | -- | | OK | OK | OK | -- | OK | OK | OK | - 2.6.25 | OK | ** | -- | | | ** | OK | -- | OK | OK | OK | - 2.6.26 | OK | ** | -- | | | ** | OK | -- | OK | OK | OK | - 2.6.27 | OK | ** | -- | | | ** | OK | -- | #2 | OK | OK | - 2.6.28 | OK | ** | -- | | | ** | OK | -- | OK | OK | OK | - 2.6.29 | OK | ** | -- | | | ** | OK | -- | OK | OK | OK | - 2.6.30 | OK | ** | -- | | | ** | OK | -- | OK | OK | OK | - 2.6.31 | OK | ** | -- | | | ** | | -- | | OK | OK | + | FLATMEM | DISCONTIGMEM | SPARSEMEM + |-------------------+-------------------+------------------------ + Kernel| | x86| PPC| PPC| | x86| | PPC| | x86| | PPC| + Version| x86| _64| 32| 64| x86| _64|ia64| 64| x86| _64|ia64| 64|s390 + -------+----+----+----+----+----+----+----+----+----+----+----+----+---- + 2.6.15 | OK | -- | | -- | -- | -- | -- | -- | -- | -- | -- | -- | + 2.6.16 | OK | OK | | | -- | OK | OK | -- | -- | | -- | | + 2.6.17 | OK | OK | | | -- | OK | -- | -- | -- | OK | -- | | + 2.6.18 | OK | OK | | OK | -- | OK | OK | -- | -- | OK | OK | OK | + 2.6.19 | OK | OK | | OK | OK | OK | | -- | OK | OK | OK | OK | + 2.6.20 | OK | OK | | #1 | OK | OK | OK | -- | OK | OK | OK | #1 | + 21-rc5 | OK | OK | | OK | OK | OK | OK | -- | OK | OK | OK | OK | + 2.6.21 | OK | OK | | | OK | OK | OK | -- | OK | OK | OK | | + 2.6.22 | OK | OK | | | OK | OK | OK | -- | OK | OK | OK | | + 2.6.23 | OK | OK | | | OK | OK | OK | -- | OK | OK | OK | | + 2.6.24 | OK | OK | | | OK | OK | OK | -- | OK | OK | OK | | + 2.6.25 | OK | ** | | | | ** | OK | -- | OK | OK | OK | | + 2.6.26 | OK | ** | | | | ** | OK | -- | OK | OK | OK | | + 2.6.27 | OK | ** | | | | ** | OK | -- | #2 | OK | OK | | + 2.6.28 | OK | ** | | | | ** | OK | -- | OK | OK | OK | | + 2.6.29 | OK | ** | | | | ** | OK | -- | OK | OK | OK | | + 2.6.30 | OK | ** | | | | ** | OK | -- | OK | OK | OK | | + 2.6.31 | OK | ** | | | | ** | | -- | OK | OK | OK | | + 2.6.32 | OK | ** | | | | ** | | -- | OK | OK | | | OK + 2.6.33 | OK | ** | | | | ** | | -- | OK | OK | | | + 2.6.34 | OK | ** | | | | ** | | -- | OK | OK | | | + 2.6.35 | OK | ** | | | | ** | | -- | OK | OK | | | + 2.6.36 | OK | ** | | | | ** | | -- | OK | OK | | | + 2.6.37 | OK | ** | | | | ** | | -- | OK | OK | | | + 2.6.38 | OK | ** | | | | ** | | -- | OK | OK | | | + 2.6.39 | OK | ** | | | | ** | | -- | OK | OK | | | + 3.0 | OK | ** | | | | ** | | -- | OK | OK | | | + 3.1 | OK | ** | | | | ** | | -- | OK | OK | | | + 3.2 | OK | ** | OK | | | ** | | -- | OK | OK | | | + 3.3 | OK | ** | | | | ** | | -- | OK | OK | | | + 3.4 | OK | ** | | | | ** | | -- | OK | OK | | | + 3.5 | OK | ** | | | | ** | | -- | OK | OK | | | + 3.6 | OK | ** | | | | ** | | -- | OK | OK | | | OK : Support. -- : Not support. @@ -83,8 +113,12 @@ * TODO 1. Supporting more kernels. 2. Fixing the report message. - (Now, it sometimes counts the number of free_pages duplicating zero-pages - if creating an ELF dumpfile.) + - Now, it sometimes counts the number of free_pages duplicating zero-pages + if creating an ELF dumpfile. + - The cyclic mode will show incorrect and many progress indicator. + 3. Send the patch to the LKML to store some symbols in VMCOREINFO. + (VtoP method for x86 remap allocator needs some symbols that + relate to remap allocator.) * NOTE 1. A vmcoreinfo file should be generated by the makedumpfile which is used @@ -103,32 +137,46 @@ does not exclude Xen user domain pages. So user should specify '-X' option for excluding Xen user domain pages. + 4. There are two running mode in makedumpfile-1.5.0 or later. + cyclic mode: + In this mode, makedumpfile reads regions of a fixed size from + /proc/vmcore, analyzes it, and writes pages to dumpfile cyclically from + start of memory to the end. Each cycle consume constant memory for + analysis of constant region, so the memory usage of makedumpfile will + be kept constant regardless of system memory size. + This mode is default mode. + + non-cyclic mode: + In this mode, makedumpfile creates temporary bitmap file in TMPDIR for + analysis. The size of bitmap increases linearly based on physical memory + size. Therefore, if your machine has a lots of memory and you use tmpfs + on TMPDIR in 2nd kernel, makedumpfile can fail due to lack of memory. + makedumpfile-1.4.4 or before has only this mode. + * FAQ - 001: It cannot be compiled with the following messages: - # make - gcc -g -O2 -Wall -D__x86_64__ -c -o ./x86.o ./x86.c - gcc -g -O2 -Wall -D__x86_64__ -c -o ./x86_64.o ./x86_64.c - gcc -g -O2 -Wall -D__x86_64__ -c -o ./ia64.o ./ia64.c - gcc -g -O2 -Wall -D__x86_64__ -c -o ./ppc64.o ./ppc64.c - gcc -g -O2 -Wall -D_FILE_OFFSET_BITS=64 -DVERSION='"1.1.4"' - -DRELEASE_DATE='"08 June 2007"' -D__x86_64__ x86.o x86_64.o ia64.o - ppc64.o-o makedumpfile - makedumpfile.c -static -ldw -lelf -lz - /tmp/ccYv3cGF.o: In function `get_debug_info': - /tmp/makedumpfile/makedumpfile.c:1341: undefined reference to - `elf_getshstrndx' - collect2: ld returned 1 exit status - make: *** [makedumpfile] Error 1 - # - - The compiler cannot find elf_getshstrndx() because it tries - searching for it only from /usr/lib/libelf.a though elf_getshstrndx() - is archived in /usr/local/lib/libelf.a. - To solve the problem, add the option (-L/usr/local/lib/) to CFLAGS - of Makefile like the following: + 001: If installing elfutils-0.137 into older elfutils by the above way, the + following problem happens sometimes. If seeing, try to enable LDFLAGS + comment (-L/usr/local/lib -I/usr/local/include) in Makefile. + + $ make + [..] + /tmp/ccXQtvnZ.o: In function `process_module': + /makedumpfile/makedumpfile.c:1387: undefined reference to `dwarf_getelf' + collect2: ld returned 1 exit status + make: *** [makedumpfile] Error 1 + + 002: makedumpfile is compiled with -static option, because the command should + run while the second kernel, which may not mount root filesystem and may + not contain dynamic library files, is running. + If the dynamic library files, which are needed by makedumpfile, exist + while the second kernel is running, we can use dynamic libraries by + "LINKTYPE" parameter. + + $ make LINKTYPE=dynamic + + This is a workaround for some linux distributions which does + not contain static library files needed by makedumpfile. - CFLAGS = -g -O2 -Wall -D_FILE_OFFSET_BITS=64 -L/usr/local/lib/ \ - -DVERSION='"$(VERSION)"' -DRELEASE_DATE='"$(DATE)"' * REFERENCES https://sourceforge.net/projects/makedumpfile/ @@ -137,7 +185,9 @@ * BUG REPORT If finding some bugs, please send the information to the following: - Ken'ichi Ohmichi Masaki Tachibana + Minoru Usui + Daisuke Nishimura + Atsushi Kumagai kexec-ml diff -Nupr makedumpfile-1.3.5/s390x.c makedumpfile-1.5.3/s390x.c --- makedumpfile-1.3.5/s390x.c 2013-07-03 15:18:37.837089017 +0800 +++ makedumpfile-1.5.3/s390x.c 1970-01-01 08:00:00.000000000 +0800 @@ -1,276 +0,0 @@ -/* - * s390x.c - * - * Created by: Michael Holzheu (holzheu@de.ibm.com) - * Copyright IBM Corp. 2010 - * - * 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 (version 2 of the License). - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifdef __s390x__ - -#include "makedumpfile.h" - -#define TABLE_SIZE 4096 - -/* - * Bits in the virtual address - * - * |<----- RX ---------->| - * | RFX | RSX | RTX | SX | PX | BX | - * 0 11 22 33 44 52 63 - * - * RX: Region Index - * RFX: Region first index - * RSX: Region second index - * RTX: Region third index - * SX: Segment index - * PX: Page index - * BX: Byte index - * - * RX part of vaddr is divided into three fields RFX, RSX and RTX each of - * 11 bit in size - */ -#define _REGION_INDEX_SHIFT 11 -#define _PAGE_INDEX_MASK 0xff000UL /* page index (PX) mask */ -#define _BYTE_INDEX_MASK 0x00fffUL /* Byte index (BX) mask */ -#define _PAGE_BYTE_INDEX_MASK (_PAGE_INDEX_MASK | _BYTE_INDEX_MASK) - -/* Region/segment table index */ -#define rsg_index(x, y) \ - (((x) >> ((_REGION_INDEX_SHIFT * y) + _SEGMENT_INDEX_SHIFT)) \ - & _REGION_OFFSET_MASK) -/* Page table index */ -#define pte_index(x) (((x) >> _PAGE_INDEX_SHIFT) & _PAGE_OFFSET_MASK) - -#define rsg_offset(x, y) (rsg_index( x, y) * sizeof(unsigned long)) -#define pte_offset(x) (pte_index(x) * sizeof(unsigned long)) - -int -get_machdep_info_s390x(void) -{ - unsigned long vmalloc_start; - char *term_str = getenv("TERM"); - - if (term_str && strcmp(term_str, "dumb") == 0) - /* '\r' control character is ignored on "dumb" terminal. */ - flag_ignore_r_char = 1; - - info->section_size_bits = _SECTION_SIZE_BITS; - info->max_physmem_bits = _MAX_PHYSMEM_BITS; - info->page_offset = __PAGE_OFFSET; - - if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of _stext.\n"); - return FALSE; - } - info->kernel_start = SYMBOL(_stext); - DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); - - /* - * Obtain the vmalloc_start address from high_memory symbol. - */ - if (SYMBOL(high_memory) == NOT_FOUND_SYMBOL) { - return TRUE; - } - if (!readmem(VADDR, SYMBOL(high_memory), &vmalloc_start, - sizeof(vmalloc_start))) { - ERRMSG("Can't get vmalloc_start.\n"); - return FALSE; - } - info->vmalloc_start = vmalloc_start; - DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); - - return TRUE; -} - -static int -is_vmalloc_addr_s390x(unsigned long vaddr) -{ - return (info->vmalloc_start && vaddr >= info->vmalloc_start); -} - -static int -rsg_table_entry_bad(unsigned long entry, int level) -{ - unsigned long mask = ~_REGION_ENTRY_INVALID - & ~_REGION_ENTRY_TYPE_MASK - & ~_REGION_ENTRY_LENGTH; - - if (level) - mask &= ~_REGION_ENTRY_ORIGIN; - else - mask &= ~_SEGMENT_ENTRY_ORIGIN; - - return (entry & mask) != 0; -} - -/* Region or segment table traversal function */ -static unsigned long -_kl_rsg_table_deref_s390x(unsigned long vaddr, unsigned long table, - int len, int level) -{ - unsigned long offset, entry; - - offset = rsg_offset(vaddr, level); - - /* check if offset is over the table limit. */ - if (offset >= ((len + 1) * TABLE_SIZE)) { - ERRMSG("offset is over the table limit.\n"); - return 0; - } - - if (!readmem(VADDR, table + offset, &entry, sizeof(entry))) { - if (level) - ERRMSG("Can't read region table %d entry\n", level); - else - ERRMSG("Can't read segment table entry\n"); - return 0; - } - /* - * Check if the segment table entry could be read and doesn't have - * any of the reserved bits set. - */ - if (rsg_table_entry_bad(entry, level)) { - ERRMSG("Bad region/segment table entry.\n"); - return 0; - } - /* - * Check if the region/segment table entry is with valid - * level and not invalid. - */ - if ((RSG_TABLE_LEVEL(entry) != level) - && (entry & _REGION_ENTRY_INVALID)) { - ERRMSG("Invalid region/segment table level or entry.\n"); - return 0; - } - - return entry; -} - -/* Page table traversal function */ -static ulong _kl_pg_table_deref_s390x(unsigned long vaddr, unsigned long table) -{ - unsigned long offset, entry; - - offset = pte_offset(vaddr); - readmem(VADDR, table + offset, &entry, sizeof(entry)); - /* - * Check if the page table entry could be read and doesn't have - * any of the reserved bits set. - * Check if the page table entry has the invalid bit set. - */ - if (entry & (_PAGE_CO | _PAGE_ZERO | _PAGE_INVALID)) { - ERRMSG("Invalid page table entry.\n"); - return 0; - } - - return entry; -} - -/* vtop_s390x() - translate virtual address to physical - * @vaddr: virtual address to translate - * - * Function converts the @vaddr into physical address using page tables. - * - * Return: - * Physical address or NOT_PADDR if translation fails. - */ -static unsigned long long -vtop_s390x(unsigned long vaddr) -{ - unsigned long long paddr = NOT_PADDR; - unsigned long table, entry; - int level, len; - - if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); - return NOT_PADDR; - } - table = SYMBOL(swapper_pg_dir); - - /* Read the first entry to find the number of page table levels. */ - readmem(VADDR, table, &entry, sizeof(entry)); - level = TABLE_LEVEL(entry); - len = TABLE_LENGTH(entry); - - if ((vaddr >> (_SEGMENT_PAGE_SHIFT + (_REGION_INDEX_SHIFT * level)))) { - ERRMSG("Address too big for the number of page table " \ - "levels.\n"); - return NOT_PADDR; - } - - /* - * Walk the region and segment tables. - */ - while (level >= 0) { - entry = _kl_rsg_table_deref_s390x(vaddr, table, len, level); - if (!entry) { - return NOT_PADDR; - } - table = entry & _REGION_ENTRY_ORIGIN; - len = RSG_TABLE_LENGTH(entry); - level--; - } - - /* - * Check if this is a large page. - * if yes, then add the 1MB page offset (PX + BX) and return the value. - * if no, then get the page table entry using PX index. - */ - if (entry & _SEGMENT_ENTRY_LARGE) { - paddr = table + (vaddr & _PAGE_BYTE_INDEX_MASK); - } else { - entry = _kl_pg_table_deref_s390x(vaddr, - entry & _SEGMENT_ENTRY_ORIGIN); - if (!entry) - return NOT_PADDR; - - /* - * Isolate the page origin from the page table entry. - * Add the page offset (BX). - */ - paddr = (entry & _REGION_ENTRY_ORIGIN) - + (vaddr & _BYTE_INDEX_MASK); - } - - return paddr; -} - -unsigned long long -vaddr_to_paddr_s390x(unsigned long vaddr) -{ - unsigned long long paddr; - - paddr = vaddr_to_paddr_general(vaddr); - if (paddr != NOT_PADDR) - return paddr; - - if (SYMBOL(high_memory) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get necessary information for vmalloc " - "translation.\n"); - return NOT_PADDR; - } - - if (is_vmalloc_addr_s390x(vaddr)) { - paddr = vtop_s390x(vaddr); - } - else { - paddr = vaddr - KVBASE; - } - - return paddr; -} - -#endif /* __s390x__ */ diff -Nupr makedumpfile-1.3.5/sadump_info.c makedumpfile-1.5.3/sadump_info.c --- makedumpfile-1.3.5/sadump_info.c 2013-07-03 15:18:37.908089017 +0800 +++ makedumpfile-1.5.3/sadump_info.c 2013-02-18 16:47:26.000000000 +0800 @@ -19,6 +19,8 @@ #if defined(__x86__) || defined(__x86_64__) #include "makedumpfile.h" +#include "elf_info.h" +#include "print_info.h" #include "sadump_mod.h" #ifdef __x86__ @@ -40,7 +42,7 @@ #define KEXEC_CORE_NOTE_DESC_BYTES roundup(sizeof(struct elf_prstatus), 4) #define KEXEC_NOTE_BYTES ((KEXEC_NOTE_HEAD_BYTES * 2) + \ - KEXEC_CORE_NOTE_NAME_BYTES + \ + KEXEC_CORE_NOTE_NAME_BYTES + \ KEXEC_CORE_NOTE_DESC_BYTES ) #define for_each_online_cpu(cpu) \ @@ -312,10 +314,8 @@ sadump_generate_elf_note_from_dumpfile(v goto cleanup; size_pt_note = ftell(si->file_elf_note); - info->offset_note = 0; - info->size_note = size_pt_note; - info->offset_vmcoreinfo = offset_vmcoreinfo; - info->size_vmcoreinfo = size_vmcoreinfo; + set_pt_note(0, size_pt_note); + set_vmcoreinfo(offset_vmcoreinfo, size_vmcoreinfo); retval = TRUE; @@ -751,7 +751,7 @@ sadump_initialize_bitmap_memory(void) { struct sadump_header *sh = si->sh_memory; struct dump_bitmap *bmp; - unsigned long dumpable_bitmap_offset, dumpable_bitmap_len; + unsigned long dumpable_bitmap_offset; unsigned long long section, max_section, pfn; unsigned long long *block_table; @@ -759,8 +759,6 @@ sadump_initialize_bitmap_memory(void) si->sub_hdr_offset + sh->block_size * (sh->sub_hdr_size + sh->bitmap_blocks); - dumpable_bitmap_len = sh->block_size * sh->dumpable_bitmap_blocks; - bmp = malloc(sizeof(struct dump_bitmap)); if (bmp == NULL) { ERRMSG("Can't allocate memory for the memory-bitmap. %s\n", @@ -949,11 +947,10 @@ failed: #endif /* __x86_64__ */ int -readpmem_sadump(unsigned long long paddr, void *bufptr, size_t size) +readpage_sadump(unsigned long long paddr, void *bufptr) { unsigned long long pfn, block, whole_offset, perdisk_offset; ulong page_offset; - char buf[info->page_size]; int fd_memory; if (si->kdump_backed_up && @@ -965,12 +962,12 @@ readpmem_sadump(unsigned long long paddr page_offset = paddr % info->page_size; if (pfn >= si->sh_memory->max_mapnr) - goto error; + return FALSE; if (!is_dumpable(info->bitmap_memory, pfn)) { ERRMSG("pfn(%llx) is excluded from %s.\n", pfn, info->name_memory); - goto error; + return FALSE; } block = pfn_to_block(pfn); @@ -980,7 +977,7 @@ readpmem_sadump(unsigned long long paddr int diskid; if (!lookup_diskset(whole_offset, &diskid, &perdisk_offset)) - goto error; + return FALSE; fd_memory = si->diskset_info[diskid].fd_memory; perdisk_offset += si->diskset_info[diskid].data_offset; @@ -992,19 +989,12 @@ readpmem_sadump(unsigned long long paddr } if (lseek(fd_memory, perdisk_offset, SEEK_SET) < 0) - goto error; - - if (read(fd_memory, buf, sizeof(buf)) != sizeof(buf)) - goto error; - - memcpy(bufptr, buf + page_offset, size); - - return size; + return FALSE; -error: - DEBUG_MSG("type_addr: %d, addr:%llx, size:%zd\n", PADDR, paddr, size); + if (read(fd_memory, bufptr, info->page_size) != info->page_size) + return FALSE; - return FALSE; + return TRUE; } int diff -Nupr makedumpfile-1.3.5/sadump_info.h makedumpfile-1.5.3/sadump_info.h --- makedumpfile-1.3.5/sadump_info.h 2013-07-03 15:18:37.906089017 +0800 +++ makedumpfile-1.5.3/sadump_info.h 2013-02-18 16:47:26.000000000 +0800 @@ -43,7 +43,7 @@ int sadump_initialize_bitmap_memory(void int sadump_num_online_cpus(void); int sadump_set_timestamp(struct timeval *ts); unsigned long long sadump_get_max_mapnr(void); -int readpmem_sadump(unsigned long long paddr, void *bufptr, size_t size); +int readpage_sadump(unsigned long long paddr, void *bufptr); int sadump_check_debug_info(void); int sadump_generate_vmcoreinfo_from_vmlinux(size_t *vmcoreinfo_size); int sadump_generate_elf_note_from_dumpfile(void); @@ -97,8 +97,8 @@ static inline unsigned long long sadump_ return 0; } -static inline int readpmem_sadump(unsigned long long paddr, - void *bufptr, size_t size) +static inline int +readpage_sadump(unsigned long long paddr, void *bufptr) { return FALSE; } diff -Nupr makedumpfile-1.3.5/x86_64.c makedumpfile-1.5.3/x86_64.c --- makedumpfile-1.3.5/x86_64.c 2009-10-09 09:51:18.000000000 +0800 +++ makedumpfile-1.5.3/x86_64.c 1970-01-01 08:00:00.000000000 +0800 @@ -1,385 +0,0 @@ -/* - * x86_64.c - * - * Copyright (C) 2006, 2007, 2008 NEC Corporation - * - * 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 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifdef __x86_64__ - -#include "makedumpfile.h" - -int -is_vmalloc_addr(ulong vaddr) -{ - /* - * vmalloc, virtual memmap, and module space as VMALLOC space. - */ - return ((vaddr >= VMALLOC_START && vaddr <= VMALLOC_END) - || (vaddr >= VMEMMAP_START && vaddr <= VMEMMAP_END) - || (vaddr >= MODULES_VADDR && vaddr <= MODULES_END)); -} - -int -get_phys_base_x86_64(void) -{ - int i; - struct pt_load_segment *pls; - - /* - * Get the relocatable offset - */ - info->phys_base = 0; /* default/traditional */ - - for (i = 0; i < info->num_load_memory; i++) { - pls = &info->pt_load_segments[i]; - if ((pls->virt_start >= __START_KERNEL_map) && - !(is_vmalloc_addr(pls->virt_start))) { - - info->phys_base = pls->phys_start - - (pls->virt_start & ~(__START_KERNEL_map)); - - break; - } - } - - return TRUE; -} - -int -get_machdep_info_x86_64(void) -{ - int i, j, mfns[MAX_X86_64_FRAMES]; - unsigned long frame_mfn[MAX_X86_64_FRAMES]; - unsigned long buf[MFNS_PER_FRAME]; - - info->section_size_bits = _SECTION_SIZE_BITS; - - if (!(vt.mem_flags & MEMORY_XEN)) - return TRUE; - - /* - * Get the information for translating domain-0's physical - * address into machine address. - */ - if (!readmem(MADDR_XEN, pfn_to_paddr(info->p2m_mfn), - &frame_mfn, PAGESIZE())) { - ERRMSG("Can't get p2m_mfn.\n"); - return FALSE; - } - - /* - * Count the number of p2m frame. - */ - for (i = 0; i < MAX_X86_64_FRAMES; i++) { - mfns[i] = 0; - if (!frame_mfn[i]) - break; - - if (!readmem(MADDR_XEN, pfn_to_paddr(frame_mfn[i]), &buf, - PAGESIZE())) { - ERRMSG("Can't get frame_mfn[%d].\n", i); - return FALSE; - } - for (j = 0; j < MFNS_PER_FRAME; j++) { - if (!buf[j]) - break; - - mfns[i]++; - } - info->p2m_frames += mfns[i]; - } - info->p2m_mfn_frame_list - = malloc(sizeof(unsigned long) * info->p2m_frames); - if (info->p2m_mfn_frame_list == NULL) { - ERRMSG("Can't allocate memory for p2m_mfn_frame_list. %s\n", - strerror(errno)); - return FALSE; - } - - /* - * Get p2m_mfn_frame_list. - */ - for (i = 0; i < MAX_X86_64_FRAMES; i++) { - if (!frame_mfn[i]) - break; - - if (!readmem(MADDR_XEN, pfn_to_paddr(frame_mfn[i]), - &info->p2m_mfn_frame_list[i * MFNS_PER_FRAME], - mfns[i] * sizeof(unsigned long))) { - ERRMSG("Can't get p2m_mfn_frame_list.\n"); - return FALSE; - } - if (mfns[i] != MFNS_PER_FRAME) - break; - } - return TRUE; -} - -int -get_versiondep_info_x86_64(void) -{ - /* - * On linux-2.6.26, MAX_PHYSMEM_BITS is changed to 44 from 40. - */ - if (info->kernel_version < KERNEL_VERSION(2, 6, 26)) - info->max_physmem_bits = _MAX_PHYSMEM_BITS_ORIG; - else if (info->kernel_version < KERNEL_VERSION(2, 6, 31)) - info->max_physmem_bits = _MAX_PHYSMEM_BITS_2_6_26; - else - info->max_physmem_bits = _MAX_PHYSMEM_BITS_2_6_31; - - if (info->kernel_version < KERNEL_VERSION(2, 6, 27)) - info->page_offset = __PAGE_OFFSET_ORIG; - else - info->page_offset = __PAGE_OFFSET_2_6_27; - - if (info->kernel_version < KERNEL_VERSION(2, 6, 31)) { - info->vmalloc_start = VMALLOC_START_ORIG; - info->vmalloc_end = VMALLOC_END_ORIG; - info->vmemmap_start = VMEMMAP_START_ORIG; - info->vmemmap_end = VMEMMAP_END_ORIG; - } else { - info->vmalloc_start = VMALLOC_START_2_6_31; - info->vmalloc_end = VMALLOC_END_2_6_31; - info->vmemmap_start = VMEMMAP_START_2_6_31; - info->vmemmap_end = VMEMMAP_END_2_6_31; - } - - return TRUE; -} - -/* - * Translate a virtual address to a physical address by using 4 levels paging. - */ -unsigned long long -vtop4_x86_64(unsigned long vaddr) -{ - unsigned long page_dir, pml4, pgd_paddr, pgd_pte, pmd_paddr, pmd_pte; - unsigned long pte_paddr, pte; - - if (SYMBOL(init_level4_pgt) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of init_level4_pgt.\n"); - return NOT_PADDR; - } - - /* - * Get PGD. - */ - page_dir = SYMBOL(init_level4_pgt); - page_dir += pml4_index(vaddr) * sizeof(unsigned long); - if (!readmem(VADDR, page_dir, &pml4, sizeof pml4)) { - ERRMSG("Can't get pml4 (page_dir:%lx).\n", page_dir); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PGD : %16lx => %16lx\n", page_dir, pml4); - - if (!(pml4 & _PAGE_PRESENT)) { - ERRMSG("Can't get a valid pml4.\n"); - return NOT_PADDR; - } - - /* - * Get PUD. - */ - pgd_paddr = pml4 & PHYSICAL_PAGE_MASK; - pgd_paddr += pgd_index(vaddr) * sizeof(unsigned long); - if (!readmem(PADDR, pgd_paddr, &pgd_pte, sizeof pgd_pte)) { - ERRMSG("Can't get pgd_pte (pgd_paddr:%lx).\n", pgd_paddr); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PUD : %16lx => %16lx\n", pgd_paddr, pgd_pte); - - if (!(pgd_pte & _PAGE_PRESENT)) { - ERRMSG("Can't get a valid pgd_pte.\n"); - return NOT_PADDR; - } - - /* - * Get PMD. - */ - pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; - pmd_paddr += pmd_index(vaddr) * sizeof(unsigned long); - if (!readmem(PADDR, pmd_paddr, &pmd_pte, sizeof pmd_pte)) { - ERRMSG("Can't get pmd_pte (pmd_paddr:%lx).\n", pmd_paddr); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PMD : %16lx => %16lx\n", pmd_paddr, pmd_pte); - - if (!(pmd_pte & _PAGE_PRESENT)) { - ERRMSG("Can't get a valid pmd_pte.\n"); - return NOT_PADDR; - } - if (pmd_pte & _PAGE_PSE) - return (PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK) - + (vaddr & ~_2MB_PAGE_MASK); - - /* - * Get PTE. - */ - pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; - pte_paddr += pte_index(vaddr) * sizeof(unsigned long); - if (!readmem(PADDR, pte_paddr, &pte, sizeof pte)) { - ERRMSG("Can't get pte (pte_paddr:%lx).\n", pte_paddr); - return NOT_PADDR; - } - if (info->vaddr_for_vtop == vaddr) - MSG(" PTE : %16lx => %16lx\n", pte_paddr, pte); - - if (!(pte & _PAGE_PRESENT)) { - ERRMSG("Can't get a valid pte.\n"); - return NOT_PADDR; - } - return (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(vaddr); -} - -unsigned long long -vaddr_to_paddr_x86_64(unsigned long vaddr) -{ - unsigned long phys_base; - unsigned long long paddr; - - /* - * Check the relocatable kernel. - */ - if (SYMBOL(phys_base) != NOT_FOUND_SYMBOL) - phys_base = info->phys_base; - else - phys_base = 0; - - if (is_vmalloc_addr(vaddr)) { - if ((paddr = vtop4_x86_64(vaddr)) == NOT_PADDR) { - ERRMSG("Can't convert a virtual address(%lx) to " \ - "physical address.\n", vaddr); - return NOT_PADDR; - } - } else if (vaddr >= __START_KERNEL_map) { - paddr = vaddr - __START_KERNEL_map + phys_base; - - } else { - if (vt.mem_flags & MEMORY_XEN) - paddr = vaddr - PAGE_OFFSET_XEN_DOM0; - else - paddr = vaddr - PAGE_OFFSET; - } - return paddr; -} - -/* - * for Xen extraction - */ -unsigned long long -kvtop_xen_x86_64(unsigned long kvaddr) -{ - unsigned long long dirp, entry; - - if (!is_xen_vaddr(kvaddr)) - return NOT_PADDR; - - if (is_xen_text(kvaddr)) - return (unsigned long)kvaddr - XEN_VIRT_START + info->xen_phys_start; - - if (is_direct(kvaddr)) - return (unsigned long)kvaddr - DIRECTMAP_VIRT_START; - - if ((dirp = kvtop_xen_x86_64(SYMBOL(pgd_l4))) == NOT_PADDR) - return NOT_PADDR; - dirp += pml4_index(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) - return NOT_PADDR; - - dirp = entry & ENTRY_MASK; - dirp += pgd_index(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) - return NOT_PADDR; - - dirp = entry & ENTRY_MASK; - dirp += pmd_index(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) - return NOT_PADDR; - - if (entry & _PAGE_PSE) { - entry = (entry & ENTRY_MASK) + (kvaddr & ((1UL << PMD_SHIFT) - 1)); - return entry; - } - dirp = entry & ENTRY_MASK; - dirp += pte_index(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) { - return NOT_PADDR; - } - - entry = (entry & ENTRY_MASK) + (kvaddr & ((1UL << PTE_SHIFT) - 1)); - - return entry; -} - -int get_xen_info_x86_64(void) -{ - unsigned long frame_table_vaddr; - unsigned long xen_end; - int i; - - if (SYMBOL(pgd_l4) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get pml4.\n"); - return FALSE; - } - - if (SYMBOL(frame_table) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of frame_table.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(frame_table), &frame_table_vaddr, - sizeof(frame_table_vaddr))) { - ERRMSG("Can't get the value of frame_table.\n"); - return FALSE; - } - info->frame_table_vaddr = frame_table_vaddr; - - if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of xenheap_phys_end.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end, - sizeof(xen_end))) { - ERRMSG("Can't get the value of xenheap_phys_end.\n"); - return FALSE; - } - info->xen_heap_start = 0; - info->xen_heap_end = paddr_to_pfn(xen_end); - - /* - * pickled_id == domain addr for x86_64 - */ - for (i = 0; i < info->num_domain; i++) { - info->domain_list[i].pickled_id = - info->domain_list[i].domain_addr; - } - - return TRUE; -} - -#endif /* x86_64 */ - diff -Nupr makedumpfile-1.3.5/x86.c makedumpfile-1.5.3/x86.c --- makedumpfile-1.3.5/x86.c 2009-10-09 09:51:18.000000000 +0800 +++ makedumpfile-1.5.3/x86.c 1970-01-01 08:00:00.000000000 +0800 @@ -1,278 +0,0 @@ -/* - * x86.c - * - * Copyright (C) 2006, 2007, 2008 NEC Corporation - * - * 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 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifdef __x86__ - -#include "makedumpfile.h" - -int -get_machdep_info_x86(void) -{ - unsigned long vmlist, vmalloc_start; - - /* PAE */ - if ((vt.mem_flags & MEMORY_X86_PAE) - || ((SYMBOL(pkmap_count) != NOT_FOUND_SYMBOL) - && (SYMBOL(pkmap_count_next) != NOT_FOUND_SYMBOL) - && ((SYMBOL(pkmap_count_next)-SYMBOL(pkmap_count))/sizeof(int)) - == 512)) { - DEBUG_MSG("\n"); - DEBUG_MSG("PAE : ON\n"); - vt.mem_flags |= MEMORY_X86_PAE; - info->max_physmem_bits = _MAX_PHYSMEM_BITS_PAE; - } else { - DEBUG_MSG("\n"); - DEBUG_MSG("PAE : OFF\n"); - info->max_physmem_bits = _MAX_PHYSMEM_BITS; - } - info->page_offset = __PAGE_OFFSET; - - if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of _stext.\n"); - return FALSE; - } - info->kernel_start = SYMBOL(_stext) & ~KVBASE_MASK; - DEBUG_MSG("kernel_start : %lx\n", info->kernel_start); - - /* - * For the compatibility, makedumpfile should run without the symbol - * vmlist and the offset of vm_struct.addr if they are not necessary. - */ - if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) - || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { - return TRUE; - } - if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) { - ERRMSG("Can't get vmlist.\n"); - return FALSE; - } - if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start, - sizeof(vmalloc_start))) { - ERRMSG("Can't get vmalloc_start.\n"); - return FALSE; - } - info->vmalloc_start = vmalloc_start; - DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start); - - return TRUE; -} - -int -get_versiondep_info_x86(void) -{ - /* - * SECTION_SIZE_BITS of PAE has been changed to 29 from 30 since - * linux-2.6.26. - */ - if (vt.mem_flags & MEMORY_X86_PAE) { - if (info->kernel_version < KERNEL_VERSION(2, 6, 26)) - info->section_size_bits = _SECTION_SIZE_BITS_PAE_ORIG; - else - info->section_size_bits = _SECTION_SIZE_BITS_PAE_2_6_26; - } else - info->section_size_bits = _SECTION_SIZE_BITS; - - return TRUE; -} - -unsigned long long -vtop_x86_PAE(unsigned long vaddr) -{ - unsigned long long page_dir, pgd_pte, pmd_paddr, pmd_pte; - unsigned long long pte_paddr, pte; - - if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); - return NOT_PADDR; - } - - page_dir = SYMBOL(swapper_pg_dir); - page_dir += pgd_index_PAE(vaddr) * sizeof(unsigned long long); - if (!readmem(VADDR, page_dir, &pgd_pte, sizeof(pgd_pte))) { - ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir); - return NOT_PADDR; - } - if (!(pgd_pte & _PAGE_PRESENT)) - return NOT_PADDR; - - if (info->vaddr_for_vtop == vaddr) - MSG(" PGD : %16llx => %16llx\n", page_dir, pgd_pte); - - pmd_paddr = pgd_pte & ENTRY_MASK; - pmd_paddr += pmd_index(vaddr) * sizeof(unsigned long long); - if (!readmem(PADDR, pmd_paddr, &pmd_pte, sizeof(pmd_pte))) { - ERRMSG("Can't get pmd_pte (pmd_paddr:%llx).\n", pmd_paddr); - return NOT_PADDR; - } - if (!(pmd_pte & _PAGE_PRESENT)) - return NOT_PADDR; - - if (info->vaddr_for_vtop == vaddr) - MSG(" PMD : %16llx => %16llx\n", pmd_paddr, pmd_pte); - - if (pmd_pte & _PAGE_PSE) - return (pmd_pte & ENTRY_MASK) + (vaddr & ((1UL << PMD_SHIFT) - 1)); - - pte_paddr = pmd_pte & ENTRY_MASK; - pte_paddr += pte_index(vaddr) * sizeof(unsigned long long); - if (!readmem(PADDR, pte_paddr, &pte, sizeof(pte))) - return NOT_PADDR; - - if (!(pte & _PAGE_PRESENT)) - return NOT_PADDR; - - if (info->vaddr_for_vtop == vaddr) - MSG(" PTE : %16llx => %16llx\n", pte_paddr, pte); - - return (pte & ENTRY_MASK) + (vaddr & ((1UL << PTE_SHIFT) - 1)); -} - -int -is_vmalloc_addr_x86(unsigned long vaddr) -{ - return (info->vmalloc_start && vaddr >= info->vmalloc_start); -} - -unsigned long long -vaddr_to_paddr_x86(unsigned long vaddr) -{ - unsigned long long paddr; - - if ((paddr = vaddr_to_paddr_general(vaddr)) != NOT_PADDR) - return paddr; - - if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) - || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) { - ERRMSG("Can't get necessary information for vmalloc translation.\n"); - return NOT_PADDR; - } - if (!is_vmalloc_addr_x86(vaddr)) - return (vaddr - info->kernel_start); - - if (vt.mem_flags & MEMORY_X86_PAE) { - paddr = vtop_x86_PAE(vaddr); - } else { - /* - * TODO: Support vmalloc translation of not-PAE kernel. - */ - ERRMSG("This makedumpfile does not support vmalloc translation of not-PAE kernel.\n"); - return NOT_PADDR; - } - - return paddr; -} - -/* - * for Xen extraction - */ -unsigned long long -kvtop_xen_x86(unsigned long kvaddr) -{ - unsigned long long dirp, entry; - - if (!is_xen_vaddr(kvaddr)) - return NOT_PADDR; - - if (is_direct(kvaddr)) - return (unsigned long)kvaddr - DIRECTMAP_VIRT_START; - - if ((dirp = kvtop_xen_x86(SYMBOL(pgd_l3))) == NOT_PADDR) - return NOT_PADDR; - dirp += pgd_index_PAE(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) - return NOT_PADDR; - - dirp = entry & ENTRY_MASK; - dirp += pmd_index(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) - return NOT_PADDR; - - if (entry & _PAGE_PSE) { - entry = (entry & ENTRY_MASK) + (kvaddr & ((1UL << PMD_SHIFT) - 1)); - return entry; - } - - dirp = entry & ENTRY_MASK; - dirp += pte_index(kvaddr) * sizeof(unsigned long long); - if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry))) - return NOT_PADDR; - - if (!(entry & _PAGE_PRESENT)) { - return NOT_PADDR; - } - - entry = (entry & ENTRY_MASK) + (kvaddr & ((1UL << PTE_SHIFT) - 1)); - - return entry; -} - -int get_xen_info_x86(void) -{ - unsigned long frame_table_vaddr; - unsigned long xen_end; - int i; - - if (SYMBOL(pgd_l2) == NOT_FOUND_SYMBOL && - SYMBOL(pgd_l3) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get pgd.\n"); - return FALSE; - } - - if (SYMBOL(pgd_l3) == NOT_FOUND_SYMBOL) { - ERRMSG("non-PAE not support right now.\n"); - return FALSE; - } - - if (SYMBOL(frame_table) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of frame_table.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(frame_table), &frame_table_vaddr, - sizeof(frame_table_vaddr))) { - ERRMSG("Can't get the value of frame_table.\n"); - return FALSE; - } - info->frame_table_vaddr = frame_table_vaddr; - - if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) { - ERRMSG("Can't get the symbol of xenheap_phys_end.\n"); - return FALSE; - } - if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end, - sizeof(xen_end))) { - ERRMSG("Can't get the value of xenheap_phys_end.\n"); - return FALSE; - } - info->xen_heap_start = 0; - info->xen_heap_end = paddr_to_pfn(xen_end); - - /* - * pickled_id == domain addr for x86 - */ - for (i = 0; i < info->num_domain; i++) { - info->domain_list[i].pickled_id = - info->domain_list[i].domain_addr; - } - - return TRUE; -} -#endif /* x86 */ -