Blame lkcd_common.c

Packit bf408e
/* lkcd_common.c - core analysis suite
Packit bf408e
 *
Packit bf408e
 * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
Packit bf408e
 * Copyright (C) 2002 Silicon Graphics, Inc. 
Packit bf408e
 * Copyright (C) 2002 Free Software Foundation, Inc.
Packit bf408e
 * Copyright (C) 2002-2005, 2007, 2009, 2011, 2013 David Anderson
Packit bf408e
 * Copyright (C) 2002-2005, 2007, 2009, 2011, 2013 Red Hat, Inc. All rights reserved.
Packit bf408e
 *
Packit bf408e
 * This program is free software; you can redistribute it and/or modify
Packit bf408e
 * it under the terms of the GNU General Public License as published by
Packit bf408e
 * the Free Software Foundation; either version 2 of the License, or
Packit bf408e
 * (at your option) any later version.
Packit bf408e
 *
Packit bf408e
 * This program is distributed in the hope that it will be useful,
Packit bf408e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bf408e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bf408e
 * GNU General Public License for more details.
Packit bf408e
 */
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  lkcd_uncompress_RLE() is essentially LKCD's __cmpuncompress_page() rountine,
Packit bf408e
 *  adapted from ../cmd/lcrash/lib/libklib/arch/i386/kl_cmp.c:
Packit bf408e
 */
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * arch/i386/cmp.c
Packit bf408e
 *
Packit bf408e
 * This file handles compression aspects of crash dump files
Packit bf408e
 * for i386 based systems.  Most of this is taken from the
Packit bf408e
 * IRIX compression code, with exceptions to how the index
Packit bf408e
 * is created, because the file format is different with Linux.
Packit bf408e
 *
Packit bf408e
 * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
Packit bf408e
 */
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  This file has no knowledge of the dump_header_t, dump_header_asm_t or
Packit bf408e
 *  dump_page_t formats, so it gathers information from them via the version
Packit bf408e
 *  specific "_v1" or "_v2_v3" type routines.
Packit bf408e
 */
Packit bf408e
Packit bf408e
#define LKCD_COMMON
Packit bf408e
#include "defs.h"
Packit bf408e
Packit bf408e
static void dump_dump_page(char *, void *);
Packit bf408e
static int lkcd_uncompress_RLE(unsigned char *, unsigned char *,uint32_t,int *);
Packit bf408e
static int lkcd_uncompress_gzip(unsigned char *, ulong, unsigned char *, ulong);
Packit bf408e
static int hash_page(ulong);
Packit bf408e
static int page_is_cached(void);
Packit bf408e
static int page_is_hashed(long *);
Packit bf408e
static int cache_page(void);
Packit bf408e
Packit bf408e
struct lkcd_environment lkcd_environment = { 0 };
Packit bf408e
struct lkcd_environment *lkcd = &lkcd_environment;
Packit bf408e
static int uncompress_errloc;
Packit bf408e
static int uncompress_recover(unsigned char *, ulong, unsigned char *, ulong);
Packit bf408e
Packit bf408e
ulonglong 
Packit bf408e
fix_lkcd_address(ulonglong addr)
Packit bf408e
{
Packit bf408e
    int i; 
Packit bf408e
    ulong offset;
Packit bf408e
Packit bf408e
    for (i = 0; i < lkcd->fix_addr_num; i++) {
Packit bf408e
	if ( (addr >=lkcd->fix_addr[i].task) && 
Packit bf408e
		(addr < lkcd->fix_addr[i].task + STACKSIZE())){
Packit bf408e
Packit bf408e
	    offset = addr - lkcd->fix_addr[i].task;
Packit bf408e
	    addr = lkcd->fix_addr[i].saddr + offset;
Packit bf408e
	}
Packit bf408e
    }
Packit bf408e
Packit bf408e
    return addr;
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Each version has its own dump initialization.
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
lkcd_dump_init(FILE *fp, int fd, char *dumpfile)
Packit bf408e
{
Packit bf408e
	switch (lkcd->version)
Packit bf408e
	{
Packit bf408e
        case LKCD_DUMP_V1:
Packit bf408e
		return(lkcd_dump_init_v1(fp, fd));
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V2:
Packit bf408e
        case LKCD_DUMP_V3:
Packit bf408e
		return(lkcd_dump_init_v2_v3(fp, fd));
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V5:
Packit bf408e
        case LKCD_DUMP_V6:
Packit bf408e
		return(lkcd_dump_init_v5(fp, fd));
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V7:
Packit bf408e
		return(lkcd_dump_init_v7(fp, fd, dumpfile));
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V8:
Packit bf408e
        case LKCD_DUMP_V9:
Packit bf408e
		return(lkcd_dump_init_v8(fp, fd, dumpfile));
Packit bf408e
Packit bf408e
	default:
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Return the page size value recorded in the dump header.
Packit bf408e
 */
Packit bf408e
uint32_t
Packit bf408e
lkcd_page_size(void)
Packit bf408e
{
Packit bf408e
	return lkcd->page_size;
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Return the panic task and panic string.
Packit bf408e
 */
Packit bf408e
unsigned long
Packit bf408e
get_lkcd_panic_task(void)
Packit bf408e
{
Packit bf408e
	return(lkcd->flags & (LKCD_VALID|LKCD_REMOTE) ? lkcd->panic_task : 0);
Packit bf408e
}
Packit bf408e
Packit bf408e
void
Packit bf408e
get_lkcd_panicmsg(char *buf)
Packit bf408e
{
Packit bf408e
	if (lkcd->flags & (LKCD_VALID|LKCD_REMOTE))
Packit bf408e
		strcpy(buf, lkcd->panic_string);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Called by remote_lkcd_dump_init() the local (!valid) lkcd_environment
Packit bf408e
 *  is used to store the panic task and panic message for use by the
Packit bf408e
 *  two routines above.
Packit bf408e
 */ 
Packit bf408e
void
Packit bf408e
set_remote_lkcd_panic_data(ulong task, char *buf)
Packit bf408e
{
Packit bf408e
	if (buf) {
Packit bf408e
		if (!(lkcd->panic_string = (char *)malloc(strlen(buf)+1))) {
Packit bf408e
			fprintf(stderr, 
Packit bf408e
			    "cannot malloc space for panic message!\n");
Packit bf408e
			clean_exit(1);
Packit bf408e
		}
Packit bf408e
		strcpy(lkcd->panic_string, buf);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (task)
Packit bf408e
		lkcd->panic_task = task;
Packit bf408e
Packit bf408e
	lkcd->flags |= LKCD_REMOTE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Does the magic number indicate an LKCD compressed dump?
Packit bf408e
 *  If so, set the version number for all future forays into the
Packit bf408e
 *  functions in this file.
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
is_lkcd_compressed_dump(char *s)
Packit bf408e
{
Packit bf408e
        int tmpfd;
Packit bf408e
        uint64_t magic;
Packit bf408e
	uint32_t version;
Packit bf408e
	char errbuf[BUFSIZE];
Packit bf408e
Packit bf408e
        if ((tmpfd = open(s, O_RDONLY)) < 0) {
Packit bf408e
		strcpy(errbuf, s);
Packit bf408e
                perror(errbuf);
Packit bf408e
                return FALSE;
Packit bf408e
        }
Packit bf408e
        if (read(tmpfd, &magic, sizeof(uint64_t)) != sizeof(uint64_t)) {
Packit bf408e
                close(tmpfd);
Packit bf408e
                return FALSE;
Packit bf408e
        }
Packit bf408e
        if (read(tmpfd, &version, sizeof(uint32_t)) != sizeof(uint32_t)) {
Packit bf408e
                close(tmpfd);
Packit bf408e
                return FALSE;
Packit bf408e
        }
Packit bf408e
Packit bf408e
        close(tmpfd);
Packit bf408e
Packit bf408e
        if (!((magic == LKCD_DUMP_MAGIC_NUMBER) || 
Packit bf408e
	     (magic == LKCD_DUMP_MAGIC_LIVE)))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	switch (version & ~(LKCD_DUMP_MCLX_V0|LKCD_DUMP_MCLX_V1))
Packit bf408e
	{
Packit bf408e
	case LKCD_DUMP_V1:
Packit bf408e
		lkcd->version = LKCD_DUMP_V1;
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	case LKCD_DUMP_V2:
Packit bf408e
	case LKCD_DUMP_V3:
Packit bf408e
		lkcd->version = LKCD_DUMP_V2;
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	case LKCD_DUMP_V5:
Packit bf408e
	case LKCD_DUMP_V6:
Packit bf408e
		lkcd->version = LKCD_DUMP_V5;
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	case LKCD_DUMP_V7:
Packit bf408e
		lkcd->version = LKCD_DUMP_V7;
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	case LKCD_DUMP_V8:
Packit bf408e
	case LKCD_DUMP_V9:
Packit bf408e
	case LKCD_DUMP_V10:
Packit bf408e
		lkcd->version = LKCD_DUMP_V8;
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	default:
Packit bf408e
		lkcd_print("unsupported LKCD dump version: %ld (%lx)\n", 
Packit bf408e
			version & ~(LKCD_DUMP_MCLX_V0|LKCD_DUMP_MCLX_V1), 
Packit bf408e
			version);
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  console-only output for info regarding current page.
Packit bf408e
 */
Packit bf408e
static void
Packit bf408e
dump_dump_page(char *s, void *dp)
Packit bf408e
{
Packit bf408e
        switch (lkcd->version)
Packit bf408e
        {
Packit bf408e
        case LKCD_DUMP_V1:
Packit bf408e
                dump_dump_page_v1(s, dp);
Packit bf408e
		break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V2:
Packit bf408e
        case LKCD_DUMP_V3:
Packit bf408e
                dump_dump_page_v2_v3(s, dp);
Packit bf408e
		break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V5:
Packit bf408e
                dump_dump_page_v5(s, dp);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V7:
Packit bf408e
                dump_dump_page_v7(s, dp);
Packit bf408e
		break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V8:
Packit bf408e
        case LKCD_DUMP_V9:
Packit bf408e
                dump_dump_page_v8(s, dp);
Packit bf408e
		break;
Packit bf408e
        }
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  help -S output, or as specified by arg.
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
dump_lkcd_environment(ulong arg)
Packit bf408e
{
Packit bf408e
	int others;
Packit bf408e
Packit bf408e
	if (arg == LKCD_DUMP_HEADER_ONLY)
Packit bf408e
		goto dump_header_only;
Packit bf408e
	if (arg == LKCD_DUMP_PAGE_ONLY)
Packit bf408e
		goto dump_page_only;
Packit bf408e
Packit bf408e
	lkcd_print("              fd: %d\n", lkcd->fd);
Packit bf408e
	lkcd_print("              fp: %lx\n", lkcd->fp);
Packit bf408e
	lkcd_print("           debug: %ld\n", lkcd->debug);
Packit bf408e
	lkcd_print("           flags: %lx  (", lkcd->flags);
Packit bf408e
	others = 0;
Packit bf408e
	if (lkcd->flags & LKCD_VALID)
Packit bf408e
		lkcd_print("%sLKCD_VALID", others++ ? "|" : "");
Packit bf408e
	if (lkcd->flags & LKCD_REMOTE)
Packit bf408e
		lkcd_print("%sLKCD_REMOTE", others++ ? "|" : "");
Packit bf408e
	if (lkcd->flags & LKCD_NOHASH)
Packit bf408e
		lkcd_print("%sLKCD_NOHASH", others++ ? "|" : "");
Packit bf408e
        if (lkcd->flags & LKCD_MCLX)
Packit bf408e
                lkcd_print("%sLKCD_MCLX", others++ ? "|" : "");
Packit bf408e
        if (lkcd->flags & LKCD_BAD_DUMP)
Packit bf408e
                lkcd_print("%sLKCD_BAD_DUMP", others++ ? "|" : "");
Packit bf408e
	lkcd_print(")\n");
Packit bf408e
Packit bf408e
dump_header_only:
Packit bf408e
        switch (lkcd->version)
Packit bf408e
        {
Packit bf408e
        case LKCD_DUMP_V1:
Packit bf408e
                dump_lkcd_environment_v1(LKCD_DUMP_HEADER_ONLY);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V2:
Packit bf408e
        case LKCD_DUMP_V3:
Packit bf408e
                dump_lkcd_environment_v2_v3(LKCD_DUMP_HEADER_ONLY);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V5:
Packit bf408e
                dump_lkcd_environment_v5(LKCD_DUMP_HEADER_ONLY);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V7:
Packit bf408e
                dump_lkcd_environment_v7(LKCD_DUMP_HEADER_ONLY);
Packit bf408e
		break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V8:
Packit bf408e
        case LKCD_DUMP_V9:
Packit bf408e
                dump_lkcd_environment_v8(LKCD_DUMP_HEADER_ONLY);
Packit bf408e
		break;
Packit bf408e
        }
Packit bf408e
Packit bf408e
        if (arg == LKCD_DUMP_HEADER_ONLY)
Packit bf408e
                return;
Packit bf408e
Packit bf408e
dump_page_only:
Packit bf408e
        switch (lkcd->version)
Packit bf408e
        {
Packit bf408e
        case LKCD_DUMP_V1:
Packit bf408e
                dump_lkcd_environment_v1(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V2:
Packit bf408e
        case LKCD_DUMP_V3:
Packit bf408e
                dump_lkcd_environment_v2_v3(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V5:
Packit bf408e
                dump_lkcd_environment_v5(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
                break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V7:
Packit bf408e
                dump_lkcd_environment_v7(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
		break;
Packit bf408e
Packit bf408e
        case LKCD_DUMP_V8:
Packit bf408e
                dump_lkcd_environment_v8(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
		break;
Packit bf408e
        }
Packit bf408e
	if (arg == LKCD_DUMP_PAGE_ONLY)
Packit bf408e
		return;
Packit bf408e
Packit bf408e
	lkcd_print("         version: %ld\n", lkcd->version);
Packit bf408e
	lkcd_print("       page_size: %ld\n", lkcd->page_size);
Packit bf408e
	lkcd_print("      page_shift: %d\n", lkcd->page_shift);
Packit bf408e
	lkcd_print("            bits: %d\n", lkcd->bits);
Packit bf408e
	lkcd_print("      panic_task: %lx\n", lkcd->panic_task);
Packit bf408e
	lkcd_print("    panic_string: %s%s", lkcd->panic_string,
Packit bf408e
		lkcd->panic_string && strstr(lkcd->panic_string, "\n") ? 
Packit bf408e
		"" : "\n");
Packit bf408e
Packit bf408e
	lkcd_print("     get_dp_size: ");
Packit bf408e
	if (lkcd->get_dp_size == get_dp_size_v1)
Packit bf408e
		lkcd_print("get_dp_size_v1()\n");
Packit bf408e
	else if (lkcd->get_dp_size == get_dp_size_v2_v3)
Packit bf408e
		lkcd_print("get_dp_size_v2_v3()\n");
Packit bf408e
        else if (lkcd->get_dp_size == get_dp_size_v5)
Packit bf408e
                lkcd_print("get_dp_size_v5()\n");
Packit bf408e
	else
Packit bf408e
		lkcd_print("%lx\n", lkcd->get_dp_size);
Packit bf408e
Packit bf408e
        lkcd_print("    get_dp_flags: ");
Packit bf408e
        if (lkcd->get_dp_flags == get_dp_flags_v1)
Packit bf408e
                lkcd_print("get_dp_flags_v1()\n");
Packit bf408e
        else if (lkcd->get_dp_flags == get_dp_flags_v2_v3)
Packit bf408e
                lkcd_print("get_dp_flags_v2_v3()\n");
Packit bf408e
        else if (lkcd->get_dp_flags == get_dp_flags_v5)
Packit bf408e
                lkcd_print("get_dp_flags_v5()\n");
Packit bf408e
        else
Packit bf408e
                lkcd_print("%lx\n", lkcd->get_dp_flags);
Packit bf408e
Packit bf408e
        lkcd_print("  get_dp_address: ");
Packit bf408e
        if (lkcd->get_dp_address == get_dp_address_v1)
Packit bf408e
                lkcd_print("get_dp_address_v1()\n");
Packit bf408e
        else if (lkcd->get_dp_address == get_dp_address_v2_v3)
Packit bf408e
                lkcd_print("get_dp_address_v2_v3()\n");
Packit bf408e
        else if (lkcd->get_dp_address == get_dp_address_v5)
Packit bf408e
                lkcd_print("get_dp_address_v5()\n");
Packit bf408e
        else
Packit bf408e
                lkcd_print("%lx\n", lkcd->get_dp_address);
Packit bf408e
Packit bf408e
	lkcd_print("     compression: ");
Packit bf408e
	lkcd_print(BITS32() ? "%lx  " : "%x  ", lkcd->compression);
Packit bf408e
	switch (lkcd->compression)
Packit bf408e
	{
Packit bf408e
	case LKCD_DUMP_COMPRESS_NONE:
Packit bf408e
		lkcd_print("(LKCD_DUMP_COMPRESS_NONE)\n");
Packit bf408e
		break;
Packit bf408e
	case LKCD_DUMP_COMPRESS_RLE:
Packit bf408e
		lkcd_print("(LKCD_DUMP_COMPRESS_RLE)\n");
Packit bf408e
		break;
Packit bf408e
	case LKCD_DUMP_COMPRESS_GZIP:
Packit bf408e
		lkcd_print("(LKCD_DUMP_COMPRESS_GZIP)\n");
Packit bf408e
		break;
Packit bf408e
	default:
Packit bf408e
		lkcd_print("(unknown)\n");
Packit bf408e
		break;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	lkcd_print("page_header_size: %ld\n", lkcd->page_header_size);
Packit bf408e
	lkcd_print("          curpos: %ld\n", lkcd->curpos);
Packit bf408e
	lkcd_print("        curpaddr: ");
Packit bf408e
	lkcd_print(BITS32() ? "%llx\n" : "%lx\n", lkcd->curpaddr);
Packit bf408e
	lkcd_print("       curbufptr: %lx\n", lkcd->curbufptr);
Packit bf408e
	lkcd_print("      curhdroffs: %ld\n", lkcd->curhdroffs);
Packit bf408e
	lkcd_print("          kvbase: ");
Packit bf408e
	lkcd_print(BITS32() ? "%llx\n" : "%lx\n", lkcd->kvbase);
Packit bf408e
	lkcd_print("  page_cache_buf: %lx\n", lkcd->page_cache_buf);
Packit bf408e
	lkcd_print(" compressed_page: %lx\n", lkcd->compressed_page);
Packit bf408e
	lkcd_print("     evict_index: %d\n", lkcd->evict_index);
Packit bf408e
	lkcd_print("       evictions: %ld\n", lkcd->evictions);
Packit bf408e
	lkcd_print(" benchmark_pages: %ld\n", lkcd->benchmark_pages);
Packit bf408e
	lkcd_print(" benchmarks_done: %ld\n", lkcd->benchmarks_done);
Packit bf408e
Packit bf408e
	lkcd_memory_dump(lkcd->fp);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Set the shadow debug flag.
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
set_lkcd_debug(ulong debug)
Packit bf408e
{
Packit bf408e
	lkcd->debug = debug;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Set no-hash flag bit.
Packit bf408e
 */
Packit bf408e
void 
Packit bf408e
set_lkcd_nohash(void)
Packit bf408e
{
Packit bf408e
	lkcd->flags |= LKCD_NOHASH; 
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Set the file pointer for debug output.
Packit bf408e
 */
Packit bf408e
FILE *
Packit bf408e
set_lkcd_fp(FILE *fp)
Packit bf408e
{
Packit bf408e
	lkcd->fp = fp;
Packit bf408e
	return fp;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Return the number of pages cached.
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
lkcd_memory_used(void)
Packit bf408e
{
Packit bf408e
	int i, pages;
Packit bf408e
        struct page_cache_hdr *sp;
Packit bf408e
Packit bf408e
        sp = &lkcd->page_cache_hdr[0];
Packit bf408e
        for (i = pages = 0; i < LKCD_CACHED_PAGES; i++, sp++) { 
Packit bf408e
		if (LKCD_VALID_PAGE(sp->pg_flags))
Packit bf408e
			pages++;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return pages;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Since the dumpfile pages are temporary tenants of a fixed page cache,
Packit bf408e
 *  this command doesn't do anything except clear the references. 
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
lkcd_free_memory(void)
Packit bf408e
{
Packit bf408e
        int i, pages;
Packit bf408e
        struct page_cache_hdr *sp;
Packit bf408e
Packit bf408e
        sp = &lkcd->page_cache_hdr[0];
Packit bf408e
        for (i = pages = 0; i < LKCD_CACHED_PAGES; i++, sp++) {
Packit bf408e
                if (LKCD_VALID_PAGE(sp->pg_flags)) {
Packit bf408e
			sp->pg_addr = 0;
Packit bf408e
			sp->pg_hit_count = 0;
Packit bf408e
                        pages++;
Packit bf408e
		}
Packit bf408e
		sp->pg_flags = 0;
Packit bf408e
        }
Packit bf408e
Packit bf408e
        return pages;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Dump the page cache;
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
lkcd_memory_dump(FILE *fp)
Packit bf408e
{
Packit bf408e
        int i, c, pages;
Packit bf408e
        struct page_cache_hdr *sp;
Packit bf408e
        struct page_hash_entry *phe;
Packit bf408e
	ulong pct_cached, pct_hashed;
Packit bf408e
	ulong pct_compressed, pct_raw;
Packit bf408e
	FILE *fpsave;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	int wrap;
Packit bf408e
Packit bf408e
	fpsave = lkcd->fp;
Packit bf408e
	lkcd->fp = fp;
Packit bf408e
Packit bf408e
        lkcd_print("     total_pages: %ld\n", lkcd->total_pages);
Packit bf408e
        pct_compressed = (lkcd->compressed*100) /
Packit bf408e
                (lkcd->hashed ? lkcd->hashed : 1);
Packit bf408e
        pct_raw = (lkcd->raw*100) /
Packit bf408e
                (lkcd->hashed ? lkcd->hashed : 1);
Packit bf408e
        lkcd_print("          hashed: %ld\n", lkcd->hashed);
Packit bf408e
        lkcd_print("      compressed: %ld (%ld%%)\n", 
Packit bf408e
		lkcd->compressed, pct_compressed);
Packit bf408e
        lkcd_print("             raw: %ld (%ld%%)\n", 
Packit bf408e
		lkcd->raw, pct_raw);
Packit bf408e
        pct_cached = (lkcd->cached_reads*100) /  
Packit bf408e
                (lkcd->total_reads ? lkcd->total_reads : 1);
Packit bf408e
        pct_hashed = (lkcd->hashed_reads*100) /
Packit bf408e
                (lkcd->total_reads ? lkcd->total_reads : 1); 
Packit bf408e
        lkcd_print("    cached_reads: %ld (%ld%%)\n", lkcd->cached_reads,
Packit bf408e
                pct_cached);
Packit bf408e
        lkcd_print("    hashed_reads: %ld (%ld%%)\n", lkcd->hashed_reads,
Packit bf408e
                pct_hashed);
Packit bf408e
        lkcd_print("     total_reads: %ld (hashed or cached: %ld%%) \n",
Packit bf408e
            lkcd->total_reads, pct_cached+pct_hashed);
Packit bf408e
Packit bf408e
        lkcd_print("page_hash[%2d]:\n", LKCD_PAGE_HASH);
Packit bf408e
Packit bf408e
	if (LKCD_DEBUG(1)) {
Packit bf408e
	        for (i = 0; i < LKCD_PAGE_HASH; i++) {
Packit bf408e
	                phe = &lkcd->page_hash[i];
Packit bf408e
	                if (!LKCD_VALID_PAGE(phe->pg_flags))
Packit bf408e
	                        continue;
Packit bf408e
	                lkcd_print("  [%2d]: ", i);
Packit bf408e
	                wrap = 0;
Packit bf408e
	                while (phe && LKCD_VALID_PAGE(phe->pg_flags)) {
Packit bf408e
				sprintf(buf, "%llx@", 
Packit bf408e
					(ulonglong)phe->pg_addr);
Packit bf408e
				sprintf(&buf[strlen(buf)],
Packit bf408e
	                        	"%llx,", (ulonglong)phe->pg_hdr_offset);
Packit bf408e
				lkcd_print("%18s", buf);
Packit bf408e
Packit bf408e
	                        phe = phe->next;
Packit bf408e
	                        if (phe && (++wrap == 3)) {
Packit bf408e
	                                lkcd_print("\n        ");
Packit bf408e
	                                wrap = 0;
Packit bf408e
	                        }
Packit bf408e
	                }
Packit bf408e
	                lkcd_print("\n");
Packit bf408e
	        }
Packit bf408e
	} else {
Packit bf408e
	        for (i = 0; i < LKCD_PAGE_HASH; i++) {
Packit bf408e
	                phe = &lkcd->page_hash[i];
Packit bf408e
	                if (!LKCD_VALID_PAGE(phe->pg_flags))
Packit bf408e
	                        continue;
Packit bf408e
	                lkcd_print("  [%2d]: ", i);
Packit bf408e
	                wrap = 0;
Packit bf408e
	                while (phe && LKCD_VALID_PAGE(phe->pg_flags)) {
Packit bf408e
				lkcd_print(BITS32() ? "%9llx," : "%9lx,",
Packit bf408e
					phe->pg_addr);
Packit bf408e
	                        phe = phe->next;
Packit bf408e
	                        if (phe && (++wrap == 7)) {
Packit bf408e
	                                lkcd_print("\n        ");
Packit bf408e
	                                wrap = 0;
Packit bf408e
	                        }
Packit bf408e
	                }
Packit bf408e
	                lkcd_print("\n");
Packit bf408e
	        }
Packit bf408e
	}
Packit bf408e
Packit bf408e
        lkcd_print("page_cache_hdr[%2d]:\n", LKCD_CACHED_PAGES);
Packit bf408e
	lkcd_print(" INDEX   PG_ADDR  PG_BUFPTR");
Packit bf408e
        lkcd_print(BITS32() ? " PG_HIT_COUNT\n" : "        PG_HIT_COUNT\n");
Packit bf408e
Packit bf408e
        sp = &lkcd->page_cache_hdr[0];
Packit bf408e
        for (i = pages = 0; i < LKCD_CACHED_PAGES; i++, sp++) {
Packit bf408e
                if (LKCD_VALID_PAGE(sp->pg_flags))
Packit bf408e
                        pages++;
Packit bf408e
		if (BITS32())
Packit bf408e
                	lkcd_print("  [%2d] %9llx  %lx        %ld\n",
Packit bf408e
			    i, sp->pg_addr, sp->pg_bufptr, sp->pg_hit_count);
Packit bf408e
		else
Packit bf408e
                	lkcd_print("  [%2d] %9lx  %lx  %ld\n",
Packit bf408e
			    i, sp->pg_addr, sp->pg_bufptr, sp->pg_hit_count);
Packit bf408e
        }
Packit bf408e
Packit bf408e
	if (lkcd->mb_hdr_offsets) {
Packit bf408e
		lkcd_print("mb_hdr_offsets[%3ld]: \n", lkcd->benchmark_pages);
Packit bf408e
Packit bf408e
		for (i = 0; i < lkcd->benchmark_pages; i += 8) {
Packit bf408e
			lkcd_print("  [%3d]", i);
Packit bf408e
			c = 0;
Packit bf408e
			while ((c < 8) && ((i+c) < lkcd->benchmark_pages)) {
Packit bf408e
				lkcd_print(" %8lx", lkcd->mb_hdr_offsets[i+c]);
Packit bf408e
				c++;
Packit bf408e
			}
Packit bf408e
			lkcd_print("\n");
Packit bf408e
		}
Packit bf408e
	} else {
Packit bf408e
		lkcd_print("  mb_hdr_offsets: NA\n");
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (lkcd->zones) {
Packit bf408e
		lkcd_print("       num_zones: %d / %d\n", lkcd->num_zones,
Packit bf408e
				lkcd->max_zones);
Packit bf408e
		lkcd_print("   zoned_offsets: %ld\n", lkcd->zoned_offsets);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	lkcd_print("  dumpfile_index: %s\n", lkcd->dumpfile_index);
Packit bf408e
	lkcd_print("             ifd: %d\n", lkcd->ifd);
Packit bf408e
        lkcd_print("    memory_pages: %ld\n", lkcd->memory_pages);
Packit bf408e
        lkcd_print(" page_offset_max: %ld\n", lkcd->page_offset_max);
Packit bf408e
        lkcd_print("  page_index_max: %ld\n", lkcd->page_index_max);
Packit bf408e
        lkcd_print("    page_offsets: %lx\n", lkcd->page_offsets);
Packit bf408e
Packit bf408e
	lkcd->fp = fpsave;
Packit bf408e
Packit bf408e
        return pages;
Packit bf408e
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  The lkcd_lseek() routine does the bulk of the work setting things up 
Packit bf408e
 *  so that the subsequent lkcd_read() simply has to do a bcopy().
Packit bf408e
Packit bf408e
 *  Given a physical address, first determine:
Packit bf408e
 *
Packit bf408e
 *   (1) its page offset (lkcd->curpos).
Packit bf408e
 *   (2) its page address as specified in the dumpfile (lkcd->curpaddr).
Packit bf408e
 *
Packit bf408e
 *  If the page data is already cached, everything will be set up for the
Packit bf408e
 *  subsequent read when page_is_cached() returns.
Packit bf408e
 *
Packit bf408e
 *  If the page data is not cached, either of the following occurs:
Packit bf408e
 *
Packit bf408e
 *   (1) page_is_hashed() will check whether the page header offset is cached,
Packit bf408e
 *       and if so, will set up the page variable, and lseek to the header.
Packit bf408e
 *
Packit bf408e
 *  In either case above, the starting point for the page search is set up.
Packit bf408e
 *  Lastly, cache_page() stores the requested page's data.
Packit bf408e
 */
Packit bf408e
Packit bf408e
static int
Packit bf408e
save_offset(uint64_t paddr, off_t off)
Packit bf408e
{
Packit bf408e
	uint64_t zone, page;
Packit bf408e
	int ii, ret;
Packit bf408e
	int max_zones;
Packit bf408e
	struct physmem_zone *zones;
Packit bf408e
Packit bf408e
	ret = -1;
Packit bf408e
	zone = paddr & lkcd->zone_mask;
Packit bf408e
Packit bf408e
	page = (paddr & ~lkcd->zone_mask) >> lkcd->page_shift;
Packit bf408e
Packit bf408e
	if (lkcd->num_zones == 0) {
Packit bf408e
		lkcd->zones = malloc(ZONE_ALLOC * sizeof(struct physmem_zone));
Packit bf408e
		if (!lkcd->zones) {
Packit bf408e
			return -1; /* This should be fatal */
Packit bf408e
		}
Packit bf408e
		BZERO(lkcd->zones, ZONE_ALLOC * sizeof(struct physmem_zone));
Packit bf408e
Packit bf408e
		lkcd->max_zones = ZONE_ALLOC;
Packit bf408e
Packit bf408e
		lkcd->zones[0].start = zone;
Packit bf408e
		lkcd->zones[0].pages = malloc((ZONE_SIZE >> lkcd->page_shift) *
Packit bf408e
					sizeof(struct page_desc));
Packit bf408e
		if (!lkcd->zones[0].pages) {
Packit bf408e
			return -1; /* this should be fatal */
Packit bf408e
		}
Packit bf408e
Packit bf408e
		BZERO(lkcd->zones[0].pages, (ZONE_SIZE >> lkcd->page_shift) *
Packit bf408e
					sizeof(struct page_desc));
Packit bf408e
		lkcd->num_zones++;
Packit bf408e
	}
Packit bf408e
Packit bf408e
retry:
Packit bf408e
	/* find the zone */
Packit bf408e
	for (ii=0; ii < lkcd->num_zones; ii++) {
Packit bf408e
		if (lkcd->zones[ii].start == zone) {
Packit bf408e
			if (lkcd->zones[ii].pages[page].offset != 0) {
Packit bf408e
			   if (lkcd->zones[ii].pages[page].offset != off) {
Packit bf408e
				if (CRASHDEBUG(1) && !STREQ(pc->curcmd, "search"))
Packit bf408e
				    error(INFO, "LKCD: conflicting page: zone %lld, "
Packit bf408e
					"page %lld: %lld, %lld != %lld\n",
Packit bf408e
					(unsigned long long)zone, 
Packit bf408e
					(unsigned long long)page, 
Packit bf408e
					(unsigned long long)paddr, 
Packit bf408e
					(unsigned long long)off,
Packit bf408e
					(unsigned long long)lkcd->zones[ii].pages[page].offset);
Packit bf408e
				return -1;
Packit bf408e
			   }
Packit bf408e
			   ret = 0;
Packit bf408e
			} else {
Packit bf408e
			   lkcd->zones[ii].pages[page].offset = off;
Packit bf408e
			   ret = 1;
Packit bf408e
			}
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
	if (ii == lkcd->num_zones) {
Packit bf408e
		/* This is a new zone */
Packit bf408e
		if (lkcd->num_zones < lkcd->max_zones) {
Packit bf408e
			/* We have room for another one */
Packit bf408e
			lkcd->zones[ii].start = zone;
Packit bf408e
			lkcd->zones[ii].pages = malloc(
Packit bf408e
					(ZONE_SIZE >> lkcd->page_shift) *
Packit bf408e
					sizeof(struct page_desc));
Packit bf408e
			if (!lkcd->zones[ii].pages) {
Packit bf408e
				return -1; /* this should be fatal */
Packit bf408e
			}
Packit bf408e
Packit bf408e
			BZERO(lkcd->zones[ii].pages, 
Packit bf408e
					(ZONE_SIZE >> lkcd->page_shift) *
Packit bf408e
					sizeof(struct page_desc));
Packit bf408e
			lkcd->zones[ii].pages[page].offset = off;
Packit bf408e
			ret = 1;
Packit bf408e
			lkcd->num_zones++;
Packit bf408e
		} else {
Packit bf408e
			/* need to expand zone */
Packit bf408e
			max_zones = lkcd->max_zones * 2;
Packit bf408e
			zones = malloc(max_zones * sizeof(struct physmem_zone));
Packit bf408e
			if (!zones) {
Packit bf408e
				return -1; /* This should be fatal */
Packit bf408e
			}
Packit bf408e
			BZERO(zones, max_zones * sizeof(struct physmem_zone));
Packit bf408e
			memcpy(zones, lkcd->zones,
Packit bf408e
				lkcd->max_zones * sizeof(struct physmem_zone));
Packit bf408e
			free(lkcd->zones);
Packit bf408e
Packit bf408e
			lkcd->zones = zones;
Packit bf408e
			lkcd->max_zones = max_zones;
Packit bf408e
			goto retry;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return ret;  /* 1 if the page is new */
Packit bf408e
}
Packit bf408e
		
Packit bf408e
static off_t
Packit bf408e
get_offset(uint64_t paddr)
Packit bf408e
{
Packit bf408e
	uint64_t zone, page;
Packit bf408e
	int ii;
Packit bf408e
Packit bf408e
	zone = paddr & lkcd->zone_mask;
Packit bf408e
	page = (paddr % ZONE_SIZE) >> lkcd->page_shift;
Packit bf408e
Packit bf408e
	if (lkcd->zones == 0) {
Packit bf408e
		return 0;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	/* find the zone */
Packit bf408e
	for (ii=0; ii < lkcd->num_zones; ii++) {
Packit bf408e
		if (lkcd->zones[ii].start == zone) {
Packit bf408e
			return (lkcd->zones[ii].pages[page].offset);
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
	return 0;
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
#ifdef IA64
Packit bf408e
Packit bf408e
int
Packit bf408e
lkcd_get_kernel_start(ulong *addr)
Packit bf408e
{
Packit bf408e
	if (!addr)
Packit bf408e
		return 0;
Packit bf408e
Packit bf408e
	switch (lkcd->version)
Packit bf408e
	{
Packit bf408e
        case LKCD_DUMP_V8:
Packit bf408e
        case LKCD_DUMP_V9:
Packit bf408e
		return lkcd_get_kernel_start_v8(addr);
Packit bf408e
Packit bf408e
	default:
Packit bf408e
		return 0;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
#endif
Packit bf408e
Packit bf408e
Packit bf408e
int
Packit bf408e
lkcd_lseek(physaddr_t paddr)
Packit bf408e
{
Packit bf408e
	int err;
Packit bf408e
        int eof;
Packit bf408e
        void *dp;
Packit bf408e
        long page = 0;
Packit bf408e
	physaddr_t physaddr;
Packit bf408e
	int seeked_to_page = 0;
Packit bf408e
	off_t page_offset;
Packit bf408e
Packit bf408e
	dp = lkcd->dump_page;
Packit bf408e
Packit bf408e
	lkcd->curpos = paddr & ((physaddr_t)(lkcd->page_size-1));
Packit bf408e
        lkcd->curpaddr = paddr & ~((physaddr_t)(lkcd->page_size-1));
Packit bf408e
Packit bf408e
	if (page_is_cached()) 
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	/* Faster than paging in lkcd->page_offsets[page] */
Packit bf408e
	if(page_is_hashed(&page)) {
Packit bf408e
		seeked_to_page = 1;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	 /* Find the offset for this page, if known */
Packit bf408e
    if ((page_offset = get_offset(paddr)) > 0) {
Packit bf408e
	off_t seek_offset;
Packit bf408e
	seek_offset = lseek(lkcd->fd, page_offset, SEEK_SET);
Packit bf408e
Packit bf408e
	if (seek_offset == page_offset) {
Packit bf408e
	    seeked_to_page = 1;
Packit bf408e
	    page = 0; /* page doesn't make any sense */
Packit bf408e
	}
Packit bf408e
    }
Packit bf408e
Packit bf408e
Packit bf408e
    if (seeked_to_page) {
Packit bf408e
	err = lkcd_load_dump_page_header(dp, page);
Packit bf408e
	if (err == LKCD_DUMPFILE_OK) {
Packit bf408e
	    return(cache_page());
Packit bf408e
	}
Packit bf408e
    }	
Packit bf408e
Packit bf408e
    /* We have to grind through some more of the dump file */
Packit bf408e
    lseek(lkcd->fd, lkcd->page_offset_max, SEEK_SET);
Packit bf408e
    eof = FALSE;
Packit bf408e
    while (!eof) {
Packit bf408e
	switch (lkcd_load_dump_page_header(dp, page))
Packit bf408e
	{
Packit bf408e
	    case LKCD_DUMPFILE_OK:
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	    case LKCD_DUMPFILE_EOF:
Packit bf408e
		eof = TRUE;
Packit bf408e
		continue;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	physaddr = lkcd->get_dp_flags() & 
Packit bf408e
	    (LKCD_DUMP_MCLX_V0|LKCD_DUMP_MCLX_V1) ?
Packit bf408e
	    (lkcd->get_dp_address() - lkcd->kvbase) << lkcd->page_shift:
Packit bf408e
	    lkcd->get_dp_address() - lkcd->kvbase;
Packit bf408e
Packit bf408e
	if (physaddr == lkcd->curpaddr) {
Packit bf408e
	    return(cache_page());
Packit bf408e
	}
Packit bf408e
	lseek(lkcd->fd, lkcd->get_dp_size(), SEEK_CUR);
Packit bf408e
    }
Packit bf408e
Packit bf408e
	return FALSE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Everything's been set up by the previous lkcd_lseek(), so all that has
Packit bf408e
 *  to be done is to read the uncompressed data into the user buffer:
Packit bf408e
 *
Packit bf408e
 *    lkcd->curbufptr points to the uncompressed page base.
Packit bf408e
 *    lkcd->curpos is the offset into the buffer.
Packit bf408e
 */
Packit bf408e
long 
Packit bf408e
lkcd_read(void *buf, long count)
Packit bf408e
{
Packit bf408e
	char *p;
Packit bf408e
Packit bf408e
	lkcd->total_reads++;
Packit bf408e
Packit bf408e
	p = lkcd->curbufptr + lkcd->curpos;
Packit bf408e
	
Packit bf408e
	BCOPY(p, buf, count);
Packit bf408e
	return count;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Check whether lkcd->curpaddr is already cached.  If it is, update
Packit bf408e
 *  lkcd->curbufptr to point to the page's uncompressed data.  
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
page_is_cached(void)
Packit bf408e
{
Packit bf408e
	int i;
Packit bf408e
Packit bf408e
	for (i = 0; i < LKCD_CACHED_PAGES; i++) {
Packit bf408e
Packit bf408e
		if (!LKCD_VALID_PAGE(lkcd->page_cache_hdr[i].pg_flags))
Packit bf408e
			continue;
Packit bf408e
Packit bf408e
		if (lkcd->page_cache_hdr[i].pg_addr == lkcd->curpaddr) {
Packit bf408e
			lkcd->page_cache_hdr[i].pg_hit_count++;
Packit bf408e
			lkcd->curbufptr = lkcd->page_cache_hdr[i].pg_bufptr;
Packit bf408e
			lkcd->cached_reads++;
Packit bf408e
			return TRUE;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return FALSE;
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  For an incoming page:
Packit bf408e
 *  
Packit bf408e
 *   (1) If it's already hashed just return TRUE.
Packit bf408e
 *   (2) If the base page_hash_entry is unused, fill it up and return TRUE;
Packit bf408e
 *   (3) Otherwise, find the last page_hash_entry on the list, allocate and
Packit bf408e
 *       fill a new one, link it on the list, and return TRUE.
Packit bf408e
 *   (4) If the malloc fails, quietly return FALSE (with no harm done).
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
hash_page(ulong type)
Packit bf408e
{
Packit bf408e
	struct page_hash_entry *phe;
Packit bf408e
	int index;
Packit bf408e
Packit bf408e
        if (lkcd->flags & LKCD_NOHASH) {
Packit bf408e
                lkcd->flags &= ~LKCD_NOHASH;
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	index = LKCD_PAGE_HASH_INDEX(lkcd->curpaddr);
Packit bf408e
Packit bf408e
	for (phe = &lkcd->page_hash[index]; LKCD_VALID_PAGE(phe->pg_flags); 
Packit bf408e
	     phe = phe->next) {
Packit bf408e
		if (phe->pg_addr == lkcd->curpaddr)
Packit bf408e
			return TRUE;
Packit bf408e
		if (!phe->next)
Packit bf408e
			break;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (LKCD_VALID_PAGE(phe->pg_flags)) {
Packit bf408e
		if ((phe->next = malloc
Packit bf408e
		    (sizeof(struct page_hash_entry))) == NULL)
Packit bf408e
			return FALSE;
Packit bf408e
		phe = phe->next;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	phe->pg_flags |= LKCD_VALID;
Packit bf408e
	phe->pg_addr = lkcd->curpaddr;
Packit bf408e
	phe->pg_hdr_offset = lkcd->curhdroffs;
Packit bf408e
	phe->next = NULL;
Packit bf408e
Packit bf408e
	lkcd->hashed++;
Packit bf408e
	switch (type)
Packit bf408e
	{
Packit bf408e
	case LKCD_DUMP_COMPRESSED:
Packit bf408e
		lkcd->compressed++;
Packit bf408e
		break;
Packit bf408e
	case LKCD_DUMP_RAW:
Packit bf408e
		lkcd->raw++;
Packit bf408e
		break;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Check whether a page is currently hashed, and if so, return the page
Packit bf408e
 *  number so that the subsequent search loop will find it immediately.
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
page_is_hashed(long *pp)
Packit bf408e
{
Packit bf408e
	struct page_hash_entry *phe;
Packit bf408e
	int index;
Packit bf408e
Packit bf408e
	index = LKCD_PAGE_HASH_INDEX(lkcd->curpaddr);
Packit bf408e
Packit bf408e
	for (phe = &lkcd->page_hash[index]; LKCD_VALID_PAGE(phe->pg_flags); 
Packit bf408e
	     phe = phe->next) {
Packit bf408e
		if (phe->pg_addr == lkcd->curpaddr) {
Packit bf408e
			*pp = (long)(lkcd->curpaddr >> lkcd->page_shift);
Packit bf408e
			lseek(lkcd->fd, phe->pg_hdr_offset, SEEK_SET);
Packit bf408e
			lkcd->hashed_reads++;
Packit bf408e
			return TRUE;
Packit bf408e
		}
Packit bf408e
		if (!phe->next)
Packit bf408e
			break;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return FALSE;
Packit bf408e
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  The caller stores the incoming page's page header offset in 
Packit bf408e
 *  lkcd->curhdroffs.
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
set_mb_benchmark(ulong page)
Packit bf408e
{
Packit bf408e
	long mb;
Packit bf408e
Packit bf408e
	if ((mb = LKCD_PAGE_MEGABYTE(page)) >= lkcd->benchmark_pages)
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
        if (!lkcd->mb_hdr_offsets[mb]) {
Packit bf408e
        	lkcd->mb_hdr_offsets[mb] = lkcd->curhdroffs;
Packit bf408e
		lkcd->benchmarks_done++;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
	
Packit bf408e
/*
Packit bf408e
 *  Coming into this routine:
Packit bf408e
 *
Packit bf408e
 *   (1) lkcd->curpaddr points to the page address as specified in the dumpfile.
Packit bf408e
 *   (2) the dump_page header has been copied into lkcd->dump_page.
Packit bf408e
 *   (3) the file pointer is sitting at the beginning of the page data,
Packit bf408e
 *       be it compressed or otherwise.
Packit bf408e
 *   (4) lkcd->curhdroffs contains the file pointer to the incoming page's
Packit bf408e
 *       header offset.
Packit bf408e
 *
Packit bf408e
 *  If an empty page cache location is available, take it.  Otherwise, evict
Packit bf408e
 *  the entry indexed by evict_index, and then bump evict index.  The hit_count
Packit bf408e
 *  is only gathered for dump_lkcd_environment().
Packit bf408e
 *
Packit bf408e
 *  If the page is compressed, uncompress it into the selected page cache entry.
Packit bf408e
 *  If the page is raw, just copy it into the selected page cache entry.
Packit bf408e
 *  If all works OK, update lkcd->curbufptr to point to the page's uncompressed
Packit bf408e
 *  data.
Packit bf408e
 *
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
cache_page(void)
Packit bf408e
{
Packit bf408e
	int i;
Packit bf408e
	ulong type;
Packit bf408e
	int found, newsz;
Packit bf408e
	uint32_t rawsz;
Packit bf408e
	ssize_t bytes ATTRIBUTE_UNUSED;
Packit bf408e
Packit bf408e
Packit bf408e
        for (i = found = 0; i < LKCD_CACHED_PAGES; i++) {
Packit bf408e
                if (LKCD_VALID_PAGE(lkcd->page_cache_hdr[i].pg_flags))
Packit bf408e
                        continue;
Packit bf408e
		found = TRUE;
Packit bf408e
		break;
Packit bf408e
        }
Packit bf408e
Packit bf408e
	if (!found) {
Packit bf408e
                i = lkcd->evict_index;
Packit bf408e
		lkcd->page_cache_hdr[i].pg_hit_count = 0;
Packit bf408e
                lkcd->evict_index = (lkcd->evict_index+1) % LKCD_CACHED_PAGES;
Packit bf408e
                lkcd->evictions++;
Packit bf408e
	}
Packit bf408e
Packit bf408e
        lkcd->page_cache_hdr[i].pg_flags = 0;
Packit bf408e
        lkcd->page_cache_hdr[i].pg_addr = lkcd->curpaddr;
Packit bf408e
	lkcd->page_cache_hdr[i].pg_hit_count++;
Packit bf408e
Packit bf408e
	type = lkcd->get_dp_flags() & (LKCD_DUMP_COMPRESSED|LKCD_DUMP_RAW);
Packit bf408e
Packit bf408e
	switch (type)
Packit bf408e
	{
Packit bf408e
	case LKCD_DUMP_COMPRESSED:
Packit bf408e
		if (LKCD_DEBUG(2)) 
Packit bf408e
			dump_dump_page("cmp: ", lkcd->dump_page);
Packit bf408e
		
Packit bf408e
		newsz = 0;
Packit bf408e
		BZERO(lkcd->compressed_page, lkcd->page_size);
Packit bf408e
                bytes = read(lkcd->fd, lkcd->compressed_page, lkcd->get_dp_size());
Packit bf408e
Packit bf408e
		switch (lkcd->compression)
Packit bf408e
		{
Packit bf408e
		case LKCD_DUMP_COMPRESS_NONE:
Packit bf408e
			lkcd_print("dump_header: DUMP_COMPRESS_NONE and "
Packit bf408e
			          "dump_page: DUMP_COMPRESSED (?)\n");
Packit bf408e
			return FALSE;
Packit bf408e
Packit bf408e
		case LKCD_DUMP_COMPRESS_RLE:
Packit bf408e
			if (!lkcd_uncompress_RLE((unsigned char *)
Packit bf408e
			    lkcd->compressed_page,
Packit bf408e
			    (unsigned char *)lkcd->page_cache_hdr[i].pg_bufptr, 	
Packit bf408e
			    lkcd->get_dp_size(), &newsz) || 
Packit bf408e
			    (newsz != lkcd->page_size)) {
Packit bf408e
				lkcd_print("uncompress of page ");
Packit bf408e
				lkcd_print(BITS32() ? 
Packit bf408e
					"%llx failed!\n" : "%lx failed!\n",
Packit bf408e
					lkcd->get_dp_address());
Packit bf408e
				lkcd_print("newsz returned: %d\n", newsz);
Packit bf408e
				return FALSE;
Packit bf408e
			}
Packit bf408e
			break;
Packit bf408e
Packit bf408e
		case LKCD_DUMP_COMPRESS_GZIP:
Packit bf408e
			if (!lkcd_uncompress_gzip((unsigned char *)
Packit bf408e
			    lkcd->page_cache_hdr[i].pg_bufptr, lkcd->page_size,
Packit bf408e
			    (unsigned char *)lkcd->compressed_page, 
Packit bf408e
			    lkcd->get_dp_size())) {
Packit bf408e
                                lkcd_print("uncompress of page ");
Packit bf408e
                                lkcd_print(BITS32() ? 
Packit bf408e
                                        "%llx failed!\n" : "%lx failed!\n",
Packit bf408e
                                        lkcd->get_dp_address());
Packit bf408e
				return FALSE;
Packit bf408e
			}
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case LKCD_DUMP_RAW:
Packit bf408e
		if (LKCD_DEBUG(2)) 
Packit bf408e
			dump_dump_page("raw: ", lkcd->dump_page);
Packit bf408e
		if ((rawsz = lkcd->get_dp_size()) == 0)
Packit bf408e
			BZERO(lkcd->page_cache_hdr[i].pg_bufptr, 
Packit bf408e
				lkcd->page_size);
Packit bf408e
		else if (rawsz == lkcd->page_size)
Packit bf408e
			bytes = read(lkcd->fd, lkcd->page_cache_hdr[i].pg_bufptr, 
Packit bf408e
				lkcd->page_size);
Packit bf408e
		else {
Packit bf408e
			lkcd_print("cache_page: "
Packit bf408e
		        	"invalid LKCD_DUMP_RAW dp_size\n");
Packit bf408e
			dump_lkcd_environment(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
			return FALSE;
Packit bf408e
		}
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	default:
Packit bf408e
		lkcd_print("cache_page: bogus page:\n");
Packit bf408e
		dump_lkcd_environment(LKCD_DUMP_PAGE_ONLY);
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
        lkcd->page_cache_hdr[i].pg_flags |= LKCD_VALID;
Packit bf408e
	lkcd->curbufptr = lkcd->page_cache_hdr[i].pg_bufptr;
Packit bf408e
Packit bf408e
	hash_page(type);
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Uncompress an RLE-encoded buffer.
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
lkcd_uncompress_RLE(unsigned char *cbuf, unsigned char *ucbuf, 
Packit bf408e
	       uint32_t blk_size, int *new_size)
Packit bf408e
{
Packit bf408e
        int i;
Packit bf408e
        unsigned char value, count, cur_byte;
Packit bf408e
        uint32_t ri, wi;
Packit bf408e
Packit bf408e
        /* initialize the read / write indices */
Packit bf408e
        ri = wi = 0;
Packit bf408e
Packit bf408e
        /* otherwise decompress using run length encoding */
Packit bf408e
        while(ri < blk_size) {
Packit bf408e
                cur_byte = cbuf[ri++];
Packit bf408e
                if (cur_byte == 0) {
Packit bf408e
                        count = cbuf[ri++];
Packit bf408e
                        if (count == 0) {
Packit bf408e
                                ucbuf[wi++] = 0;
Packit bf408e
                        } else {
Packit bf408e
                                value = cbuf[ri++];
Packit bf408e
                                for (i = 0; i <= count; i++) {
Packit bf408e
                                        ucbuf[wi++] = value;
Packit bf408e
                                }
Packit bf408e
                        }
Packit bf408e
                } else {
Packit bf408e
                        ucbuf[wi++] = cur_byte;
Packit bf408e
                }
Packit bf408e
Packit bf408e
                /* if our write index is beyond the page size, exit out */
Packit bf408e
                if (wi > /* PAGE_SIZE */ lkcd->page_size) {
Packit bf408e
			lkcd_print( 
Packit bf408e
           "Attempted to decompress beyond page boundaries: file corrupted!\n");
Packit bf408e
                        return (0);
Packit bf408e
                }
Packit bf408e
        }
Packit bf408e
Packit bf408e
        /* set return size to be equal to uncompressed size (in bytes) */
Packit bf408e
        *new_size = wi;
Packit bf408e
Packit bf408e
        return 1;
Packit bf408e
}
Packit bf408e
Packit bf408e
/* Returns the bit offset if it's able to correct, or negative if not */
Packit bf408e
static int
Packit bf408e
uncompress_recover(unsigned char *dest, ulong destlen,
Packit bf408e
    unsigned char *source, ulong sourcelen)
Packit bf408e
{
Packit bf408e
        int byte, bit;
Packit bf408e
        ulong retlen = destlen;
Packit bf408e
        int good_decomp = 0, good_rv = -1;
Packit bf408e
Packit bf408e
        /* Generate all single bit errors */
Packit bf408e
        if (sourcelen > 16384) {
Packit bf408e
                lkcd_print("uncompress_recover: sourcelen %ld too long\n",
Packit bf408e
                    sourcelen);
Packit bf408e
                return(-1);
Packit bf408e
        }
Packit bf408e
        for (byte = 0; byte < sourcelen; byte++) {
Packit bf408e
                for (bit = 0; bit < 8; bit++) {
Packit bf408e
                        source[byte] ^= (1 << bit);
Packit bf408e
Packit bf408e
                        if (uncompress(dest, &retlen, source, sourcelen) == Z_OK &&
Packit bf408e
                            retlen == destlen) {
Packit bf408e
                                good_decomp++;
Packit bf408e
                                lkcd_print("good for flipping byte %d bit %d\n",
Packit bf408e
                                    byte, bit);
Packit bf408e
                                good_rv = bit + byte * 8;
Packit bf408e
                        }
Packit bf408e
Packit bf408e
                        /* Put it back */
Packit bf408e
                        source[byte] ^= (1 << bit);
Packit bf408e
                }
Packit bf408e
        }
Packit bf408e
        if (good_decomp == 0) {
Packit bf408e
                lkcd_print("Could not correct gzip errors.\n");
Packit bf408e
                return -2;
Packit bf408e
        } else if (good_decomp > 1) {
Packit bf408e
                lkcd_print("Too many valid gzip decompressions: %d.\n", good_decomp);
Packit bf408e
                return -3;
Packit bf408e
        } else {
Packit bf408e
                source[good_rv >> 8] ^= 1 << (good_rv % 8);
Packit bf408e
                uncompress(dest, &retlen, source, sourcelen);
Packit bf408e
                source[good_rv >> 8] ^= 1 << (good_rv % 8);
Packit bf408e
                return good_rv;
Packit bf408e
        }
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Uncompress a gzip'd buffer.
Packit bf408e
 *
Packit bf408e
 *  Returns FALSE on error.  If set, then
Packit bf408e
 *    a non-negative value of uncompress_errloc indicates the location of
Packit bf408e
 *    a single-bit error, and the data may be used.
Packit bf408e
 */
Packit bf408e
static int 
Packit bf408e
lkcd_uncompress_gzip(unsigned char *dest, ulong destlen, 
Packit bf408e
	unsigned char *source, ulong sourcelen)
Packit bf408e
{
Packit bf408e
        ulong retlen = destlen;
Packit bf408e
        int rc = FALSE;
Packit bf408e
Packit bf408e
	switch (uncompress(dest, &retlen, source, sourcelen)) 
Packit bf408e
	{
Packit bf408e
	case Z_OK:
Packit bf408e
		if (retlen == destlen) {
Packit bf408e
                        rc = TRUE;
Packit bf408e
                        break;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		lkcd_print("uncompress: returned length not page size: %ld\n",
Packit bf408e
				retlen);
Packit bf408e
                rc = FALSE;
Packit bf408e
                break;
Packit bf408e
Packit bf408e
	case Z_MEM_ERROR:
Packit bf408e
		lkcd_print("uncompress: Z_MEM_ERROR (not enough memory)\n");
Packit bf408e
                rc = FALSE;
Packit bf408e
                break;
Packit bf408e
Packit bf408e
	case Z_BUF_ERROR:
Packit bf408e
		lkcd_print("uncompress: "
Packit bf408e
			"Z_BUF_ERROR (not enough room in output buffer)\n");
Packit bf408e
                rc = FALSE;
Packit bf408e
                break;
Packit bf408e
Packit bf408e
	case Z_DATA_ERROR:
Packit bf408e
		lkcd_print("uncompress: Z_DATA_ERROR (input data corrupted)\n");
Packit bf408e
                rc = FALSE;
Packit bf408e
                break;
Packit bf408e
        default:
Packit bf408e
                rc = FALSE;
Packit bf408e
                break;
Packit bf408e
	}
Packit bf408e
Packit bf408e
        if (rc == FALSE) {
Packit bf408e
                uncompress_errloc =
Packit bf408e
                    uncompress_recover(dest, destlen, source, sourcelen);
Packit bf408e
        }
Packit bf408e
	return rc;
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Generic print routine to handle integral and remote daemon usage of
Packit bf408e
 */
Packit bf408e
void 
Packit bf408e
lkcd_print(char *fmt, ...)
Packit bf408e
{
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	va_list ap;
Packit bf408e
Packit bf408e
        if (!fmt || !strlen(fmt))
Packit bf408e
                return;
Packit bf408e
Packit bf408e
        va_start(ap, fmt);
Packit bf408e
        (void)vsnprintf(buf, BUFSIZE, fmt, ap);
Packit bf408e
        va_end(ap);
Packit bf408e
Packit bf408e
	if (lkcd->fp)
Packit bf408e
		fprintf(lkcd->fp, "%s", buf);
Packit bf408e
	else
Packit bf408e
		console(buf);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Try to read the current dump page header, reporting back either
Packit bf408e
 *  LKCD_DUMPFILE_EOF, LKCD_DUMPFILE_END or LKCD_DUMPFILE_OK.  The header's
Packit bf408e
 *  file pointer position is saved in lkcd->curhdroffs.  If the page is
Packit bf408e
 *  an even megabyte, save its offset.
Packit bf408e
 */
Packit bf408e
int
Packit bf408e
lkcd_load_dump_page_header(void *dp, ulong page)
Packit bf408e
{
Packit bf408e
	uint32_t dp_flags;
Packit bf408e
	uint64_t dp_address, physaddr;
Packit bf408e
	off_t page_offset;
Packit bf408e
	int ret;
Packit bf408e
Packit bf408e
Packit bf408e
	/* This is wasted effort */
Packit bf408e
        page_offset = lkcd->curhdroffs = lseek(lkcd->fd, 0, SEEK_CUR);
Packit bf408e
Packit bf408e
        if (read(lkcd->fd, dp, lkcd->page_header_size) != 
Packit bf408e
	    lkcd->page_header_size) {
Packit bf408e
		if (page > lkcd->total_pages) 
Packit bf408e
			lkcd_dumpfile_complaint(page, lkcd->total_pages, 
Packit bf408e
				LKCD_DUMPFILE_EOF);
Packit bf408e
                return LKCD_DUMPFILE_EOF;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	dp_flags = lkcd->get_dp_flags();
Packit bf408e
	dp_address = lkcd->get_dp_address();
Packit bf408e
Packit bf408e
        if (dp_flags & LKCD_DUMP_END) {
Packit bf408e
                return LKCD_DUMPFILE_END;
Packit bf408e
        }
Packit bf408e
Packit bf408e
	if ((lkcd->flags & LKCD_VALID) && (page > lkcd->total_pages)) 
Packit bf408e
		lkcd->total_pages = page;
Packit bf408e
Packit bf408e
#ifdef X86
Packit bf408e
	/*
Packit bf408e
	 *  Ugly leftover from very early x86 LKCD versions which used 
Packit bf408e
	 *  the kernel unity-mapped virtual address as the dp_address.
Packit bf408e
	 */
Packit bf408e
        if ((page == 0) && !(lkcd->flags & LKCD_VALID) && 
Packit bf408e
	    (lkcd->version == LKCD_DUMP_V1) && 
Packit bf408e
	    (dp_address == 0xc0000000)) 
Packit bf408e
        	lkcd->kvbase = dp_address;
Packit bf408e
#endif
Packit bf408e
Packit bf408e
	physaddr = dp_flags & (LKCD_DUMP_MCLX_V0|LKCD_DUMP_MCLX_V1) ?
Packit bf408e
		(dp_address - lkcd->kvbase) << lkcd->page_shift : 
Packit bf408e
        	dp_address - lkcd->kvbase;
Packit bf408e
Packit bf408e
Packit bf408e
	if ((ret = save_offset(physaddr, page_offset)) < 0) {
Packit bf408e
	    return LKCD_DUMPFILE_EOF; /* really an error */
Packit bf408e
	} 
Packit bf408e
Packit bf408e
	lkcd->zoned_offsets += ret;  /* return = 0 if already known */
Packit bf408e
Packit bf408e
	if (page_offset > lkcd->page_offset_max) {
Packit bf408e
	    /* doesn't this mean I have to re-read this dp? */
Packit bf408e
	    lkcd->page_offset_max = page_offset;
Packit bf408e
	}
Packit bf408e
Packit bf408e
Packit bf408e
	return LKCD_DUMPFILE_OK;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Register a complaint one time, if appropriate.
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
lkcd_dumpfile_complaint(uint32_t realpages, uint32_t dh_num_pages, int retval)
Packit bf408e
{
Packit bf408e
	if (lkcd->flags & LKCD_BAD_DUMP)
Packit bf408e
		return;
Packit bf408e
	
Packit bf408e
	lkcd->flags |= LKCD_BAD_DUMP;
Packit bf408e
Packit bf408e
	if (realpages > dh_num_pages) {
Packit bf408e
		lkcd_print(
Packit bf408e
"\n\nWARNING: This dumpfile contains more pages than the amount indicated\n"
Packit bf408e
"         in the dumpfile header.  This is indicative of a failure during\n"
Packit bf408e
"         the post-panic creation of the dumpfile on the dump device.\n\n");
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (realpages < dh_num_pages) {
Packit bf408e
		lkcd_print(
Packit bf408e
"\n\nWARNING: This dumpfile contains fewer pages than the amount indicated\n"
Packit bf408e
"         in the dumpfile header.  This is indicative of a failure during\n"
Packit bf408e
"         the creation of the dumpfile during boot.\n\n");
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
int
Packit bf408e
get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp)
Packit bf408e
{
Packit bf408e
	switch (lkcd->version) {
Packit bf408e
	case LKCD_DUMP_V8:
Packit bf408e
	case LKCD_DUMP_V9:
Packit bf408e
		return get_lkcd_regs_for_cpu_v8(bt, eip, esp);
Packit bf408e
	default:
Packit bf408e
		return -1;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e