dumpcore: use ptrace function to trigger a coredump
. dumpcore currently relies on minix segments . also ptrace dumpcore fix
This commit is contained in:
parent
5e38c802d8
commit
85ff5a947e
3 changed files with 19 additions and 170 deletions
|
@ -20,172 +20,6 @@
|
|||
|
||||
#define CLICK_WORDS (CLICK_SIZE / sizeof(unsigned long))
|
||||
|
||||
int adjust_stack(pid_t pid, struct mem_map *seg)
|
||||
{
|
||||
static unsigned long buf[CLICK_WORDS];
|
||||
struct ptrace_range pr;
|
||||
size_t off, top, bottom;
|
||||
int i;
|
||||
|
||||
/* FIXME: kernel/VM strangeness */
|
||||
seg->mem_vir -= seg->mem_len - 1;
|
||||
|
||||
/* Scan the stack, top to bottom, to find the lowest accessible region.
|
||||
* In practice that will be at 64MB, so we also scan for the lowest non-zero
|
||||
* region in order to keep the core file size managable.
|
||||
* Portability note: this code assumes that the stack grows down.
|
||||
*/
|
||||
top = seg->mem_vir + seg->mem_len;
|
||||
|
||||
pr.pr_space = TS_DATA;
|
||||
pr.pr_addr = (top - 1) << CLICK_SHIFT;
|
||||
pr.pr_size = sizeof(buf);
|
||||
pr.pr_ptr = buf;
|
||||
|
||||
for (off = top - 1; off >= seg->mem_vir; off--) {
|
||||
if (ptrace(T_GETRANGE, pid, (long) &pr, 0)) {
|
||||
if (errno == EFAULT)
|
||||
break;
|
||||
|
||||
perror("ptrace(T_GETRANGE)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < CLICK_WORDS; i += sizeof(buf[0]))
|
||||
if (buf[i] != 0)
|
||||
bottom = off;
|
||||
|
||||
pr.pr_addr -= sizeof(buf);
|
||||
}
|
||||
|
||||
/* Add one extra zero page as margin. */
|
||||
if (bottom > off && bottom > seg->mem_vir)
|
||||
bottom--;
|
||||
|
||||
seg->mem_len -= bottom - seg->mem_vir;
|
||||
seg->mem_vir = bottom;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_seg(int fd, pid_t pid, int seg, off_t seg_off, phys_bytes seg_bytes)
|
||||
{
|
||||
ssize_t w;
|
||||
static char buf[CLICK_SIZE];
|
||||
struct ptrace_range pr;
|
||||
|
||||
pr.pr_space = (seg == T) ? TS_INS : TS_DATA;
|
||||
pr.pr_addr = seg_off;
|
||||
pr.pr_size = sizeof(buf);
|
||||
pr.pr_ptr = buf;
|
||||
|
||||
for ( ; pr.pr_addr < seg_off + seg_bytes; pr.pr_addr += sizeof(buf))
|
||||
{
|
||||
/* Copy a chunk from user space to the block buffer. */
|
||||
if (ptrace(T_GETRANGE, pid, (long) &pr, 0)) {
|
||||
/* Create holes for inaccessible areas. */
|
||||
if (errno == EFAULT) {
|
||||
lseek(fd, sizeof(buf), SEEK_CUR);
|
||||
continue;
|
||||
}
|
||||
|
||||
perror("ptrace(T_GETRANGE)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((w=write(fd, buf, sizeof(buf))) != sizeof(buf)) {
|
||||
if(w < 0) printf("write error: %s\n", strerror(errno));
|
||||
printf("write_seg: write failed: %d/%d\n", w, sizeof(buf));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dumpcore(pid_t pid)
|
||||
{
|
||||
int r, seg, fd;
|
||||
vir_bytes len;
|
||||
off_t off, seg_off;
|
||||
long data;
|
||||
struct mem_map segs[NR_LOCAL_SEGS];
|
||||
struct proc procentry;
|
||||
ssize_t w;
|
||||
char core_name[PATH_MAX];
|
||||
|
||||
/* Get the process table entry for this process. */
|
||||
len = sizeof(struct proc) / sizeof(long);
|
||||
for (off = 0; off < len; off++)
|
||||
{
|
||||
errno = 0;
|
||||
data = ptrace(T_GETUSER, pid, off * sizeof(long), 0);
|
||||
if (data == -1 && errno != 0)
|
||||
{
|
||||
perror("ptrace(T_GETUSER)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
((long *) &procentry)[off] = data;
|
||||
}
|
||||
|
||||
memcpy(segs, procentry.p_memmap, sizeof(segs));
|
||||
|
||||
/* Correct and reduce the stack segment. */
|
||||
r = adjust_stack(pid, &segs[S]);
|
||||
if (r != 0)
|
||||
goto error;
|
||||
|
||||
/* Create a core file with a temporary, unique name. */
|
||||
sprintf(core_name, "core.%d", pid);
|
||||
|
||||
if((fd = open(core_name, O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0) {
|
||||
fprintf(stderr, "couldn't open %s (%s)\n", core_name,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write out the process's segments. */
|
||||
if((w=write(fd, segs, sizeof(segs))) != sizeof(segs)) {
|
||||
if(w < 0) printf("write error: %s\n", strerror(errno));
|
||||
printf( "segs write failed: %d/%d\n", w, sizeof(segs));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Write out the whole kernel process table entry to get the regs. */
|
||||
if((w=write(fd, &procentry, sizeof(procentry))) != sizeof(procentry)) {
|
||||
if(w < 0) printf("write error: %s\n", strerror(errno));
|
||||
printf( "proc write failed: %d/%d\n", w, sizeof(procentry));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Loop through segments and write the segments themselves out. */
|
||||
for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
|
||||
len= segs[seg].mem_len << CLICK_SHIFT;
|
||||
seg_off= segs[seg].mem_vir << CLICK_SHIFT;
|
||||
r= write_seg(fd, pid, seg, seg_off, len);
|
||||
if (r != 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Give the core file its final name. */
|
||||
if (rename(core_name, "core")) {
|
||||
perror("rename");
|
||||
goto error;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
|
||||
unlink(core_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
|
@ -223,7 +57,10 @@ int main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
r = dumpcore(pid);
|
||||
if (ptrace(T_DUMPCORE, pid, 0, 0) != 0) {
|
||||
fprintf(stderr, "warning, dumpcore failed (%s)\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
if (ptrace(T_DETACH, pid, 0, 0)) {
|
||||
fprintf(stderr, "warning, detaching failed (%s)\n",
|
||||
|
|
|
@ -839,7 +839,13 @@ static void service_pm_postponed(void)
|
|||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
traced_proc_e = job_m_in.PM_TRACED_PROC;
|
||||
term_signal = job_m_in.PM_TERM_SIG;
|
||||
if(job_m_in.PM_PROC != job_m_in.PM_TRACED_PROC) {
|
||||
/* dumpcore request */
|
||||
term_signal = 0;
|
||||
} else {
|
||||
/* dumpcore on exit */
|
||||
term_signal = job_m_in.PM_TERM_SIG;
|
||||
}
|
||||
core_path = (vir_bytes) job_m_in.PM_PATH;
|
||||
|
||||
r = pm_dumpcore(proc_e, term_signal, core_path);
|
||||
|
@ -918,7 +924,12 @@ static void service_pm()
|
|||
case PM_DUMPCORE:
|
||||
{
|
||||
endpoint_t proc_e = job_m_in.PM_PROC;
|
||||
okendpt(proc_e, &slot);
|
||||
|
||||
if(isokendpt(proc_e, &slot) != OK) {
|
||||
printf("VFS: proc ep %d not ok\n", proc_e);
|
||||
return;
|
||||
}
|
||||
|
||||
fp = &fproc[slot];
|
||||
|
||||
if (fp->fp_flags & FP_PENDING) {
|
||||
|
|
|
@ -717,7 +717,8 @@ int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name)
|
|||
unlock_filp(f);
|
||||
(void) close_fd(fp, core_fd); /* ignore failure, we're exiting anyway */
|
||||
|
||||
free_proc(fp, FP_EXITING);
|
||||
if(csig)
|
||||
free_proc(fp, FP_EXITING);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue