/* * sadump.h - core analysis suite * * Copyright (c) 2011 FUJITSU LIMITED * * 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. * * Author: HATAYAMA Daisuke */ #include "defs.h" #include "sadump.h" #include /* htonl, htons */ #include #include enum { failed = -1 }; static struct sadump_data sadump_data = { 0 }; static struct sadump_data *sd = &sadump_data; static int read_device(void *buf, size_t bytes, ulong *offset); static int read_dump_header(char *file); static int add_disk(char *file); static int open_dump_file(char *file); static int open_disk(char *file); static uint64_t paddr_to_pfn(physaddr_t paddr); static inline int is_set_bit(char *bitmap, uint64_t pfn); static inline int page_is_ram(uint64_t nr); static inline int page_is_dumpable(uint64_t nr); static int lookup_diskset(uint64_t whole_offset, int *diskid, uint64_t *disk_offset); static struct tm *efi_time_t_to_tm(const efi_time_t *e); static char * guid_to_str(efi_guid_t *guid, char *buf, size_t buflen); static int verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]); static ulong per_cpu_ptr(ulong ptr, int cpu); static ulong early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu); static ulong legacy_per_cpu_ptr(ulong ptr, int cpu); static int get_prstatus_from_crash_notes(int cpu, char *prstatus); static void display_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s); static int cpu_to_apicid(int cpu, int *apicid); static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram); static int block_table_init(void); static uint64_t pfn_to_block(uint64_t pfn); struct sadump_data * sadump_get_sadump_data(void) { if (!SADUMP_VALID() || !SADUMP_DUMPFILE()) return NULL; return &sadump_data; } int sadump_cleanup_sadump_data(void) { int i; if (!SADUMP_VALID() || !SADUMP_DUMPFILE()) return FALSE; if (sd->flags & SADUMP_DISKSET) { for (i = 1; i < sd->sd_list_len; ++i) { if (sd->sd_list[i]->dfd) close(sd->sd_list[i]->dfd); free(sd->sd_list[i]->header); free(sd->sd_list[i]); } } close(sd->dfd); free(sd->header); free(sd->dump_header); free(sd->diskset_header); free(sd->bitmap); free(sd->dumpable_bitmap); free(sd->page_buf); free(sd->block_table); if (sd->sd_list[0]) free(sd->sd_list[0]); free(sd->sd_list); memset(&sadump_data, 0, sizeof(sadump_data)); pc->flags &= ~SADUMP; pc->dumpfile = NULL; pc->readmem = NULL; pc->writemem = NULL; return TRUE; } static int read_device(void *buf, size_t bytes, ulong *offset) { if (lseek(sd->dfd, *offset, SEEK_SET) == failed) { error(INFO, "sadump: cannot lseek dump device\n"); return FALSE; } if (read(sd->dfd, buf, bytes) < bytes) { error(INFO, "sadump: cannot read dump device\n"); return FALSE; } *offset += bytes; return TRUE; } static int read_dump_header(char *file) { struct sadump_part_header *sph = NULL; struct sadump_header *sh = NULL; struct sadump_disk_set_header *new, *sdh = NULL; struct sadump_media_header *smh = NULL; struct sadump_diskset_data *sd_list_len_0 = NULL; size_t block_size = SADUMP_DEFAULT_BLOCK_SIZE; ulong flags = 0; ulong offset = 0, sub_hdr_offset, data_offset; uint32_t smram_cpu_state_size = 0; ulong bitmap_len, dumpable_bitmap_len; char *bitmap = NULL, *dumpable_bitmap = NULL, *page_buf = NULL; char guid1[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; char guid2[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; sph = malloc(block_size); if (!sph) { error(INFO, "sadump: cannot allocate partition header buffer\n"); goto err; } sdh = malloc(block_size); if (!sdh) { error(INFO, "sadump: cannot allocate disk set header buffer\n"); goto err; } sh = malloc(block_size); if (!sh) { error(INFO, "sadump: cannot allocate dump header buffer\n"); goto err; } smh = malloc(block_size); if (!smh) { error(INFO, "sadump: cannot allocate media header buffer\n"); goto err; } restart: if (!read_device(sph, block_size, &offset)) { error(INFO, "sadump: cannot read partition header\n"); goto err; } if (sph->signature1 != SADUMP_SIGNATURE1 || sph->signature2 != SADUMP_SIGNATURE2) { flags |= SADUMP_MEDIA; if (CRASHDEBUG(1)) error(INFO, "sadump: read dump device as media " "format\n"); offset = 0; if (!read_device(smh, block_size, &offset)) { error(INFO, "sadump: cannot read media header\n"); goto err; } if (!read_device(sph, block_size, &offset)) { error(INFO, "sadump: cannot read partition header\n"); goto err; } if (sph->signature1 != SADUMP_SIGNATURE1 || sph->signature2 != SADUMP_SIGNATURE2) { if (CRASHDEBUG(1)) error(INFO, "sadump: does not have partition " "header\n"); goto err; } } if (!verify_magic_number(sph->magicnum)) { error(INFO, "sadump: invalid magic number\n"); goto err; } if (!(flags & SADUMP_MEDIA) && sph->set_disk_set) { uint32_t header_blocks; size_t header_size; flags |= SADUMP_DISKSET; if (CRASHDEBUG(1)) error(INFO, "sadump: read dump device as diskset\n"); if (sph->set_disk_set != 1 || sph->set_disk_set > SADUMP_MAX_DISK_SET_NUM) { if (CRASHDEBUG(1)) error(INFO, "sadump: invalid disk set number: " "%d\n", sph->set_disk_set); goto err; } if (!read_device(&header_blocks, sizeof(uint32_t), &offset)) { error(INFO, "sadump: cannot read disk set header " "size\n"); goto err; } offset -= sizeof(uint32_t); header_size = header_blocks * block_size; if (header_size > block_size) { new = realloc(sdh, header_size); if (!new) { error(INFO, "sadump: cannot re-allocate disk " "set buffer\n"); goto err; } sdh = new; } if (!read_device(sdh, header_size, &offset)) { error(INFO, "sadump: cannot read disk set header\n"); goto err; } } if (!read_device(sh, block_size, &offset)) { error(INFO, "sadump: cannot read dump header\n"); goto err; } sub_hdr_offset = offset; if (strncmp(sh->signature, SADUMP_SIGNATURE, 8) != 0) { if (CRASHDEBUG(1)) error(INFO, "sadump: does not have dump header\n"); goto err; } if (flags & SADUMP_MEDIA) { if (memcmp(&sph->sadump_id, &smh->sadump_id, sizeof(efi_guid_t)) != 0) { if (CRASHDEBUG(1)) error(INFO, "sadump: system ID mismatch\n" " partition header: %s\n" " media header: %s\n", guid_to_str(&sph->sadump_id, guid1, sizeof(guid1)), guid_to_str(&smh->sadump_id, guid2, sizeof(guid2))); goto err; } if (memcmp(&sph->disk_set_id, &smh->disk_set_id, sizeof(efi_guid_t)) != 0) { if (CRASHDEBUG(1)) error(INFO, "sadump: disk set ID mismatch\n" " partition header: %s\n" " media header: %s\n", guid_to_str(&sph->disk_set_id, guid1, sizeof(guid1)), guid_to_str(&smh->disk_set_id, guid2, sizeof(guid2))); goto err; } if (memcmp(&sph->time_stamp, &smh->time_stamp, sizeof(efi_time_t)) != 0) { if (CRASHDEBUG(1)) { error(INFO, "sadump: time stamp mismatch\n"); error(INFO, "sadump: partition header: %s\n", strip_linefeeds(asctime (efi_time_t_to_tm (&sph->time_stamp)))); error(INFO, "sadump: media header: %s\n", strip_linefeeds(asctime (efi_time_t_to_tm (&smh->time_stamp)))); } } if (smh->sequential_num != 1) { error(INFO, "sadump: first media file has sequential " "number %d\n", smh->sequential_num); goto err; } } if (sh->block_size != block_size) { block_size = sh->block_size; offset = 0; goto restart; } if (CRASHDEBUG(1)) { if (flags & SADUMP_MEDIA) error(INFO, "sadump: media backup file\n"); else if (flags & SADUMP_DISKSET) error(INFO, "sadump: diskset configuration with %d " "disks\n", sdh->disk_num); else error(INFO, "sadump: single partition " "configuration\n"); } flags |= SADUMP_LOCAL; switch (sh->header_version) { case 0: sd->max_mapnr = (uint64_t)sh->max_mapnr; break; default: error(WARNING, "sadump: unsupported header version: %u\n" "sadump: assuming header version: 1\n", sh->header_version); case 1: sd->max_mapnr = sh->max_mapnr_64; break; } if (sh->sub_hdr_size > 0) { if (!read_device(&smram_cpu_state_size, sizeof(uint32_t), &offset)) { error(INFO, "sadump: cannot read SMRAM CPU STATE size\n"); goto err; } smram_cpu_state_size /= sh->nr_cpus; offset -= sizeof(uint32_t); offset += sh->sub_hdr_size * block_size; } if (!sh->bitmap_blocks) { error(INFO, "sadump: bitmap_blocks is zero\n"); goto err; } bitmap_len = block_size * sh->bitmap_blocks; bitmap = calloc(bitmap_len, 1); if (!bitmap) { error(INFO, "sadump: cannot allocate memory for bitmap " "buffer\n"); goto err; } if (!read_device(bitmap, bitmap_len, &offset)) { error(INFO, "sadump: cannot read bitmap\n"); goto err; } if (!sh->dumpable_bitmap_blocks) { error(INFO, "sadump: dumpable_bitmap_blocks is zero\n"); goto err; } dumpable_bitmap_len = block_size * sh->dumpable_bitmap_blocks; dumpable_bitmap = calloc(dumpable_bitmap_len, 1); if (!dumpable_bitmap) { error(INFO, "sadump: cannot allocate memory for " "dumpable_bitmap buffer\n"); goto err; } if (!read_device(dumpable_bitmap, dumpable_bitmap_len, &offset)) { error(INFO, "sadump: cannot read dumpable bitmap\n"); goto err; } data_offset = offset; page_buf = malloc(block_size); if (!page_buf) { error(INFO, "sadump: cannot allocate page buffer\n"); goto err; } sd->filename = file; /* * Switch to zero excluded mode by default on sadump-related * formats because some Fujitsu troubleshooting software * assumes the behavior. */ sd->flags = flags | SADUMP_ZERO_EXCLUDED; if (machine_type("X86")) sd->machine_type = EM_386; else if (machine_type("X86_64")) sd->machine_type = EM_X86_64; else { error(INFO, "sadump: unsupported machine type: %s\n", MACHINE_TYPE); goto err; } sd->data_offset = data_offset; sd->block_size = block_size; sd->block_shift = ffs(sd->block_size) - 1; sd->bitmap = bitmap; sd->dumpable_bitmap = dumpable_bitmap; sd->sub_hdr_offset = sub_hdr_offset; sd->smram_cpu_state_size = smram_cpu_state_size; sd->header = sph; sd->dump_header = sh; if (flags & SADUMP_DISKSET) sd->diskset_header = sdh; if (flags & SADUMP_MEDIA) sd->media_header = smh; sd->page_buf = page_buf; if (flags & SADUMP_DISKSET) { sd_list_len_0 = malloc(sizeof(struct sadump_diskset_data)); if (!sd_list_len_0) { error(INFO, "sadump: cannot allocate diskset data buffer\n"); goto err; } sd_list_len_0->filename = sd->filename; sd_list_len_0->dfd = sd->dfd; sd_list_len_0->header = sd->header; sd_list_len_0->data_offset = sd->data_offset; sd->sd_list = malloc(sizeof(struct sadump_diskset_data *)); if (!sd->sd_list) { error(INFO, "sadump: cannot allocate diskset list buffer\n"); goto err; } sd->sd_list_len = 1; sd->sd_list[0] = sd_list_len_0; } if (!block_table_init()) { error(INFO, "sadump: cannot initialize block hash table\n"); goto err; } if (!(flags & SADUMP_DISKSET)) free(sdh); if (!(flags & SADUMP_MEDIA)) free(smh); return TRUE; err: close(sd->dfd); free(sph); free(sdh); free(sh); free(smh); free(bitmap); free(dumpable_bitmap); free(page_buf); free(sd_list_len_0); free(sd->sd_list); return FALSE; } static int add_disk(char *file) { struct sadump_part_header *ph; struct sadump_diskset_data *this_disk; int diskid; char guid1[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; char guid2[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; diskid = sd->sd_list_len - 1; this_disk = sd->sd_list[diskid]; if (CRASHDEBUG(1)) error(INFO, "sadump: add disk #%d\n", diskid+1); ph = malloc(sd->block_size); if (!ph) { error(INFO, "sadump: cannot malloc block_size buffer\n"); return FALSE; } if (lseek(this_disk->dfd, 0, SEEK_SET) == failed) { error(INFO, "sadump: cannot lseek dump partition header\n"); free(ph); return FALSE; } if (read(this_disk->dfd, ph, sd->block_size) < sd->block_size) { error(INFO, "sadump: cannot read dump partition header\n"); free(ph); return FALSE; } if (ph->signature1 != SADUMP_SIGNATURE1 || ph->signature2 != SADUMP_SIGNATURE2) { if (CRASHDEBUG(1)) error(INFO, "sadump: does not have partition header\n"); free(ph); return FALSE; } if (memcmp(&sd->header->sadump_id, &ph->sadump_id, sizeof(efi_guid_t)) != 0) { if (CRASHDEBUG(1)) error(INFO, "sadump: system ID mismatch\n" " partition header on disk #1: %s\n" " partition header on disk #%d: %s\n", guid_to_str(&sd->header->sadump_id, guid1, sizeof(guid1)), diskid+1, guid_to_str(&ph->sadump_id, guid2, sizeof(guid2))); free(ph); return FALSE; } if (memcmp(&sd->header->disk_set_id, &ph->disk_set_id, sizeof(efi_guid_t)) != 0) { if (CRASHDEBUG(1)) error(INFO, "sadump: disk set ID mismatch\n" " partition header on disk #1: %s\n" " partition header on disk #%d: %s\n", guid_to_str(&sd->header->disk_set_id, guid1, sizeof(guid1)), diskid+1, guid_to_str(&ph->disk_set_id, guid2, sizeof(guid2))); free(ph); return FALSE; } if (memcmp(&sd->diskset_header->vol_info[diskid - 1].id, &ph->vol_id, sizeof(efi_guid_t)) != 0) { if (CRASHDEBUG(1)) error(INFO, "sadump: volume ID mismatch\n" " disk set header on disk #1: %s\n" " partition header on disk #%d: %s\n", guid_to_str(&sd->diskset_header->vol_info[diskid-1].id, guid1, sizeof(guid1)), diskid+1, guid_to_str(&ph->vol_id, guid2, sizeof(guid2))); free(ph); return FALSE; } if (memcmp(&sd->header->time_stamp, &ph->time_stamp, sizeof(efi_time_t)) != 0) { if (CRASHDEBUG(1)) { error(INFO, "sadump: time stamp mismatch\n"); error(INFO, "sadump: partition header on disk #1: %s\n", strip_linefeeds(asctime (efi_time_t_to_tm (&sd->header->time_stamp)))); error(INFO, "sadump: partition header on disk #%d: %s\n", diskid+1, strip_linefeeds(asctime (efi_time_t_to_tm (&ph->time_stamp)))); } } if (diskid != ph->set_disk_set - 1) { if (CRASHDEBUG(1)) error(INFO, "sadump: wrong disk order; " "#%d expected but #%d given\n", diskid+1, ph->set_disk_set); free(ph); return FALSE; } this_disk->header = ph; this_disk->data_offset = sd->block_size; this_disk->filename = file; return TRUE; } static int open_dump_file(char *file) { int fd; fd = open(file, O_RDONLY); if (fd < 0) { error(INFO, "sadump: unable to open dump file %s", file); return FALSE; } sd->dfd = fd; return TRUE; } static int open_disk(char *file) { struct sadump_diskset_data *this_disk; sd->sd_list_len++; if (CRASHDEBUG(1)) error(INFO, "sadump: open disk #%d\n", sd->sd_list_len); if (sd->sd_list_len > sd->diskset_header->disk_num) { error(INFO, "sadump: too many diskset arguments; " "this diskset consists of %d disks\n", sd->diskset_header->disk_num); return FALSE; } sd->sd_list = realloc(sd->sd_list, sd->sd_list_len * sizeof(struct sadump_diskset_data *)); if (!sd->sd_list) { if (CRASHDEBUG(1)) { error(INFO, "sadump: cannot malloc diskset list buffer\n"); } return FALSE; } this_disk = malloc(sizeof(struct sadump_diskset_data)); if (!this_disk) { if (CRASHDEBUG(1)) { error(INFO, "sadump: cannot malloc diskset data buffer\n"); } return FALSE; } memset(this_disk, 0, sizeof(*this_disk)); sd->sd_list[sd->sd_list_len - 1] = this_disk; this_disk->dfd = open(file, O_RDONLY); if (!this_disk->dfd) { free(this_disk); error(INFO, "sadump: unable to open dump file %s", file); return FALSE; } return TRUE; } int is_sadump(char *file) { if (SADUMP_VALID()) { if (!(sd->flags & SADUMP_DISKSET)) { if (CRASHDEBUG(1)) error(INFO, "sadump: does not support multiple" " file formats\n"); (void) sadump_cleanup_sadump_data(); return FALSE; } if (!open_disk(file) || !add_disk(file)) { (void) sadump_cleanup_sadump_data(); return FALSE; } return TRUE; } if (!open_dump_file(file) || !read_dump_header(file)) return FALSE; return TRUE; } int sadump_is_diskset(void) { if (!SADUMP_VALID()) return FALSE; return !!(sd->flags & SADUMP_DISKSET); } uint sadump_page_size(void) { return sd->dump_header->block_size; } /* * Translate physical address in paddr to PFN number. This means normally that * we just shift paddr by some constant. */ static uint64_t paddr_to_pfn(physaddr_t paddr) { return paddr >> sd->block_shift; } static inline int is_set_bit(char *bitmap, uint64_t pfn) { ulong index, bit; index = pfn >> 3; bit = 7 - (pfn & 7); return !!(bitmap[index] & (1UL << bit)); } static inline int page_is_ram(uint64_t nr) { return is_set_bit(sd->bitmap, nr); } static inline int page_is_dumpable(uint64_t nr) { return is_set_bit(sd->dumpable_bitmap, nr); } static int lookup_diskset(uint64_t whole_offset, int *diskid, uint64_t *disk_offset) { uint64_t offset = whole_offset; int i; for (i = 0; i < sd->sd_list_len; ++i) { uint64_t used_device_i, ram_size; ulong data_offset_i; used_device_i = sd->sd_list[i]->header->used_device; data_offset_i = sd->sd_list[i]->data_offset; ram_size = used_device_i - data_offset_i; if (offset < ram_size) break; offset -= ram_size; } if (i == sd->sd_list_len) return FALSE; *diskid = i; *disk_offset = offset; return TRUE; } int read_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) { physaddr_t curpaddr ATTRIBUTE_UNUSED; uint64_t pfn, whole_offset, perdisk_offset, block; ulong page_offset; int dfd; if (sd->flags & SADUMP_KDUMP_BACKUP && paddr >= sd->backup_src_start && paddr < sd->backup_src_start + sd->backup_src_size) { ulong orig_paddr; orig_paddr = paddr; paddr += sd->backup_offset - sd->backup_src_start; if (CRASHDEBUG(1)) error(INFO, "sadump: kdump backup region: %#llx => %#llx\n", orig_paddr, paddr); } pfn = paddr_to_pfn(paddr); curpaddr = paddr & ~((physaddr_t)(sd->block_size-1)); page_offset = paddr & ((physaddr_t)(sd->block_size-1)); if ((pfn >= sd->max_mapnr) || !page_is_ram(pfn)) return SEEK_ERROR; if (!page_is_dumpable(pfn)) { if (!(sd->flags & SADUMP_ZERO_EXCLUDED)) return PAGE_EXCLUDED; memset(bufptr, 0, cnt); return cnt; } block = pfn_to_block(pfn); whole_offset = block * sd->block_size; if (sd->flags & SADUMP_DISKSET) { int diskid; if (!lookup_diskset(whole_offset, &diskid, &perdisk_offset)) return SEEK_ERROR; dfd = sd->sd_list[diskid]->dfd; perdisk_offset += sd->sd_list[diskid]->data_offset; } else { dfd = sd->dfd; perdisk_offset = whole_offset + sd->data_offset; } if (lseek(dfd, perdisk_offset, SEEK_SET) == failed) return SEEK_ERROR; if (read(dfd, sd->page_buf, sd->block_size) != sd->block_size) return READ_ERROR; memcpy(bufptr, sd->page_buf + page_offset, cnt); return cnt; } int write_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) { return 0; } int sadump_init(char *unused, FILE *fptr) { if (!SADUMP_VALID()) return FALSE; return TRUE; } ulong get_sadump_panic_task(void) { return NO_TASK; } ulong get_sadump_switch_stack(ulong task) { return 0; } static struct tm * efi_time_t_to_tm(const efi_time_t *e) { static struct tm t; time_t ti; memset(&t, 0, sizeof(t)); t.tm_sec = e->second; t.tm_min = e->minute; t.tm_hour = e->hour; t.tm_mday = e->day; t.tm_mon = e->month - 1; t.tm_year = e->year - 1900; if (e->timezone != EFI_UNSPECIFIED_TIMEZONE) t.tm_hour += e->timezone; else if (CRASHDEBUG(1)) error(INFO, "sadump: timezone information is missing\n"); ti = mktime(&t); if (ti == (time_t)-1) return &t; return localtime_r(&ti, &t); } static char * guid_to_str(efi_guid_t *guid, char *buf, size_t buflen) { snprintf(buf, buflen, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", htonl(guid->data1), htons(guid->data2), htons(guid->data3), guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); return buf; } static int verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]) { int i; for (i = 1; i < DUMP_PART_HEADER_MAGICNUM_SIZE; ++i) if (magicnum[i] != (magicnum[i - 1] + 7) * 11) return FALSE; return TRUE; } int sadump_memory_used(void) { return 0; } int sadump_free_memory(void) { return 0; } /* * This function is dump-type independent, and could be used to dump * the diskdump_data structure contents and perhaps the sadump header * data. */ int sadump_memory_dump(FILE *fp) { struct sadump_part_header *sph; struct sadump_disk_set_header *sdh; struct sadump_header *sh; struct sadump_media_header *smh; int i, others; char guid[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; fprintf(fp, "sadump_data: \n"); fprintf(fp, " filename: %s\n", sd->filename); fprintf(fp, " flags: %lx (", sd->flags); others = 0; if (sd->flags & SADUMP_LOCAL) fprintf(fp, "%sSADUMP_LOCAL", others++ ? "|" : ""); if (sd->flags & SADUMP_DISKSET) fprintf(fp, "%sSADUMP_DISKSET", others++ ? "|" : ""); if (sd->flags & SADUMP_MEDIA) fprintf(fp, "%sSADUMP_MEDIA", others++ ? "|" : ""); if (sd->flags & SADUMP_ZERO_EXCLUDED) fprintf(fp, "%sSADUMP_ZERO_EXCLUDED", others++ ? "|" : ""); if (sd->flags & SADUMP_KDUMP_BACKUP) fprintf(fp, "%sSADUMP_KDUMP_BACKUP", others++ ? "|" : ""); fprintf(fp, ") \n"); fprintf(fp, " dfd: %d\n", sd->dfd); fprintf(fp, " machine_type: %d ", sd->machine_type); switch (sd->machine_type) { case EM_386: fprintf(fp, "(EM_386)\n"); break; case EM_X86_64: fprintf(fp, "(EM_X86_64)\n"); break; default: fprintf(fp, "(unknown)\n"); break; } fprintf(fp, "\n header: %lx\n", (ulong)sd->header); sph = sd->header; fprintf(fp, " signature1: %x\n", sph->signature1); fprintf(fp, " signature2: %x\n", sph->signature2); fprintf(fp, " enable: %u\n", sph->enable); fprintf(fp, " reboot: %u\n", sph->reboot); fprintf(fp, " compress: %u\n", sph->compress); fprintf(fp, " recycle: %u\n", sph->recycle); fprintf(fp, " label: (unused)\n"); fprintf(fp, " sadump_id: %s\n", guid_to_str(&sph->sadump_id, guid, sizeof(guid))); fprintf(fp, " disk_set_id: %s\n", guid_to_str(&sph->disk_set_id, guid, sizeof(guid))); fprintf(fp, " vol_id: %s\n", guid_to_str(&sph->vol_id, guid, sizeof(guid))); fprintf(fp, " time_stamp: %s\n", strip_linefeeds(asctime(efi_time_t_to_tm(&sph->time_stamp)))); fprintf(fp, " set_disk_set: %u\n", sph->set_disk_set); fprintf(fp, " reserve: %u\n", sph->reserve); fprintf(fp, " used_device: %llu\n", (ulonglong)sph->used_device); fprintf(fp, " magicnum: %s\n", verify_magic_number(sph->magicnum) ? "(valid)" : "(invalid)"); fprintf(fp, "\n dump header: %lx\n", (ulong)sd->dump_header); sh = sd->dump_header; fprintf(fp, " signature: %s\n", sh->signature); fprintf(fp, " header_version: %u\n", sh->header_version); fprintf(fp, " reserve: %u\n", sh->reserve); fprintf(fp, " timestamp: %s\n", strip_linefeeds(asctime(efi_time_t_to_tm(&sh->timestamp)))); fprintf(fp, " status: %u\n", sh->status); fprintf(fp, " compress: %u\n", sh->compress); fprintf(fp, " block_size: %u\n", sh->block_size); fprintf(fp, " extra_hdr_size: %u\n", sh->extra_hdr_size); fprintf(fp, " sub_hdr_size: %u\n", sh->sub_hdr_size); fprintf(fp, " bitmap_blocks: %u\n", sh->bitmap_blocks); fprintf(fp, "dumpable_bitmap_blocks: %u\n", sh->dumpable_bitmap_blocks); fprintf(fp, " max_mapnr: %u\n", sh->max_mapnr); fprintf(fp, " total_ram_blocks: %u\n", sh->total_ram_blocks); fprintf(fp, " device_blocks: %u\n", sh->device_blocks); fprintf(fp, " written_blocks: %u\n", sh->written_blocks); fprintf(fp, " current_cpu: %u\n", sh->current_cpu); fprintf(fp, " nr_cpus: %u\n", sh->nr_cpus); if (sh->header_version >= 1) { fprintf(fp, " max_mapnr_64: %" PRIu64 "\n" " total_ram_blocks_64: %" PRIu64 "\n" " device_blocks_64: %" PRIu64 "\n" " written_blocks_64: %" PRIu64 "\n", sh->max_mapnr_64, sh->total_ram_blocks_64, sh->device_blocks_64, sh->written_blocks_64); } fprintf(fp, "\n dump sub heaer: "); if (sh->sub_hdr_size > 0) { ulong offset = sd->sub_hdr_offset; struct sadump_apic_state as; struct sadump_smram_cpu_state scs, zero; uint32_t size; uint aid; memset(&zero, 0, sizeof(zero)); if (!read_device(&size, sizeof(uint32_t), &offset)) { error(INFO, "sadump: cannot read sub header size\n"); return FALSE; } fprintf(fp, "\n size: %u\n", size); for (aid = 0; aid < sh->nr_cpus; ++aid) { if (!read_device(&as, sizeof(as), &offset)) { error(INFO, "sadump: cannot read sub header " "apic_id\n"); return FALSE; } fprintf(fp, " " "apic_id[%u]: ApicId %llu: Ldr: %llu\n", aid, (ulonglong)as.ApicId, (ulonglong)as.Ldr); } for (aid = 0; aid < sh->nr_cpus; ++aid) { if (!read_device(&scs, sizeof(scs), &offset)) { error(INFO, "sadump: cannot read sub header " "cpu_state\n"); return FALSE; } if (memcmp(&scs, &zero, sizeof(scs)) != 0) { fprintf(fp, "\n"); display_smram_cpu_state(aid, &scs); } } } else fprintf(fp, "(n/a)\n"); fprintf(fp, "\n disk set header: %lx ", (ulong)sd->diskset_header); if ((sdh = sd->diskset_header)) { fprintf(fp, "\ndisk_set_header_size: %u\n", sdh->disk_set_header_size); fprintf(fp, " disk_num: %u\n", sdh->disk_num); fprintf(fp, " disk_set_size: %llu\n", (ulonglong)sdh->disk_set_size); for (i = 0; i < sdh->disk_num - 1; ++i) { struct sadump_volume_info *vol = &sdh->vol_info[i]; fprintf(fp, " vol_info[%d]: \n", i); fprintf(fp, " id: %s\n", guid_to_str(&vol->id, guid, sizeof(guid))); fprintf(fp, " vol_size: %llu\n", (ulonglong)vol->vol_size); fprintf(fp, " status: %u\n", vol->status); fprintf(fp, " cache_size: %u\n", vol->cache_size); } } else fprintf(fp, "(n/a)\n"); fprintf(fp, "\n media header: %lx ", (ulong)sd->media_header); if ((smh = sd->media_header)) { fprintf(fp, "\n sadump_id: %s\n", guid_to_str(&smh->sadump_id, guid, sizeof(guid))); fprintf(fp, " disk_set_id: %s\n", guid_to_str(&smh->disk_set_id, guid, sizeof(guid))); fprintf(fp, " time_stamp: %s\n", strip_linefeeds(asctime(efi_time_t_to_tm(&smh->time_stamp)))); fprintf(fp, " sequential_num: %d\n", smh->sequential_num); fprintf(fp, " term_cord: %d\n", smh->term_cord); fprintf(fp, "disk_set_header_size: %d\n", smh->disk_set_header_size); fprintf(fp, " disks_in_use: %d\n", smh->disks_in_use); fprintf(fp, " reserve: (not displayed) \n"); } else fprintf(fp, "(n/a)\n"); fprintf(fp, "\n bitmap: %lx\n", (ulong)sd->bitmap); fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)sd->dumpable_bitmap); fprintf(fp, " sub_hdr_offset: %lx\n", (ulong)sd->sub_hdr_offset); fprintf(fp, "smram_cpu_state_size: %lx\n", (ulong)sd->smram_cpu_state_size); fprintf(fp, " data_offset: %lx\n", sd->data_offset); fprintf(fp, " block_size: %d\n", sd->block_size); fprintf(fp, " block_shift: %d\n", sd->block_shift); fprintf(fp, " page_buf: %lx\n", (ulong)sd->page_buf); fprintf(fp, " block_table: %lx\n", (ulong)sd->block_table); fprintf(fp, " sd_list_len: %d\n", sd->sd_list_len); fprintf(fp, " sd_list: %lx\n", (ulong)sd->sd_list); fprintf(fp, " backup_src_start: %llx\n", sd->backup_src_start); fprintf(fp, " backup_src_size: %lx\n", sd->backup_src_size); fprintf(fp, " backup_offset: %llx\n", (ulonglong)sd->backup_src_size); for (i = 0; i < sd->sd_list_len; ++i) { struct sadump_diskset_data *sdd = sd->sd_list[i]; fprintf(fp, "\n sd_list[%d]: \n", i); fprintf(fp, " filename: %s\n", sdd->filename); fprintf(fp, " dfd: %d\n", sdd->dfd); fprintf(fp, " header: %lx\n", (ulong)sdd->header); sph = sdd->header; fprintf(fp, " signature1: %x\n", sph->signature1); fprintf(fp, " signature2: %x\n", sph->signature2); fprintf(fp, " enable: %u\n", sph->enable); fprintf(fp, " reboot: %u\n", sph->reboot); fprintf(fp, " compress: %u\n", sph->compress); fprintf(fp, " recycle: %u\n", sph->recycle); fprintf(fp, " label: (unused)\n"); fprintf(fp, " sadump_id: %s\n", guid_to_str(&sph->sadump_id, guid, sizeof(guid))); fprintf(fp, " disk_set_id: %s\n", guid_to_str(&sph->disk_set_id, guid, sizeof(guid))); fprintf(fp, " vol_id: %s\n", guid_to_str(&sph->vol_id, guid, sizeof(guid))); fprintf(fp, " time_stamp: %s\n", strip_linefeeds(asctime(efi_time_t_to_tm(&sph->time_stamp)))); fprintf(fp, " set_disk_set: %u\n", sph->set_disk_set); fprintf(fp, " reserve: %u\n", sph->reserve); fprintf(fp, " used_device: %llu\n", (ulonglong)sph->used_device); fprintf(fp, " magicnum: %s\n", verify_magic_number(sph->magicnum) ? "(valid)" : "(invalid)"); fprintf(fp, " data_offset: %lx\n", sdd->data_offset); } return TRUE; } static ulong per_cpu_ptr(ulong ptr, int cpu) { if (cpu < 0 || cpu >= kt->cpus) return 0UL; if (kt->cpus == 1) return ptr; if (!(kt->flags & PER_CPU_OFF)) return 0UL; if (machine_type("X86_64")) { ulong __per_cpu_load; readmem(symbol_value("__per_cpu_load"), KVADDR, &__per_cpu_load, sizeof(__per_cpu_load), "__per_cpu_load", FAULT_ON_ERROR); if (kt->__per_cpu_offset[cpu] == __per_cpu_load) return 0UL; } else if (machine_type("X86")) { if (kt->__per_cpu_offset[cpu] == 0) return 0UL; } return ptr + kt->__per_cpu_offset[cpu]; } static ulong early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu) { char sym_early_ptr[BUFSIZE], sym_early_map[BUFSIZE]; ulong early_ptr; if (cpu < 0 || cpu >= kt->cpus) return 0UL; if (!sym && !(sym = per_cpu_symbol_search(symbol))) return 0UL; if (!(kt->flags & SMP)) return per_cpu_ptr(sym->value, cpu); snprintf(sym_early_ptr, BUFSIZE, "%s_early_ptr", symbol); snprintf(sym_early_map, BUFSIZE, "%s_early_map", symbol); if (!symbol_exists(sym_early_ptr) || !symbol_exists(sym_early_map)) return 0UL; readmem(symbol_value(sym_early_ptr), KVADDR, &early_ptr, sizeof(early_ptr), sym_early_ptr, FAULT_ON_ERROR); return early_ptr ? symbol_value(sym_early_map)+cpu*sizeof(uint16_t) : per_cpu_ptr(sym->value, cpu); } static ulong legacy_per_cpu_ptr(ulong ptr, int cpu) { ulong addr; if (!(kt->flags & SMP)) return ptr; if (cpu < 0 || cpu >= kt->cpus) return 0UL; if (!readmem(~ptr + cpu * sizeof(ulong), KVADDR, &addr, sizeof(ulong), "search percpu_data", FAULT_ON_ERROR)) return 0UL; return addr; } /** * Retrieve eip and esp register values from crash_notes saved by * kdump at crash. If register values has not been saved yet, set 0 to * eip and esp instead. */ static int get_prstatus_from_crash_notes(int cpu, char *prstatus) { ulong crash_notes, crash_notes_ptr, percpu_addr; char *prstatus_ptr, *note_buf, *zero_buf, *name; uint32_t *buf; if (cpu < 0 || kt->cpus <= cpu) { error(INFO, "sadump: given cpu is invalid: %d\n", cpu); return FALSE; } if (!symbol_exists("crash_notes")) { error(INFO, "sadump: symbol crash_notes doesn't exist\n"); return FALSE; } crash_notes = symbol_value("crash_notes"); readmem(crash_notes, KVADDR, &crash_notes_ptr, sizeof(ulong), "dereference crash_notes", FAULT_ON_ERROR); if (!crash_notes_ptr) { if (CRASHDEBUG(1)) error(INFO, "sadump: buffer for crash_notes is NULL\n"); return FALSE; } percpu_addr = VALID_STRUCT(percpu_data) ? legacy_per_cpu_ptr(crash_notes_ptr, cpu) : per_cpu_ptr(crash_notes_ptr, cpu); zero_buf = GETBUF(SIZE(note_buf)); BZERO(zero_buf, SIZE(note_buf)); note_buf = GETBUF(SIZE(note_buf)); readmem(percpu_addr, KVADDR, note_buf, SIZE(note_buf), "read crash_notes", FAULT_ON_ERROR); if (memcmp(note_buf, zero_buf, SIZE(note_buf)) == 0) return FALSE; if (BITS64()) { Elf64_Nhdr *note64; note64 = (Elf64_Nhdr *)note_buf; buf = (uint32_t *)note_buf; name = (char *)(note64 + 1); if (note64->n_type != NT_PRSTATUS || note64->n_namesz != strlen("CORE") + 1 || strncmp(name, "CORE", note64->n_namesz) || note64->n_descsz != SIZE(elf_prstatus)) return FALSE; prstatus_ptr = (char *)(buf + (sizeof(*note64) + 3) / 4 + (note64->n_namesz + 3) / 4); } else { Elf32_Nhdr *note32; note32 = (Elf32_Nhdr *)note_buf; buf = (uint32_t *)note_buf; name = (char *)(note32 + 1); if ((note32->n_type != NT_PRSTATUS) && (note32->n_namesz != strlen("CORE") + 1 || strncmp(name, "CORE", note32->n_namesz) || note32->n_descsz != SIZE(elf_prstatus))) return FALSE; prstatus_ptr = (char *)(buf + (sizeof(*note32) + 3) / 4 + (note32->n_namesz + 3) / 4); } memcpy(prstatus, prstatus_ptr, SIZE(elf_prstatus)); return TRUE; } int sadump_get_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *smram) { ulong offset; if (!sd->sub_hdr_offset || !sd->smram_cpu_state_size || apicid >= sd->dump_header->nr_cpus) return FALSE; offset = sd->sub_hdr_offset + sizeof(uint32_t) + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); if (lseek(sd->dfd, offset + apicid * sd->smram_cpu_state_size, SEEK_SET) == failed) error(FATAL, "sadump: cannot lseek smram cpu state in dump sub header\n"); if (read(sd->dfd, smram, sd->smram_cpu_state_size) != sd->smram_cpu_state_size) error(FATAL, "sadump: cannot read smram cpu state in dump sub " "header\n"); return TRUE; } static void display_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s) { fprintf(fp, "APIC ID: %d\n" " RIP: %016llx RSP: %08x%08x RBP: %08x%08x\n" " RAX: %08x%08x RBX: %08x%08x RCX: %08x%08x\n" " RDX: %08x%08x RSI: %08x%08x RDI: %08x%08x\n" " R08: %08x%08x R09: %08x%08x R10: %08x%08x\n" " R11: %08x%08x R12: %08x%08x R13: %08x%08x\n" " R14: %08x%08x R15: %08x%08x\n" " SMM REV: %08x SMM BASE %08x\n" " CS : %08x DS: %08x SS: %08x ES: %08x FS: %08x\n" " GS : %08x\n" " CR0: %016llx CR3: %016llx CR4: %08x\n" " GDT: %08x%08x LDT: %08x%08x IDT: %08x%08x\n" " GDTlim: %08x LDTlim: %08x IDTlim: %08x\n" " LDTR: %08x TR: %08x RFLAGS: %016llx\n" " EPTP: %016llx EPTP_SETTING: %08x\n" " DR6: %016llx DR7: %016llx\n" " Ia32Efer: %016llx\n" " IoMemAddr: %08x%08x IoEip: %016llx\n" " IoMisc: %08x LdtInfo: %08x\n" " IoInstructionRestart: %04x AutoHaltRestart: %04x\n", apicid, (ulonglong)s->Rip, s->RspUpper, s->RspLower, s->RbpUpper, s->RbpLower, s->RaxUpper, s->RaxLower, s->RbxUpper, s->RbxLower, s->RcxUpper, s->RcxLower, s->RdxUpper, s->RdxLower, s->RsiUpper, s->RsiLower, s->RdiUpper, s->RdiLower, s->R8Upper, s->R8Lower, s->R9Upper, s->R9Lower, s->R10Upper, s->R10Lower, s->R11Upper, s->R11Lower, s->R12Upper, s->R12Lower, s->R13Upper, s->R13Lower, s->R14Upper, s->R14Lower, s->R15Upper, s->R15Lower, s->SmmRevisionId, s->Smbase, s->Cs, s->Ds, s->Ss, s->Es, s->Fs, s->Gs, (ulonglong)s->Cr0, (ulonglong)s->Cr3, s->Cr4, s->GdtUpper, s->GdtLower, s->LdtUpper, s->LdtLower, s->IdtUpper, s->IdtLower, s->GdtLimit, s->LdtLimit, s->IdtLimit, s->Ldtr, s->Tr, (ulonglong)s->Rflags, (ulonglong)s->Eptp, s->EptpSetting, (ulonglong)s->Dr6, (ulonglong)s->Dr7, (ulonglong)s->Ia32Efer, s->IoMemAddrUpper, s->IoMemAddrLower, (ulonglong)s->IoEip, s->IoMisc, s->LdtInfo, s->IoInstructionRestart, s->AutoHaltRestart); } static int cpu_to_apicid(int cpu, int *apicid) { struct syment *sym; if (symbol_exists("bios_cpu_apicid")) { uint8_t apicid_u8; readmem(symbol_value("bios_cpu_apicid") + cpu*sizeof(uint8_t), KVADDR, &apicid_u8, sizeof(uint8_t), "bios_cpu_apicid", FAULT_ON_ERROR); *apicid = (int)apicid_u8; if (CRASHDEBUG(1)) error(INFO, "sadump: apicid %u for cpu %d from " "bios_cpu_apicid\n", apicid_u8, cpu); } else if ((sym = per_cpu_symbol_search("x86_bios_cpu_apicid"))) { uint16_t apicid_u16; readmem(early_per_cpu_ptr("x86_bios_cpu_apicid", sym, cpu), KVADDR, &apicid_u16, sizeof(uint16_t), "x86_bios_cpu_apicid", FAULT_ON_ERROR); *apicid = (int)apicid_u16; if (CRASHDEBUG(1)) error(INFO, "sadump: apicid %u for cpu %d from " "x86_bios_cpu_apicid\n", apicid_u16, cpu); } else { if (CRASHDEBUG(1)) error(INFO, "sadump: no symbols for access to apicid\n"); return FALSE; } return TRUE; } static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram) { int apicid = 0; if (cpu < 0 || kt->cpus <= cpu) { error(INFO, "sadump: given cpu is invalid: %d\n", cpu); return FALSE; } if (!cpu_to_apicid(cpu, &apicid)) return FALSE; sadump_get_smram_cpu_state(apicid, smram); return TRUE; } void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp) { ulong ip, sp; struct sadump_smram_cpu_state smram; char *prstatus; int cpu = bt->tc->processor; if (!is_task_active(bt->task)) { machdep->get_stack_frame(bt, ipp, spp); return; } bt->flags |= BT_DUMPFILE_SEARCH; if (machine_type("X86_64")) machdep->get_stack_frame(bt, ipp, spp); else if (machine_type("X86")) get_netdump_regs_x86(bt, ipp, spp); if (bt->flags & BT_DUMPFILE_SEARCH) return; prstatus = GETBUF(SIZE(elf_prstatus)); if (get_prstatus_from_crash_notes(cpu, prstatus)) { ip = ULONG(prstatus + OFFSET(elf_prstatus_pr_reg) + (BITS64() ? OFFSET(user_regs_struct_rip) : OFFSET(user_regs_struct_eip))); sp = ULONG(prstatus + OFFSET(elf_prstatus_pr_reg) + (BITS64() ? OFFSET(user_regs_struct_rsp) : OFFSET(user_regs_struct_eip))); if (ip || sp) { *ipp = ip; *spp = sp; return; } } get_sadump_smram_cpu_state(cpu, &smram); ip = smram.Rip; sp = ((uint64_t)smram.RspUpper << 32) + smram.RspLower; if (is_kernel_text(ip) && (((sp >= GET_STACKBASE(bt->task)) && (sp < GET_STACKTOP(bt->task))) || in_alternate_stack(bt->tc->processor, sp))) { *ipp = ip; *spp = sp; bt->flags |= BT_KERNEL_SPACE; return; } if (!is_kernel_text(ip) && in_user_stack(bt->tc->task, sp)) bt->flags |= BT_USER_SPACE; } void sadump_display_regs(int cpu, FILE *ofp) { struct sadump_smram_cpu_state smram; if (cpu < 0 || cpu >= kt->cpus) { error(INFO, "sadump: given cpu is invalid: %d\n", cpu); return; } get_sadump_smram_cpu_state(cpu, &smram); if (machine_type("X86_64")) { fprintf(ofp, " RIP: %016llx RSP: %016llx RFLAGS: %08llx\n" " RAX: %016llx RBX: %016llx RCX: %016llx\n" " RDX: %016llx RSI: %016llx RDI: %016llx\n" " RBP: %016llx R8: %016llx R9: %016llx\n" " R10: %016llx R11: %016llx R12: %016llx\n" " R13: %016llx R14: %016llx R15: %016llx\n" " CS: %04x SS: %04x\n", (ulonglong)(smram.Rip), (ulonglong)(((uint64_t)smram.RspUpper<<32)+smram.RspLower), (ulonglong)(smram.Rflags), (ulonglong)(((uint64_t)smram.RaxUpper<<32)+smram.RaxLower), (ulonglong)(((uint64_t)smram.RbxUpper<<32)+smram.RbxLower), (ulonglong)(((uint64_t)smram.RcxUpper<<32)+smram.RcxLower), (ulonglong)(((uint64_t)smram.RdxUpper<<32)+smram.RdxLower), (ulonglong)(((uint64_t)smram.RsiUpper<<32)+smram.RsiLower), (ulonglong)(((uint64_t)smram.RdiUpper<<32)+smram.RdiLower), (ulonglong)(((uint64_t)smram.RbpUpper<<32)+smram.RbpLower), (ulonglong)(((uint64_t)smram.R8Upper<<32)+smram.R8Lower), (ulonglong)(((uint64_t)smram.R9Upper<<32)+smram.R9Lower), (ulonglong)(((uint64_t)smram.R10Upper<<32)+smram.R10Lower), (ulonglong)(((uint64_t)smram.R11Upper<<32)+smram.R11Lower), (ulonglong)(((uint64_t)smram.R12Upper<<32)+smram.R12Lower), (ulonglong)(((uint64_t)smram.R13Upper<<32)+smram.R13Lower), (ulonglong)(((uint64_t)smram.R14Upper<<32)+smram.R14Lower), (ulonglong)(((uint64_t)smram.R15Upper<<32)+smram.R15Lower), smram.Cs, smram.Ss); } if (machine_type("X86")) { fprintf(ofp, " EAX: %08llx EBX: %08llx ECX: %08llx EDX: %08llx\n" " DS: %04x ESI: %08llx ES: %04x EDI: %08llx\n" " SS: %04x ESP: %08llx EBP: %08llx GS: %04x\n" " CS: %04x EIP: %08llx EFLAGS: %08llx\n", (ulonglong)smram.RaxLower, (ulonglong)smram.RbxLower, (ulonglong)smram.RcxLower, (ulonglong)smram.RdxLower, smram.Ds & 0xffff, (ulonglong)smram.RsiLower, smram.Es & 0xffff, (ulonglong)smram.RdiLower, smram.Ss, (ulonglong)smram.RspLower, (ulonglong)smram.RbpLower, smram.Gs, smram.Cs, (ulonglong)smram.Rip, (ulonglong)smram.Rflags); } } /* * sadump does not save phys_base; it must resort to another way. */ int sadump_phys_base(ulong *phys_base) { if (SADUMP_VALID() && !sd->phys_base) { if (CRASHDEBUG(1)) error(NOTE, "sadump: does not save phys_base.\n"); return FALSE; } if (sd->phys_base) { *phys_base = sd->phys_base; return TRUE; } return FALSE; } int sadump_set_phys_base(ulong phys_base) { sd->phys_base = phys_base; return TRUE; } /* * Used by "sys" command to show diskset disk names. */ void sadump_show_diskset(void) { int i; for (i = 0; i < sd->sd_list_len; ++i) { char *filename = sd->sd_list[i]->filename; fprintf(fp, "%s%s", i ? " " : "", filename); if ((i+1) < sd->sd_list_len) fprintf(fp, "\n"); } } static int block_table_init(void) { uint64_t pfn, section, max_section, *block_table; max_section = divideup(sd->max_mapnr, SADUMP_PF_SECTION_NUM); block_table = calloc(sizeof(uint64_t), max_section); if (!block_table) { error(INFO, "sadump: cannot allocate memory for block_table\n"); return FALSE; } for (section = 0; section < max_section; ++section) { if (section > 0) block_table[section] = block_table[section-1]; for (pfn = section * SADUMP_PF_SECTION_NUM; pfn < (section + 1) * SADUMP_PF_SECTION_NUM; ++pfn) if (page_is_dumpable(pfn)) block_table[section]++; } sd->block_table = block_table; return TRUE; } static uint64_t pfn_to_block(uint64_t pfn) { uint64_t block, section, p; section = pfn / SADUMP_PF_SECTION_NUM; if (section) block = sd->block_table[section - 1]; else block = 0; for (p = section * SADUMP_PF_SECTION_NUM; p < pfn; ++p) if (page_is_dumpable(p)) block++; return block; } int sadump_is_zero_excluded(void) { return (sd->flags & SADUMP_ZERO_EXCLUDED) ? TRUE : FALSE; } void sadump_set_zero_excluded(void) { sd->flags |= SADUMP_ZERO_EXCLUDED; } void sadump_unset_zero_excluded(void) { sd->flags &= ~SADUMP_ZERO_EXCLUDED; } struct sadump_data * get_sadump_data(void) { return sd; } #ifdef X86_64 static int get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram) { ulong offset; struct sadump_header *sh = sd->dump_header; int apicid; struct sadump_smram_cpu_state scs, zero; offset = sd->sub_hdr_offset + sizeof(uint32_t) + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); memset(&zero, 0, sizeof(zero)); for (apicid = 0; apicid < sh->nr_cpus; ++apicid) { if (!read_device(&scs, sizeof(scs), &offset)) { error(INFO, "sadump: cannot read sub header " "cpu_state\n"); return FALSE; } if (memcmp(&scs, &zero, sizeof(scs)) != 0) { *smram = scs; return TRUE; } } return FALSE; } int sadump_get_cr3_idtr(ulong *cr3, ulong *idtr) { struct sadump_smram_cpu_state scs; memset(&scs, 0, sizeof(scs)); get_sadump_smram_cpu_state_any(&scs); *cr3 = scs.Cr3; *idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower; return TRUE; } #endif /* X86_64 */