Beispiel #1
0
/*
 *  Used by gdb_interface() to catch gdb-related errors, if desired.
 */
void
gdb_error_hook(void)
{
	char buf1[BUFSIZE];
	char buf2[BUFSIZE];
	int buffers;

	if (CRASHDEBUG(2)) {
		sprintf(buf2, "\n");

		if (CRASHDEBUG(5) && (buffers = get_embedded()))
			sprintf(buf2, "(%d buffer%s in use)\n",
				buffers, buffers > 1 ? "s" : "");

		fprintf(stderr, "%s: returned via gdb_error_hook %s",
			gdb_command_string(pc->cur_gdb_cmd, buf1, TRUE), buf2);

		console("%s: returned via gdb_error_hook %s",
			gdb_command_string(pc->cur_gdb_cmd, buf1, TRUE), buf2);
	}

#ifdef GDB_7_6
	do_cleanups(all_cleanups()); 
#else
	do_cleanups(NULL); 
#endif

	longjmp(pc->gdb_interface_env, 1);
}
Beispiel #2
0
int
read_ramdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
{
	off_t offset;
	int i, found;
	struct ramdump_def *r = &ramdump[0];

	offset = 0;

	for (i = found = 0; i < nodes; i++) {
		r = &ramdump[i];

		if ((paddr >= r->start_paddr) &&
		    (paddr <= r->end_paddr)) {
			offset = (off_t)paddr - (off_t)r->start_paddr;
			found++;
			break;
		}
	}

	if (!found) {
		if (CRASHDEBUG(8))
			fprintf(fp, "read_ramdump: READ_ERROR: "
		    	    "offset not found for paddr: %llx\n",
				(ulonglong)paddr);
		return READ_ERROR;
	}

	if (CRASHDEBUG(8))
		fprintf(fp,
		"read_ramdump: addr: %lx paddr: %llx cnt: %d offset: %llx\n",
			addr, (ulonglong)paddr, cnt, (ulonglong)offset);

	if (lseek(r->rfd, offset, SEEK_SET) == -1) {
		if (CRASHDEBUG(8))
			fprintf(fp, "read_ramdump: SEEK_ERROR: "
				"offset: %llx\n", (ulonglong)offset);
		return SEEK_ERROR;
	}

	if (read(r->rfd, bufptr, cnt) != cnt) {
		if (CRASHDEBUG(8))
			fprintf(fp, "read_ramdump: READ_ERROR: "
				"offset: %llx\n", (ulonglong)offset);
		return READ_ERROR;
	}

        return cnt;
}
static int
read_raw_dump_file(int fd, off_t offset, void *buf, size_t size)
{
	if (lseek(fd, offset, SEEK_SET) < 0) {
		if (CRASHDEBUG(1))
			error(INFO, "cannot lseek dump file\n");
		return FALSE;
	}
	if (read(fd, buf, size) < size) {
		if (CRASHDEBUG(1))
			error(INFO, "cannot read dump file\n");
		return FALSE;
	}

	return TRUE;
}
/*
 *  Determine whether a file is a diskdump creation, and if TRUE,
 *  initialize the diskdump_data structure based upon the contents
 *  of the diskdump header data.
 */
int
is_diskdump(char *file)
{
	int sz, i;

	if (!open_dump_file(file) || !read_dump_header(file))
		return FALSE;

	sz = dd->block_size * (DISKDUMP_CACHED_PAGES);
	if ((dd->page_cache_buf = malloc(sz)) == NULL)
		error(FATAL, "%s: cannot malloc compressed page_cache_buf\n",
			DISKDUMP_VALID() ? "diskdump" : "compressed kdump");

	for (i = 0; i < DISKDUMP_CACHED_PAGES; i++)
		dd->page_cache_hdr[i].pg_bufptr =
			&dd->page_cache_buf[i * dd->block_size];

	if ((dd->compressed_page = (char *)malloc(dd->block_size)) == NULL)
		error(FATAL, "%s: cannot malloc compressed page space\n",
			DISKDUMP_VALID() ? "diskdump" : "compressed kdump");

	if (CRASHDEBUG(1))
		__diskdump_memory_dump(fp);

	if (pc->flags2 & GET_OSRELEASE) 
		diskdump_get_osrelease();

#ifdef LZO
	if (lzo_init() == LZO_E_OK)
		dd->flags |= LZO_SUPPORTED;
#endif

	return TRUE;
}
void
map_cpus_to_prstatus_kdump_cmprs(void)
{
	void **nt_ptr;
	int online, i, j, nrcpus;
	size_t size;

	if (!(online = get_cpus_online()) || (online == kt->cpus))
		return;

	if (CRASHDEBUG(1))
		error(INFO,
		    "cpus: %d online: %d NT_PRSTATUS notes: %d (remapping)\n",
			kt->cpus, online, dd->num_prstatus_notes);

	size = NR_CPUS * sizeof(void *);

	nt_ptr = (void **)GETBUF(size);
	BCOPY(dd->nt_prstatus_percpu, nt_ptr, size);
	BZERO(dd->nt_prstatus_percpu, size);

	/*
	 *  Re-populate the array with the notes mapping to online cpus
	 */
	nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS);

	for (i = 0, j = 0; i < nrcpus; i++) {
		if (in_cpu_map(ONLINE, i))
			dd->nt_prstatus_percpu[i] = nt_ptr[j++];
	}

	FREEBUF(nt_ptr);
}
Beispiel #6
0
/*
 *  Quickest way to gdb -- just pass a command string to pass through.
 */
int
gdb_pass_through(char *cmd, FILE *fptr, ulong flags)
{
        struct gnu_request *req;
	int retval;

	if (CRASHDEBUG(1))
  		console("gdb_pass_through: [%s]\n", cmd); 

        req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request));
        req->buf = cmd;
	if (fptr)
		req->fp = fptr;
        req->command = GNU_PASS_THROUGH;
	req->flags = flags;

        gdb_interface(req);

	if ((req->flags & (GNU_RETURN_ON_ERROR|GNU_COMMAND_FAILED)) ==
	    (GNU_RETURN_ON_ERROR|GNU_COMMAND_FAILED))
		retval = FALSE;
	else
		retval = TRUE;

        FREEBUF(req);

	return retval;
}
ulong
get_diskdump_panic_task(void)
{
	int i;

	if ((!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID())
	    || !get_active_set())
		return NO_TASK;

	if (DISKDUMP_VALID())
		return (ulong)dd->header->tasks[dd->header->current_cpu];

	if (KDUMP_CMPRS_VALID()) {
		if (kernel_symbol_exists("crashing_cpu") &&
		    cpu_map_addr("online")) {
			get_symbol_data("crashing_cpu", sizeof(int), &i);
			if ((i >= 0) && in_cpu_map(ONLINE, i)) {
				if (CRASHDEBUG(1))
					error(INFO, "get_diskdump_panic_task: "
					    "active_set[%d]: %lx\n", 
						i, tt->active_set[i]);
				return (tt->active_set[i]);
			}
		}
	}

	return NO_TASK;
}
Beispiel #8
0
/*
 *  gdb callback to access debug mode. 
 */
int
gdb_CRASHDEBUG(ulong dval)
{
	if (CRASHDEBUG(dval)) 
		return TRUE;

	return (pc->cur_req && (pc->cur_req->debug >= dval));
}
int 
dwarf_print_stack_entry(struct bt_info *bt, int level)
{
	unsigned long offset;
	struct syment *sp;
	char *name;
	struct unwind_frame_info *frame;

	frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info));
	UNW_SP(frame) = bt->stkptr;
	UNW_PC(frame) = bt->instptr;

	sp = value_search(UNW_PC(frame), &offset);
	if (!sp) {
		if (CRASHDEBUG(1))
		    fprintf(fp, "unwind: cannot find symbol for PC: %lx\n",
			UNW_PC(frame));
		goto bailout;
	}

	/*
	 * If offset is zero, it means we have crossed over to the next
	 *  function. Recalculate by adjusting the text address
	 */
	if (!offset) {
		sp = value_search(UNW_PC(frame) - 1, &offset);
		if (!sp) {
			if (CRASHDEBUG(1))
				fprintf(fp,
				    "unwind: cannot find symbol for PC: %lx\n",
					UNW_PC(frame)-1);
			goto bailout;
		}
	}
        name = sp->name;
	fprintf(fp, " #%d [%016lx] %s at %016lx \n", level, UNW_SP(frame), name, UNW_PC(frame));

bailout:
	FREEBUF(frame);
	return level;
}
static void 
add_diskdump_data(char* name)
{
#define DDL_SIZE 16
	int i;
	int sz = sizeof(void*);
	struct diskdump_data *ddp;

	if (dd_list == NULL) {
		dd_list = calloc(DDL_SIZE, sz);
		num_dd = DDL_SIZE;
	} else {
		for (i = 0; i < num_dumpfiles; i++) {
			ddp = dd_list[i];
                	if (same_file(ddp->filename, name))
				error(FATAL, 
				    "split dumpfiles are identical:\n"
				    "  %s\n  %s\n",
					ddp->filename, name);
			if (memcmp(ddp->header, dd->header,
			    sizeof(struct disk_dump_header)))
				error(FATAL, 
				    "split dumpfiles derived from different vmcores:\n"
				    "  %s\n  %s\n",
					ddp->filename, name);
		}
	}

	if (num_dumpfiles == num_dd) {
		/* expand list */
		struct diskdump_data **tmp;
		tmp = calloc(num_dd*2, sz);
		memcpy(tmp, dd_list, sz*num_dd);
		free(dd_list);
		dd_list = tmp;
		num_dd *= 2;
	}

	dd_list[num_dumpfiles] = dd;
	dd->flags |= DUMPFILE_SPLIT;
	dd->filename = name;

	if (CRASHDEBUG(1))
		fprintf(fp, "%s: start_pfn=%lu, end_pfn=%lu\n", name,
			dd->sub_header_kdump->start_pfn,
			dd->sub_header_kdump->end_pfn);
}
Beispiel #11
0
/*
 *  Try to set a crash scope block based upon the vaddr.   
 */
int
gdb_set_crash_scope(ulong vaddr, char *arg)
{
        struct gnu_request request, *req = &request;
	char name[BUFSIZE];
	struct load_module *lm;

	if (!is_kernel_text(vaddr)) {
		error(INFO, "invalid text address: %s\n", arg);
		return FALSE;
	}

	if (module_symbol(vaddr, NULL, &lm, name, 0)) {
		if (!(lm->mod_flags & MOD_LOAD_SYMS)) {
			error(INFO, "attempting to find/load \"%s\" module debuginfo\n", 
				lm->mod_name);
			if (!load_module_symbols_helper(lm->mod_name)) {
				error(INFO, "cannot find/load \"%s\" module debuginfo\n", 
					lm->mod_name);
				return FALSE;
			}
		}
	}

	req->command = GNU_SET_CRASH_BLOCK;
	req->addr = vaddr;
	req->flags = 0;
	req->addr2 = 0;
	gdb_command_funnel(req);    

	if (CRASHDEBUG(1))
		fprintf(fp, 
		    "gdb_set_crash_scope: %s  addr: %lx  block: %lx\n",
			req->flags & GNU_COMMAND_FAILED ? "FAILED" : "OK",  
			req->addr, req->addr2);

	if (req->flags & GNU_COMMAND_FAILED) {
		error(INFO, 
			"gdb cannot find text block for address: %s\n", arg);
		return FALSE;
	}

	return TRUE;
}
void
check_flattened_format(char *file)
{
	int fd;
	struct makedumpfile_header fh;

	if (flattened_format)
		return;

	fd = open(file, O_RDONLY);
	if (fd < 0) {
		error(INFO, "unable to open dump file %s", file);
		return;
	}
	if (read(fd, &fh, sizeof(fh)) < 0) {
		error(INFO, "unable to read dump file %s", file);
		close(fd);
		return;
	}
	close(fd);

	if (!is_bigendian()){
		fh.type    = bswap_64(fh.type);
		fh.version = bswap_64(fh.version);
	}
	if ((strncmp(fh.signature, MAKEDUMPFILE_SIGNATURE, sizeof(MAKEDUMPFILE_SIGNATURE)) != 0) || 
	    (fh.type != TYPE_FLAT_HEADER))
		return;

	if (!read_all_makedumpfile_data_header(file))
		return;

	if (CRASHDEBUG(1))
		fprintf(fp, "%s: FLAT\n\n", file);

	fh_save = fh;

	flattened_format = TRUE;
}
Beispiel #13
0
/*
 *  Called from main() this routine sets up the call-back hook such that
 *  gdb's main() routine -- renamed gdb_main() -- will call back to
 *  our main_loop() after gdb initializes.
 */
void
gdb_main_loop(int argc, char **argv)
{
	argc = 1;

	if (pc->flags & SILENT) {
		if (pc->flags & READNOW)
			argv[argc++] = "--readnow";
		argv[argc++] = "--quiet";
		argv[argc++] = pc->namelist_debug ? 
			pc->namelist_debug : 
			(pc->debuginfo_file && (st->flags & CRC_MATCHES) ?
			pc->debuginfo_file : pc->namelist);
	} else {
		if (pc->flags & READNOW)
			argv[argc++] = "--readnow";
		argv[argc++] = pc->namelist_debug ? 
			pc->namelist_debug : 
			(pc->debuginfo_file && (st->flags & CRC_MATCHES) ?
			pc->debuginfo_file : pc->namelist);
	}

	if (CRASHDEBUG(1)) {
		int i;
		fprintf(fp, "gdb ");
		for (i = 1; i < argc; i++)
			fprintf(fp, "%s ", argv[i]);
		fprintf(fp, "\n");
	}

        optind = 0;
#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1)
        command_loop_hook = main_loop;
#else
	deprecated_command_loop_hook = main_loop;
#endif
        gdb_main_entry(argc, argv);
}
Beispiel #14
0
static int
verify_paddr(physaddr_t paddr)
{
	int i, ok;

	if (!machdep->verify_paddr(paddr))
		return FALSE;

	if (!nr_segments)
		return TRUE;

	for (i = ok = 0; i < nr_segments; i++) {
		if ((paddr >= ram_segments[i].start) &&
		    (paddr < ram_segments[i].end)) {
			ok++;
			break;
		}
	}

	/*
	 *  Pre-2.6.13 x86_64 /proc/iomem was restricted to 4GB,
	 *  so just accept it.
	 */
	if ((paddr >= 0x100000000ULL) &&
	    machine_type("X86_64") &&
	    (THIS_KERNEL_VERSION < LINUX(2,6,13)))
		ok++;

	if (!ok) {
		if (CRASHDEBUG(1))
			console("reject: %llx\n", (ulonglong)paddr);
		return FALSE;
	}
	
	return TRUE;
}
Beispiel #15
0
/*
 *  General purpose routine for passing commands to gdb.  All gdb commands
 *  come through here, where they are passed to gdb_command_funnel().
 */
void 
gdb_interface(struct gnu_request *req)
{
	if (!(pc->flags & GDB_INIT)) 
		error(FATAL, "gdb_interface: gdb not initialized?\n"); 

	if (output_closed()) 
		restart(0);

	if (!req->fp) {
		req->fp = ((pc->flags & RUNTIME) || (pc->flags2 & ALLOW_FP)) ? 
			fp : CRASHDEBUG(1) ? fp : pc->nullfp;
	}

	pc->cur_req = req;
	pc->cur_gdb_cmd = req->command;

	if (req->flags & GNU_RETURN_ON_ERROR) {
		error_hook = gdb_error_hook;
        	if (setjmp(pc->gdb_interface_env)) {
			pc->last_gdb_cmd = pc->cur_gdb_cmd;
			pc->cur_gdb_cmd = 0;
			pc->cur_req = NULL;
			req->flags |= GNU_COMMAND_FAILED;
			pc->flags &= ~IN_GDB;
			return;
		}
	} else
		error_hook = NULL;

	if (CRASHDEBUG(2))
		dump_gnu_request(req, IN_GDB);

        if (!(pc->flags & DROP_CORE)) 
		SIGACTION(SIGSEGV, restart, &pc->sigaction, NULL);
        else 
		SIGACTION(SIGSEGV, SIG_DFL, &pc->sigaction, NULL);

	if (interruptible()) { 
		SIGACTION(SIGINT, pc->gdb_sigaction.sa_handler, 
			&pc->gdb_sigaction, NULL);
	} else {
		SIGACTION(SIGINT, SIG_IGN, &pc->sigaction, NULL);
		SIGACTION(SIGPIPE, SIG_IGN, &pc->sigaction, NULL);
	} 

	pc->flags |= IN_GDB;
	gdb_command_funnel(req);
	pc->flags &= ~IN_GDB;

	SIGACTION(SIGINT, restart, &pc->sigaction, NULL);
	SIGACTION(SIGSEGV, SIG_DFL, &pc->sigaction, NULL);

	if (CRASHDEBUG(2))
		dump_gnu_request(req, !IN_GDB);

	error_hook = NULL;
        pc->last_gdb_cmd = pc->cur_gdb_cmd;
        pc->cur_gdb_cmd = 0;
	pc->cur_req = NULL;
}
/*
 *  Read from a diskdump-created dumpfile.
 */
int
read_diskdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
{
	int ret;
	physaddr_t curpaddr;
	ulong pfn, page_offset;

	pfn = paddr_to_pfn(paddr);

	if (KDUMP_SPLIT()) {
		/* Find proper dd */
		int i;
		unsigned long start_pfn;
		unsigned long end_pfn;

		for (i=0; i<num_dumpfiles; i++) {
			start_pfn = dd_list[i]->sub_header_kdump->start_pfn;
			end_pfn = dd_list[i]->sub_header_kdump->end_pfn;
			if ((pfn >= start_pfn) && (pfn <= end_pfn))	{
				dd = dd_list[i];
				break;
			}
		}

		if (i == num_dumpfiles) {
			if (CRASHDEBUG(8))
				fprintf(fp, "read_diskdump: SEEK_ERROR: "
				    "paddr/pfn %llx/%lx beyond last dumpfile\n",
					(ulonglong)paddr, pfn);
			return SEEK_ERROR;
		}
	}

	curpaddr = paddr & ~((physaddr_t)(dd->block_size-1));
	page_offset = paddr & ((physaddr_t)(dd->block_size-1));

	if ((pfn >= dd->header->max_mapnr) || !page_is_ram(pfn)) {
		if (CRASHDEBUG(8)) {
			fprintf(fp, "read_diskdump: SEEK_ERROR: "
			    "paddr/pfn: %llx/%lx ",
				(ulonglong)paddr, pfn);
			if (pfn >= dd->header->max_mapnr)
				fprintf(fp, "max_mapnr: %x\n",
					dd->header->max_mapnr);
			else
				fprintf(fp, "!page_is_ram\n");
		}

		return SEEK_ERROR;
	}

	if (!page_is_dumpable(pfn)) {
		if ((dd->flags & (ZERO_EXCLUDED|ERROR_EXCLUDED)) ==
		    ERROR_EXCLUDED) {
			if (CRASHDEBUG(8))
				fprintf(fp, "read_diskdump: PAGE_EXCLUDED: "
			    	    "paddr/pfn: %llx/%lx\n",
					(ulonglong)paddr, pfn);
			return PAGE_EXCLUDED;
		}
		if (CRASHDEBUG(8))
			fprintf(fp, "read_diskdump: zero-fill: "
		    	    "paddr/pfn: %llx/%lx\n",
				(ulonglong)paddr, pfn);
		memset(bufptr, 0, cnt);
		return cnt;
	}

	if (!page_is_cached(curpaddr)) {
		if (CRASHDEBUG(8))
			fprintf(fp, "read_diskdump: paddr/pfn: %llx/%lx"
			    " -> cache physical page: %llx\n",
				(ulonglong)paddr, pfn, (ulonglong)curpaddr);

		if ((ret = cache_page(curpaddr)) < 0) {
			if (CRASHDEBUG(8))
				fprintf(fp, "read_diskdump: " 
				    "%s: cannot cache page: %llx\n",
					ret == SEEK_ERROR ?  
					"SEEK_ERROR" : "READ_ERROR",
					(ulonglong)curpaddr);
			return ret;
		}
	} else if (CRASHDEBUG(8))
		fprintf(fp, "read_diskdump: paddr/pfn: %llx/%lx"
		    " -> physical page is cached: %llx\n", 
			(ulonglong)paddr, pfn, (ulonglong)curpaddr);
	
	memcpy(bufptr, dd->curbufptr + page_offset, cnt);
	return cnt;
}
Beispiel #17
0
static char *write_elf(Elf64_Phdr *load, Elf64_Ehdr *e_head, size_t data_offset)
{
#define CPY_BUF_SZ 4096
	int fd1, fd2, i, err = 1;
	char *buf;
	char *out_elf;
	size_t offset;
	ssize_t rd, len;

	buf = (char *)malloc(CPY_BUF_SZ);

	offset = data_offset;

	if (user_elf) {
		fd2 = open(user_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
		if (fd2 < 0) {
			error(INFO, "%s open error, %s\n",
				user_elf, strerror(errno));
			goto end1;
		}
		out_elf = user_elf;
	} else {
		fd2 = mkstemp(elf_default);
		if (fd2 < 0) {
			error(INFO, "%s open error, %s\n",
				elf_default, strerror(errno));
			goto end1;
		}
		out_elf = elf_default;
		pc->flags2 |= RAMDUMP;
	}

	if (user_elf) {
		sprintf(buf, "creating ELF dumpfile: %s", out_elf);
		please_wait(buf);
	} else if (CRASHDEBUG(1))
		fprintf(fp, "creating temporary ELF header: %s\n\n",
			elf_default);

	while (offset > 0) {
		len = write(fd2, e_head + (data_offset - offset), offset);
		if (len < 0) {
			error(INFO, "ramdump write error, %s\n",
				strerror(errno));
			goto end;
		}
		offset -= len;
	}

	if (user_elf) {
		for (i = 0; i < nodes; i++) {
			offset = load[i].p_offset;

			fd1 = open(ramdump[i].path, O_RDONLY, S_IRUSR);
			if (fd1 < 0) {
				error(INFO, "%s open error, %s\n",
					ramdump[i].path, strerror(errno));
				goto end;
			}

			lseek(fd2, (off_t)offset, SEEK_SET);
			while ((rd = read(fd1, buf, CPY_BUF_SZ)) > 0) {
				if (write(fd2, buf, rd) != rd) {
					error(INFO, "%s write error, %s\n",
						ramdump[i].path,
						strerror(errno));
					close(fd1);
					goto end;
				}
			}
			close(fd1);
		}
		please_wait_done();
	}

	err = 0;
end:
	close(fd2);
end1:
	free(buf);
	return err ? NULL : out_elf;
}
static int 
read_dump_header(char *file)
{
	struct disk_dump_header *header = NULL;
	struct disk_dump_sub_header *sub_header = NULL;
	struct kdump_sub_header *sub_header_kdump = NULL;
	size_t size;
	int bitmap_len;
	int block_size = (int)sysconf(_SC_PAGESIZE);
	off_t offset;
	const off_t failed = (off_t)-1;
	ulong pfn;
	int i, j, max_sect_len;
	int is_split = 0;

	if (block_size < 0)
		return FALSE;

restart:
	if ((header = realloc(header, block_size)) == NULL)
		error(FATAL, "diskdump / compressed kdump: cannot malloc block_size buffer\n");

	if (FLAT_FORMAT()) {
		if (!read_flattened_format(dd->dfd, 0, header, block_size)) {
			error(FATAL, "diskdump / compressed kdump: cannot read header\n");
			goto err;
		}
	} else {
		if (lseek(dd->dfd, 0, SEEK_SET) == failed) {
			if (CRASHDEBUG(1))
				error(INFO, "diskdump / compressed kdump: cannot lseek dump header\n");
			goto err;
		}
		if (read(dd->dfd, header, block_size) < block_size) {
			if (CRASHDEBUG(1))
				error(INFO, "diskdump / compressed kdump: cannot read dump header\n");
			goto err;
		}
	}

	/* validate dump header */
	if (!memcmp(header->signature, DISK_DUMP_SIGNATURE,
				sizeof(header->signature))) {
		dd->flags |= DISKDUMP_LOCAL;
	} else if (!memcmp(header->signature, KDUMP_SIGNATURE,
				sizeof(header->signature))) {
		dd->flags |= KDUMP_CMPRS_LOCAL;
		if (header->header_version >= 1)
			dd->flags |= ERROR_EXCLUDED;
	} else {
		if (CRASHDEBUG(1))
			error(INFO, 
			    "diskdump / compressed kdump: dump does not have panic dump header\n");
		goto err;
	}

	if (CRASHDEBUG(1))
		fprintf(fp, "%s: header->utsname.machine: %s\n", 
			DISKDUMP_VALID() ? "diskdump" : "compressed kdump",
			header->utsname.machine);

	if (STRNEQ(header->utsname.machine, "i686") &&
	    machine_type_mismatch(file, "X86", NULL, 0))
		goto err;
	else if (STRNEQ(header->utsname.machine, "x86_64") &&
	    machine_type_mismatch(file, "X86_64", NULL, 0))
		goto err;
	else if (STRNEQ(header->utsname.machine, "ia64") &&
	    machine_type_mismatch(file, "IA64", NULL, 0))
		goto err;
	else if (STREQ(header->utsname.machine, "ppc") &&
	    machine_type_mismatch(file, "PPC", NULL, 0))
		goto err;
	else if (STREQ(header->utsname.machine, "ppc64") &&
	    machine_type_mismatch(file, "PPC64", NULL, 0))
		goto err;
	else if (STRNEQ(header->utsname.machine, "arm") &&
	    machine_type_mismatch(file, "ARM", NULL, 0))
		goto err;
	else if (STRNEQ(header->utsname.machine, "s390x") &&
	    machine_type_mismatch(file, "S390X", NULL, 0))
		goto err;

	if (header->block_size != block_size) {
		block_size = header->block_size;
		if (CRASHDEBUG(1))
			fprintf(fp, 
			    "retrying with different block/page size: %d\n", 
				header->block_size);
		goto restart;
	}
	dd->block_size  = header->block_size;
	dd->block_shift = ffs(header->block_size) - 1;

	if ((DISKDUMP_VALID() &&
             (sizeof(*header) + sizeof(void *) * header->nr_cpus > block_size)) ||
             header->nr_cpus <= 0) {
                error(INFO, "%s: invalid nr_cpus value: %d\n",
                        DISKDUMP_VALID() ? "diskdump" : "compressed kdump",
                        header->nr_cpus);
		if (!machine_type("S390") && !machine_type("S390X")) {
			/* s390 can get register information also from memory */
			goto err;
		}
        }

	/* read sub header */
	offset = (off_t)block_size;

	if (DISKDUMP_VALID()) {
		if ((sub_header = malloc(block_size)) == NULL)
			error(FATAL, "diskdump: cannot malloc sub_header buffer\n");

		if (FLAT_FORMAT()) {
			if (!read_flattened_format(dd->dfd, offset, sub_header, block_size)) {
				error(INFO, "diskdump: cannot read dump sub header\n");
				goto err;
			}
		} else {
			if (lseek(dd->dfd, offset, SEEK_SET) == failed) {
				error(INFO, "diskdump: cannot lseek dump sub header\n");
				goto err;
			}
			if (read(dd->dfd, sub_header, block_size) < block_size) {
				error(INFO, "diskdump: cannot read dump sub header\n");
				goto err;
			}
		}
		dd->sub_header = sub_header;
	} else if (KDUMP_CMPRS_VALID()) {
		if ((sub_header_kdump = malloc(block_size)) == NULL)
			error(FATAL, "compressed kdump: cannot malloc sub_header_kdump buffer\n");

		if (FLAT_FORMAT()) {
			if (!read_flattened_format(dd->dfd, offset, sub_header_kdump, block_size)) {
				error(INFO, "compressed kdump: cannot read dump sub header\n");
				goto err;
			}
		} else {
			if (lseek(dd->dfd, offset, SEEK_SET) == failed) {
				error(INFO, "compressed kdump: cannot lseek dump sub header\n");
				goto err;
			}
			if (read(dd->dfd, sub_header_kdump, block_size) < block_size) {
				error(INFO, "compressed kdump: cannot read dump sub header\n");
				goto err;
			}
		}
		dd->sub_header_kdump = sub_header_kdump;
	}

	/* read memory bitmap */
	bitmap_len = block_size * header->bitmap_blocks;
	dd->bitmap_len = bitmap_len;

	offset = (off_t)block_size * (1 + header->sub_hdr_size);

	if ((dd->bitmap = malloc(bitmap_len)) == NULL)
		error(FATAL, "%s: cannot malloc bitmap buffer\n",
			DISKDUMP_VALID() ? "diskdump" : "compressed kdump");

	dd->dumpable_bitmap = calloc(bitmap_len, 1);

	if (CRASHDEBUG(8))
		fprintf(fp, "%s: memory bitmap offset: %llx\n",
			DISKDUMP_VALID() ? "diskdump" : "compressed kdump",
			(ulonglong)offset);

	if (FLAT_FORMAT()) {
		if (!read_flattened_format(dd->dfd, offset, dd->bitmap, bitmap_len)) {
			error(INFO, "%s: cannot read memory bitmap\n",
				DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
			goto err;
		}
	} else {
		if (lseek(dd->dfd, offset, SEEK_SET) == failed) {
			error(INFO, "%s: cannot lseek memory bitmap\n",
				DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
			goto err;
		}
		if (read(dd->dfd, dd->bitmap, bitmap_len) < bitmap_len) {
			error(INFO, "%s: cannot read memory bitmap\n",
				DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
			goto err;
		}
	}

	if (dump_is_partial(header))
		memcpy(dd->dumpable_bitmap, dd->bitmap + bitmap_len/2,
		       bitmap_len/2);
	else
		memcpy(dd->dumpable_bitmap, dd->bitmap, bitmap_len);

	dd->data_offset
		= (1 + header->sub_hdr_size + header->bitmap_blocks)
		* header->block_size;

	dd->header = header;

	if (machine_type("ARM"))
		dd->machine_type = EM_ARM;
	else if (machine_type("X86"))
		dd->machine_type = EM_386;
	else if (machine_type("X86_64"))
		dd->machine_type = EM_X86_64;
	else if (machine_type("IA64"))
		dd->machine_type = EM_IA_64;
	else if (machine_type("PPC"))
		dd->machine_type = EM_PPC;
	else if (machine_type("PPC64"))
		dd->machine_type = EM_PPC64;
	else if (machine_type("S390X"))
		dd->machine_type = EM_S390;
	else {
		error(INFO, "%s: unsupported machine type: %s\n", 
			DISKDUMP_VALID() ? "diskdump" : "compressed kdump",
			MACHINE_TYPE);
		goto err;
	}

	/* process elf notes data */
	if (KDUMP_CMPRS_VALID() && !(dd->flags & NO_ELF_NOTES) &&
		(dd->header->header_version >= 4) &&
		(sub_header_kdump->offset_note) &&
		(sub_header_kdump->size_note) && (machdep->process_elf_notes)) {
		size = sub_header_kdump->size_note;
		offset = sub_header_kdump->offset_note;

		if ((dd->notes_buf = malloc(size)) == NULL)
			error(FATAL, "compressed kdump: cannot malloc notes"
				" buffer\n");

		if ((dd->nt_prstatus_percpu = malloc(NR_CPUS * sizeof(void*))) == NULL)
			error(FATAL, "compressed kdump: cannot malloc pointer"
				" to NT_PRSTATUS notes\n");

		if (FLAT_FORMAT()) {
			if (!read_flattened_format(dd->dfd, offset, dd->notes_buf, size)) {
				error(INFO, "compressed kdump: cannot read notes data"
					"\n");
				goto err;
			}
		} else {
			if (lseek(dd->dfd, offset, SEEK_SET) == failed) {
				error(INFO, "compressed kdump: cannot lseek notes data\n");
				goto err;
			}
			if (read(dd->dfd, dd->notes_buf, size) < size) {
				error(INFO, "compressed kdump: cannot read notes data"
					"\n");
				goto err;
			}
		}

		machdep->process_elf_notes(dd->notes_buf, size);
	}

	/* Check if dump file contains erasesinfo data */
	if (KDUMP_CMPRS_VALID() && (dd->header->header_version >= 5) &&
		(sub_header_kdump->offset_eraseinfo) &&
		(sub_header_kdump->size_eraseinfo))
		pc->flags2 |= ERASEINFO_DATA;

	/* For split dumpfile */
	if (KDUMP_CMPRS_VALID()) {
		is_split = ((dd->header->header_version >= 2) &&
		            (sub_header_kdump->split));

		if ((is_split && (num_dumpfiles != 0) && (dd_list == NULL))||
		    (!is_split && (num_dumpfiles != 0))) {
			clean_diskdump_data();
			goto err;
		}

		if (is_split)
			add_diskdump_data(file);

		num_dumpfiles++;
	}

	if (!is_split) {
		max_sect_len = divideup(header->max_mapnr, BITMAP_SECT_LEN);
		pfn = 0;
		dd->filename = file;
	}
	else {
		ulong start = sub_header_kdump->start_pfn;
		ulong end = sub_header_kdump->end_pfn;
		max_sect_len = divideup(end - start + 1, BITMAP_SECT_LEN);
		pfn = start;
	}

	dd->valid_pages = calloc(sizeof(ulong), max_sect_len + 1);
	for (i = 1; i < max_sect_len + 1; i++) {
		dd->valid_pages[i] = dd->valid_pages[i - 1];
		for (j = 0; j < BITMAP_SECT_LEN; j++, pfn++)
			if (page_is_dumpable(pfn))
				dd->valid_pages[i]++;
	}

        return TRUE;

err:
	free(header);
	if (sub_header)
		free(sub_header);
	if (sub_header_kdump)
		free(sub_header_kdump);
	if (dd->bitmap)
		free(dd->bitmap);
	if (dd->dumpable_bitmap)
		free(dd->dumpable_bitmap);
	if (dd->notes_buf)
		free(dd->notes_buf);
	if (dd->nt_prstatus_percpu)
		free(dd->nt_prstatus_percpu);

	dd->flags &= ~(DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL);
	pc->flags2 &= ~ELF_NOTES;
	return FALSE;
}
int 
dwarf_backtrace(struct bt_info *bt, int level, ulong stacktop)
{
	unsigned long bp, offset;
	struct syment *sp;
	char *name;
	struct unwind_frame_info *frame;
	int is_ehframe = (!st->dwarf_debug_frame_size && st->dwarf_eh_frame_size);

	frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info));
//	frame->regs.rsp = bt->stkptr;
//	frame->regs.rip = bt->instptr;
	UNW_SP(frame) = bt->stkptr;
	UNW_PC(frame) = bt->instptr;

	/* read rbp from stack for non active tasks */
	if (!(bt->flags & BT_DUMPFILE_SEARCH) && !bt->bptr) {
//		readmem(frame->regs.rsp, KVADDR, &bp,
		readmem(UNW_SP(frame), KVADDR, &bp,
	                sizeof(unsigned long), "reading bp", FAULT_ON_ERROR);
		frame->regs.rbp = bp;  /* fixme for x86 */
	}

	sp = value_search(UNW_PC(frame), &offset);
	if (!sp) {
		if (CRASHDEBUG(1))
		    fprintf(fp, "unwind: cannot find symbol for PC: %lx\n", 
			UNW_PC(frame));
		goto bailout;
	}

	/*
	 * If offset is zero, it means we have crossed over to the next
	 *  function. Recalculate by adjusting the text address
	 */
	if (!offset) {
		sp = value_search(UNW_PC(frame) - 1, &offset);
		if (!sp) {
			if (CRASHDEBUG(1))
				fprintf(fp, 
				    "unwind: cannot find symbol for PC: %lx\n",
					UNW_PC(frame)-1);
			goto bailout;
		}
	}
		


        name = sp->name;
	fprintf(fp, " #%d [%016lx] %s at %016lx \n", level, UNW_SP(frame), name, UNW_PC(frame));

	if (CRASHDEBUG(2))
		fprintf(fp, "    < SP: %lx PC: %lx FP: %lx >\n", UNW_SP(frame), 
			UNW_PC(frame), frame->regs.rbp);

       	while ((UNW_SP(frame) < stacktop)
				&& !unwind(frame, is_ehframe) && UNW_PC(frame)) {
		/* To prevent rip pushed on IRQ stack being reported both
		 * both on the IRQ and process stacks
		 */
		if ((bt->flags & BT_IRQSTACK) && (UNW_SP(frame) >= stacktop - 16))
			break;
               	level++;
		sp = value_search(UNW_PC(frame), &offset);
		if (!sp) {
			if (CRASHDEBUG(1))
				fprintf(fp, 
				    "unwind: cannot find symbol for PC: %lx\n",
					UNW_PC(frame));
			break;
		}

		/*
		 * If offset is zero, it means we have crossed over to the next
		 *  function. Recalculate by adjusting the text address
		 */
		if (!offset) {
			sp = value_search(UNW_PC(frame) - 1, &offset);
			if (!sp) {
				if (CRASHDEBUG(1))
					fprintf(fp,
					    "unwind: cannot find symbol for PC: %lx\n",
						UNW_PC(frame)-1);
				goto bailout;
			}
		}
	        name = sp->name;
		fprintf(fp, "%s#%d [%016lx] %s at %016lx \n", level < 10 ? " " : "",
			level, UNW_SP(frame), name, UNW_PC(frame));

		if (CRASHDEBUG(2))
			fprintf(fp, "    < SP: %lx PC: %lx FP: %lx >\n", UNW_SP(frame), 
				UNW_PC(frame), frame->regs.rbp);
       	}

bailout:
	FREEBUF(frame);
	return ++level;
}
/*
 *  Initialize the unwind table(s) in the best-case order:
 *
 *   1. Use the in-memory kernel and module unwind tables.
 *   2. Use the in-memory kernel-only .eh_frame data. (possible?)
 *   3. Use the kernel-only .eh_frame data from the vmlinux file.
 */ 
void 
init_unwind_table(void)
{
	ulong unwind_table_size;
	void *unwind_table;

	kt->flags &= ~DWARF_UNWIND;

	if (gather_in_memory_unwind_tables()) {
                if (CRASHDEBUG(1))
                        fprintf(fp, "init_unwind_table: DWARF_UNWIND_MEMORY (%d tables)\n",
				unwind_tables_cnt);

                kt->flags |= DWARF_UNWIND_MEMORY;
		if (unwind_tables_cnt > 1)
                	kt->flags |= DWARF_UNWIND_MODULES;
                if (!(kt->flags & NO_DWARF_UNWIND))
                        kt->flags |= DWARF_UNWIND;

		return;
	}

	if (symbol_exists("__start_unwind") &&
	    symbol_exists("__end_unwind")) {
		unwind_table_size = symbol_value("__end_unwind") - 
			symbol_value("__start_unwind");

		if (!(unwind_table = malloc(unwind_table_size))) {
			error(WARNING, "cannot malloc unwind table space\n");
			goto try_eh_frame;
		}

		if (!readmem(symbol_value("__start_unwind"), KVADDR, unwind_table,
            	    unwind_table_size, "unwind table", RETURN_ON_ERROR)) {
			error(WARNING, "cannot read unwind table data\n");
			free(unwind_table);
			goto try_eh_frame;
		}

		kt->flags |= DWARF_UNWIND_MEMORY;
		if (!(kt->flags & NO_DWARF_UNWIND))
			kt->flags |= DWARF_UNWIND;

		default_unwind_table.size = unwind_table_size;
		default_unwind_table.address = unwind_table;

		if (CRASHDEBUG(1)) 
			fprintf(fp, "init_unwind_table: DWARF_UNWIND_MEMORY\n");

		return;
	}

try_eh_frame:

	if (st->dwarf_eh_frame_size || st->dwarf_debug_frame_size) {
		int fd;
		int is_ehframe = (!st->dwarf_debug_frame_size &&
				   st->dwarf_eh_frame_size);

		unwind_table_size = is_ehframe ? st->dwarf_eh_frame_size :
						 st->dwarf_debug_frame_size;

		if (!(unwind_table = malloc(unwind_table_size))) {
			error(WARNING, "cannot malloc unwind table space\n");
			return;
		}

		if ((fd = open(pc->namelist, O_RDONLY)) < 0) {
			error(WARNING, "cannot open %s for %s data\n",
				pc->namelist, is_ehframe ? ".eh_frame" : ".debug_frame");
			free(unwind_table);
			return;
		}

		if (is_ehframe)
			lseek(fd, st->dwarf_eh_frame_file_offset, SEEK_SET);
		else
			lseek(fd, st->dwarf_debug_frame_file_offset, SEEK_SET);

		if (read(fd, unwind_table, unwind_table_size) !=
		    unwind_table_size) {
			if (CRASHDEBUG(1))
				error(WARNING, "cannot read %s data from %s\n",
			        	is_ehframe ? ".eh_frame" : ".debug_frame", pc->namelist);
			free(unwind_table);
			return;
		}

		close(fd);

		default_unwind_table.size = unwind_table_size;
		default_unwind_table.address = unwind_table;

		kt->flags |= DWARF_UNWIND_EH_FRAME;
		if (!(kt->flags & NO_DWARF_UNWIND))
			kt->flags |= DWARF_UNWIND;

		if (CRASHDEBUG(1)) 
			fprintf(fp, "init_unwind_table: DWARF_UNWIND_EH_FRAME\n");

		return;
	}
}
/*
 *  Find the appropriate kernel-only "root_table" unwind_table,
 *  and pass it to populate_local_tables() to do the heavy lifting.
 */
static int 
gather_in_memory_unwind_tables(void)
{
	int i, cnt, found;
	struct syment *sp, *root_tables[10];
	char *root_table_buf;
	char buf[BUFSIZE];
	ulong name;

	STRUCT_SIZE_INIT(unwind_table, "unwind_table");
	MEMBER_OFFSET_INIT(unwind_table_core, "unwind_table", "core");
	MEMBER_OFFSET_INIT(unwind_table_init, "unwind_table", "init");
	MEMBER_OFFSET_INIT(unwind_table_address, "unwind_table", "address");
	MEMBER_OFFSET_INIT(unwind_table_size, "unwind_table", "size");
	MEMBER_OFFSET_INIT(unwind_table_link, "unwind_table", "link");
	MEMBER_OFFSET_INIT(unwind_table_name, "unwind_table", "name");

	if (INVALID_SIZE(unwind_table) ||
	    INVALID_MEMBER(unwind_table_core) ||
	    INVALID_MEMBER(unwind_table_init) ||
	    INVALID_MEMBER(unwind_table_address) ||
	    INVALID_MEMBER(unwind_table_size) ||
	    INVALID_MEMBER(unwind_table_link) ||
	    INVALID_MEMBER(unwind_table_name)) {
		if (CRASHDEBUG(1)) 
			error(NOTE, 
	    "unwind_table structure has changed, or does not exist in this kernel\n");
		return 0;
	}

	/*
	 *  Unfortunately there are two kernel root_table symbols.
	 */
	if (!(cnt = get_syment_array("root_table", root_tables, 10)))
		return 0;

	root_table_buf = GETBUF(SIZE(unwind_table));
	for (i = found = 0; i < cnt; i++) {
		sp = root_tables[i];
		if (!readmem(sp->value, KVADDR, root_table_buf,
                    SIZE(unwind_table), "root unwind_table", 
		    RETURN_ON_ERROR|QUIET))
			goto gather_failed;

		name = ULONG(root_table_buf + OFFSET(unwind_table_name));
		if (read_string(name, buf, strlen("kernel")+1) && 
		    STREQ("kernel", buf)) {
			found++;
			if (CRASHDEBUG(1))
				fprintf(fp, "root_table name: %lx [%s]\n", 
					name, buf);
			break;
		}
	}

	if (!found)
		goto gather_failed;

	cnt = populate_local_tables(sp->value, root_table_buf);

	FREEBUF(root_table_buf);
	return cnt;

gather_failed:

	FREEBUF(root_table_buf);
	return 0;
}
/*
 *  Transfer the relevant data from the kernel and module unwind_table
 *  structures to the local_unwind_table structures.
 */
static int
populate_local_tables(ulong root, char *buf)
{
	struct list_data list_data, *ld;
	int i, cnt;
	ulong *table_list;
	ulong vaddr;
	struct local_unwind_table *tp;

        ld = &list_data;
        BZERO(ld, sizeof(struct list_data));
        ld->start = root;
        ld->member_offset = OFFSET(unwind_table_link);
	ld->flags = RETURN_ON_LIST_ERROR;
	if (CRASHDEBUG(1))
        	ld->flags |= VERBOSE;

	hq_open();
        cnt = do_list(ld);
	if (cnt == -1) {
		error(WARNING, "UNWIND: failed to gather unwind_table list");
		return 0;
	}
        table_list = (ulong *)GETBUF(cnt * sizeof(ulong));
	cnt = retrieve_list(table_list, cnt);
	hq_close();

	if (!(local_unwind_tables = 
	    malloc(sizeof(struct local_unwind_table) * cnt))) {
		error(WARNING, "cannot malloc unwind_table space (%d tables)\n",
			cnt);
		FREEBUF(table_list);
		return 0;
	}

	for (i = 0; i < cnt; i++, tp++) {

                if (!readmem(table_list[i], KVADDR, buf,
                    SIZE(unwind_table), "unwind_table",
                    RETURN_ON_ERROR|QUIET)) {
			error(WARNING, "cannot read unwind_table\n");
			goto failed;
		}

		tp = &local_unwind_tables[i];

		/*
		 *  Copy the required table info for find_table().
		 */
        	BCOPY(buf + OFFSET(unwind_table_core),
                	(char *)&tp->core.pc, sizeof(ulong)*2);
        	BCOPY(buf + OFFSET(unwind_table_init),
                	(char *)&tp->init.pc, sizeof(ulong)*2);
        	BCOPY(buf + OFFSET(unwind_table_size),
                	(char *)&tp->size, sizeof(ulong));

		/*
		 *  Then read the DWARF CFI data.
		 */
		vaddr = ULONG(buf + OFFSET(unwind_table_address));

		if (!(tp->address = malloc(tp->size))) {
			error(WARNING, "cannot malloc unwind_table space\n");
			goto failed;
			break;
		}
                if (!readmem(vaddr, KVADDR, tp->address,
                    tp->size, "DWARF CFI data", RETURN_ON_ERROR|QUIET)) {
			error(WARNING, "cannot read unwind_table data\n");
			goto failed;
		}
	}

	unwind_tables_cnt = cnt;

	if (CRASHDEBUG(7))
		dump_local_unwind_tables();

failed:

	FREEBUF(table_list);
	return unwind_tables_cnt;
}
Beispiel #23
0
/*
 *  The gdb target_xfer_memory() has a hook installed to re-route
 *  all memory accesses back here; reads of 1 or 4 bytes come primarily
 *  from text disassembly requests, and are diverted to the text cache.
 */
int 
gdb_readmem_callback(ulong addr, void *buf, int len, int write)
{ 
	char locbuf[SIZEOF_32BIT], *p1;
	uint32_t *p2;
	int memtype;

	if (write)
		return FALSE;

	if (pc->cur_req->flags & GNU_NO_READMEM)
		return TRUE;

	if (pc->curcmd_flags & MEMTYPE_UVADDR)
		memtype = UVADDR;
	else if (pc->curcmd_flags & MEMTYPE_FILEADDR)
		memtype = FILEADDR;
	else if (!IS_KVADDR(addr)) {
		if (STREQ(pc->curcmd, "gdb") && 
		    STRNEQ(pc->cur_req->buf, "x/")) {
			memtype = UVADDR;
		} else {
			if (CRASHDEBUG(1))
			        console("gdb_readmem_callback: %lx %d FAILED\n",
					addr, len);
			return FALSE;
		}
	} else
		memtype = KVADDR;

	if (CRASHDEBUG(1))
		console("gdb_readmem_callback[%d]: %lx %d\n", 
			memtype, addr, len);

	if (memtype == FILEADDR)
		return(readmem(pc->curcmd_private, memtype, buf, len,
                	"gdb_readmem_callback", RETURN_ON_ERROR));
	
	switch (len)
	{
	case SIZEOF_8BIT:
		p1 = (char *)buf;
		if ((memtype == KVADDR) && 
		    text_value_cache_byte(addr, (unsigned char *)p1)) 
			return TRUE;

		if (!readmem(addr, memtype, locbuf, SIZEOF_32BIT,
		    "gdb_readmem_callback", RETURN_ON_ERROR)) 
			return FALSE;

		*p1 = locbuf[0];
		if (memtype == KVADDR) {
			p2 = (uint32_t *)locbuf;
			text_value_cache(addr, *p2, 0);
		}
		return TRUE;

	case SIZEOF_32BIT:
		if ((memtype == KVADDR) && text_value_cache(addr, 0, buf)) 
			return TRUE;

		if (!readmem(addr, memtype, buf, SIZEOF_32BIT, 
		    "gdb_readmem callback", RETURN_ON_ERROR))
			return FALSE;

		if (memtype == KVADDR)
			text_value_cache(addr, 
				(uint32_t)*((uint32_t *)buf), NULL);
		return TRUE;
	}

	return(readmem(addr, memtype, buf, len,
                "gdb_readmem_callback", RETURN_ON_ERROR));

}
Beispiel #24
0
void
gdb_session_init(void)
{
	struct gnu_request *req;
	int debug_data_pulled_in;

        if (!have_partial_symbols() && !have_full_symbols())
		no_debugging_data(FATAL);

	/*
	 *  Restore the SIGINT and SIGPIPE handlers, which got temporarily
	 *  re-assigned by gdb.  The SIGINT call also initializes GDB's
         *  SIGINT sigaction.
	 */
	SIGACTION(SIGINT, restart, &pc->sigaction, &pc->gdb_sigaction);
	SIGACTION(SIGPIPE, SIG_IGN, &pc->sigaction, NULL);

	if (!(pc->flags & DROP_CORE)) 
		SIGACTION(SIGSEGV, restart, &pc->sigaction, NULL);

	/*
	 *  Set up pointers to gdb variables.
	 */
#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1)
	gdb_output_format = &output_format;
	gdb_print_max = &print_max;
	gdb_prettyprint_structs = &prettyprint_structs;
	gdb_prettyprint_arrays = &prettyprint_arrays;
	gdb_repeat_count_threshold = &repeat_count_threshold;
	gdb_stop_print_at_null = &stop_print_at_null;
	gdb_output_radix = &output_radix;
#else
	gdb_output_format = (int *) 
		gdb_user_print_option_address("output_format");
	gdb_print_max = (unsigned int *)
		gdb_user_print_option_address("print_max");
	gdb_prettyprint_structs = (int *)
		gdb_user_print_option_address("prettyprint_structs");
	gdb_prettyprint_arrays = (int *)
		gdb_user_print_option_address("prettyprint_arrays");
	gdb_repeat_count_threshold = (int *)
		gdb_user_print_option_address("repeat_count_threshold");
	gdb_stop_print_at_null = (int *)
		gdb_user_print_option_address("stop_print_at_null");
	gdb_output_radix = (unsigned int *)
		gdb_user_print_option_address("output_radix");
#endif
	/*
         *  If the output radix is set via the --hex or --dec command line
	 *  option, then pc->output_radix will be non-zero; otherwise use 
	 *  the gdb default.  
	 */
	if (pc->output_radix) {  
		*gdb_output_radix = pc->output_radix;
		*gdb_output_format = (*gdb_output_radix == 10) ? 0 : 'x';
	}

	switch (*gdb_output_radix)
	{
	case 10:
	case 16:
		pc->output_radix = *gdb_output_radix;
		break;
	default:
		pc->output_radix = *gdb_output_radix = 10;
		*gdb_output_format = 0;
	}
		
	*gdb_prettyprint_structs = 1;
	*gdb_repeat_count_threshold = 0x7fffffff;
	*gdb_print_max = 256;
#ifdef GDB_5_3
	gdb_disassemble_from_exec = 0;
#endif

	pc->flags |= GDB_INIT;   /* set here so gdb_interface will work */

        req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request));
        req->buf = GETBUF(BUFSIZE);

	/*
	 *  Make sure the namelist has symbolic data.  Later versions of
	 *  gcc may require that debug data be pulled in by printing a 
	 *  static kernel data structure.
  	 */
	debug_data_pulled_in = FALSE;
retry:
	BZERO(req->buf, BUFSIZE);
        req->command = GNU_GET_DATATYPE;
	req->name = XEN_HYPER_MODE() ? "page_info" : "task_struct";
        req->flags = GNU_RETURN_ON_ERROR;
        gdb_interface(req);

        if (req->flags & GNU_COMMAND_FAILED) {
		if (XEN_HYPER_MODE())
			no_debugging_data(WARNING);  /* just bail out */

		if (!debug_data_pulled_in) {
			if (CRASHDEBUG(1))
				error(INFO, 
           "gdb_session_init: pulling in debug data by accessing init_mm.mmap %s\n",
					symbol_exists("sysfs_mount") ?
					"and syfs_mount" : "");
			debug_data_pulled_in = TRUE;
			req->command = GNU_PASS_THROUGH;
			req->flags = GNU_RETURN_ON_ERROR|GNU_NO_READMEM;
			req->name = NULL;
			if (symbol_exists("sysfs_mount"))
				sprintf(req->buf, "print sysfs_mount, init_mm.mmap");
			else
				sprintf(req->buf, "print init_mm.mmap");
			gdb_interface(req);
        		if (!(req->flags & GNU_COMMAND_FAILED)) 
				goto retry;
		}
		no_debugging_data(WARNING);
	}

	if (pc->flags & KERNEL_DEBUG_QUERY) {
		fprintf(fp, "\n%s: %s: contains debugging data\n\n",
			pc->program_name, pc->namelist);
		if (REMOTE())
			remote_exit();
		clean_exit(0);
	}

	/*
	 *  Set up any pre-ordained gdb settings here that can't be
	 *  accessed directly.
	 */

	req->command = GNU_PASS_THROUGH;
	req->name = NULL, req->flags = 0;
	sprintf(req->buf, "set height 0");
	gdb_interface(req);

	req->command = GNU_PASS_THROUGH;
	req->name = NULL, req->flags = 0;
	sprintf(req->buf, "set width 0");
	gdb_interface(req);

       /*
        *  Patch gdb's symbol values with the correct values from either
        *  the System.map or non-debug vmlinux, whichever is in effect.
        */
	if ((pc->flags & SYSMAP) || (kt->flags & (RELOC_SET|RELOC_FORCE)) || 
	    (pc->namelist_debug && !pc->debuginfo_file)) {
		req->command = GNU_PATCH_SYMBOL_VALUES;
        	req->flags = GNU_RETURN_ON_ERROR;
		gdb_interface(req);
        	if (req->flags & GNU_COMMAND_FAILED)
			error(FATAL, "patching of gdb symbol values failed\n");
	} else if (!(pc->flags & SILENT))
		fprintf(fp, "\n");


	FREEBUF(req->buf);
	FREEBUF(req);
}