crash/sadump.c

1709 lines
44 KiB
C

/*
* 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 <d.hatayama@jp.fujitsu.com>
*/
#include "defs.h"
#include "sadump.h"
#include <arpa/inet.h> /* htonl, htons */
#include <elf.h>
#include <inttypes.h>
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);
static void mask_reserved_fields(struct sadump_smram_cpu_state *smram);
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;
}
/*
* Reserved fields in SMRAM CPU states could
* be non-zero even if the corresponding APICs
* are NOT used. This breaks the assumption
* that SMRAM CPU state is zero cleared if and
* only if the APIC corresponding to the entry
* is NOT used.
*/
mask_reserved_fields(&scs);
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;
}
int
sadump_get_nr_cpus(void)
{
/* apicids */
return sd->dump_header->nr_cpus;
}
#ifdef X86_64
int
sadump_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr)
{
struct sadump_smram_cpu_state scs;
memset(&scs, 0, sizeof(scs));
if (!sadump_get_smram_cpu_state(cpu, &scs))
return FALSE;
*cr3 = scs.Cr3;
*cr4 = scs.Cr4;
*idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower;
return TRUE;
}
#endif /* X86_64 */
static void
mask_reserved_fields(struct sadump_smram_cpu_state *smram)
{
memset(smram->Reserved1, 0, sizeof(smram->Reserved1));
memset(smram->Reserved2, 0, sizeof(smram->Reserved2));
memset(smram->Reserved3, 0, sizeof(smram->Reserved3));
memset(smram->Reserved4, 0, sizeof(smram->Reserved4));
memset(smram->Reserved5, 0, sizeof(smram->Reserved5));
memset(smram->Reserved6, 0, sizeof(smram->Reserved6));
memset(smram->Reserved7, 0, sizeof(smram->Reserved7));
}