Add a virt_foreach() that does the same as what phys_foreach() does and

change virt_size(), virt_dumphdrs() and virt_dumpdata() into its callback
functions.
In virt_foreach() we iterate over all the virtual memory regions that we
want in the minidump. For now, just start with the PBVM (= kernel text
and data plus preloaded modules). The core file this produces can already
be used to work out the libkvm changes that need to be made to support it.
In parallel, we can flesh out the in-kernel bits to dump more of what we
need in a minidump without changing the core file structure.
This commit is contained in:
Marcel Moolenaar 2013-12-28 19:54:19 +00:00
parent b61949dd20
commit e10d245f6c

View File

@ -219,27 +219,113 @@ phys_foreach(phys_callback_t cb, void *arg)
* Virtual dump (aka minidump) support
*/
static int
virt_size(uint64_t *dumpsize)
{
typedef int virt_callback_t(vm_offset_t, vm_size_t, int, void*);
static int
virt_cb_size(vm_offset_t va, vm_size_t sz, int seqnr, void *arg)
{
uint64_t *dumpsize = (uint64_t *)arg;
*dumpsize += sz;
return (0);
}
static int
virt_dumphdrs(struct dumperinfo *di)
virt_cb_dumphdr(vm_offset_t va, vm_size_t sz, int seqnr, void *arg)
{
struct dumperinfo *di = (struct dumperinfo *)arg;
Elf64_Phdr phdr;
int error;
bzero(&phdr, sizeof(phdr));
phdr.p_type = PT_LOAD;
phdr.p_flags = PF_R; /* XXX */
phdr.p_offset = fileofs;
phdr.p_vaddr = va;
phdr.p_paddr = ~0UL;
phdr.p_filesz = sz;
phdr.p_memsz = sz;
phdr.p_align = PAGE_SIZE;
return (-ENOSYS);
error = buf_write(di, (char*)&phdr, sizeof(phdr));
fileofs += phdr.p_filesz;
return (error);
}
static int
virt_dumpdata(struct dumperinfo *di)
virt_cb_dumpdata(vm_offset_t va, vm_size_t sz, int seqnr, void *arg)
{
struct dumperinfo *di = (struct dumperinfo *)arg;
size_t counter, iosz;
int c, error, twiddle;
error = 0; /* catch case in which pgs is 0 */
counter = 0; /* Update twiddle every 16MB */
twiddle = 0;
return (-ENOSYS);
printf(" chunk %d: %ld pages ", seqnr, atop(sz));
while (sz) {
iosz = (sz > DFLTPHYS) ? DFLTPHYS : sz;
counter += iosz;
if (counter >> 24) {
printf("%c\b", "|/-\\"[twiddle++ & 3]);
counter &= (1<<24) - 1;
}
#ifdef SW_WATCHDOG
wdog_kern_pat(WD_LASTVAL);
#endif
error = dump_write(di, (void*)va, 0, dumplo, iosz);
if (error)
break;
dumplo += iosz;
sz -= iosz;
va += iosz;
/* Check for user abort. */
c = cncheckc();
if (c == 0x03)
return (ECANCELED);
if (c != -1)
printf("(CTRL-C to abort) ");
}
printf("... %s\n", (error) ? "fail" : "ok");
return (error);
}
static int
virt_foreach(virt_callback_t cb, void *arg)
{
vm_offset_t va;
vm_size_t sz;
int error, seqnr;
seqnr = 0;
while (1) {
switch (seqnr) {
case 0:
va = IA64_PBVM_BASE;
sz = round_page(bootinfo->bi_kernend) - va;
break;
default:
va = 0;
sz = 0;
break;
}
if (va == 0 && sz == 0)
break;
error = (*cb)(va, sz, seqnr, arg);
if (error)
return (-error);
seqnr++;
}
return (seqnr);
}
/*
* main entry point.
*/
void
dumpsys(struct dumperinfo *di)
{
@ -274,7 +360,7 @@ dumpsys(struct dumperinfo *di)
/* Calculate dump size. */
dumpsize = 0L;
status = (minidump) ? virt_size(&dumpsize) :
status = (minidump) ? virt_foreach(virt_cb_size, &dumpsize) :
phys_foreach(phys_cb_size, &dumpsize);
if (status < 0) {
error = -status;
@ -311,7 +397,7 @@ dumpsys(struct dumperinfo *di)
goto fail;
/* Dump program headers */
status = (minidump) ? virt_dumphdrs(di) :
status = (minidump) ? virt_foreach(virt_cb_dumphdr, di) :
phys_foreach(phys_cb_dumphdr, di);
if (status < 0) {
error = -status;
@ -329,7 +415,7 @@ dumpsys(struct dumperinfo *di)
dumplo += hdrgap;
/* Dump memory chunks (updates dumplo) */
status = (minidump) ? virt_dumpdata(di) :
status = (minidump) ? virt_foreach(virt_cb_dumpdata, di) :
phys_foreach(phys_cb_dumpdata, di);
if (status < 0) {
error = -status;