1 /* dumpcore - create core file of running process */
5 #include <minix/config.h>
6 #include <minix/type.h>
8 #include <minix/const.h>
9 #include <sys/ptrace.h>
18 #include "../../kernel/arch/i386/include/archtypes.h"
19 #include "../../kernel/proc.h"
21 #define CLICK_WORDS (CLICK_SIZE / sizeof(unsigned long))
23 int adjust_stack(pid_t pid
, struct mem_map
*seg
)
25 static unsigned long buf
[CLICK_WORDS
];
26 struct ptrace_range pr
;
27 size_t off
, top
, bottom
;
30 /* FIXME: kernel/VM strangeness */
31 seg
->mem_vir
-= seg
->mem_len
- 1;
33 /* Scan the stack, top to bottom, to find the lowest accessible region.
34 * In practice that will be at 64MB, so we also scan for the lowest non-zero
35 * region in order to keep the core file size managable.
36 * Portability note: this code assumes that the stack grows down.
38 top
= seg
->mem_vir
+ seg
->mem_len
;
40 pr
.pr_space
= TS_DATA
;
41 pr
.pr_addr
= (top
- 1) << CLICK_SHIFT
;
42 pr
.pr_size
= sizeof(buf
);
45 for (off
= top
- 1; off
>= seg
->mem_vir
; off
--) {
46 if (ptrace(T_GETRANGE
, pid
, (long) &pr
, 0)) {
50 perror("ptrace(T_GETRANGE)");
54 for (i
= 0; i
< CLICK_WORDS
; i
+= sizeof(buf
[0]))
58 pr
.pr_addr
-= sizeof(buf
);
61 /* Add one extra zero page as margin. */
62 if (bottom
> off
&& bottom
> seg
->mem_vir
)
65 seg
->mem_len
-= bottom
- seg
->mem_vir
;
66 seg
->mem_vir
= bottom
;
71 int write_seg(int fd
, pid_t pid
, int seg
, off_t seg_off
, phys_bytes seg_bytes
)
76 static char buf
[CLICK_SIZE
];
77 struct ptrace_range pr
;
79 pr
.pr_space
= (seg
== T
) ? TS_INS
: TS_DATA
;
81 pr
.pr_size
= sizeof(buf
);
84 for ( ; pr
.pr_addr
< seg_off
+ seg_bytes
; pr
.pr_addr
+= sizeof(buf
))
86 /* Copy a chunk from user space to the block buffer. */
87 if (ptrace(T_GETRANGE
, pid
, (long) &pr
, 0)) {
88 /* Create holes for inaccessible areas. */
89 if (errno
== EFAULT
) {
90 lseek(fd
, sizeof(buf
), SEEK_CUR
);
94 perror("ptrace(T_GETRANGE)");
98 if((w
=write(fd
, buf
, sizeof(buf
))) != sizeof(buf
)) {
99 if(w
< 0) printf("write error: %s\n", strerror(errno
));
100 printf("write_seg: write failed: %d/%d\n", w
, sizeof(buf
));
108 int dumpcore(pid_t pid
)
114 struct mem_map segs
[NR_LOCAL_SEGS
];
115 struct proc procentry
;
117 char core_name
[PATH_MAX
];
119 /* Get the process table entry for this process. */
120 len
= sizeof(struct proc
) / sizeof(long);
121 for (off
= 0; off
< len
; off
++)
124 data
= ptrace(T_GETUSER
, pid
, off
* sizeof(long), 0);
125 if (data
== -1 && errno
!= 0)
127 perror("ptrace(T_GETUSER)");
131 ((long *) &procentry
)[off
] = data
;
134 memcpy(segs
, procentry
.p_memmap
, sizeof(segs
));
136 /* Correct and reduce the stack segment. */
137 r
= adjust_stack(pid
, &segs
[S
]);
141 /* Create a core file with a temporary, unique name. */
142 sprintf(core_name
, "core.%d", pid
);
144 if((fd
= open(core_name
, O_CREAT
|O_EXCL
|O_WRONLY
, 0600)) < 0) {
145 fprintf(stderr
, "couldn't open %s (%s)\n", core_name
,
150 /* Write out the process's segments. */
151 if((w
=write(fd
, segs
, sizeof(segs
))) != sizeof(segs
)) {
152 if(w
< 0) printf("write error: %s\n", strerror(errno
));
153 printf( "segs write failed: %d/%d\n", w
, sizeof(segs
));
157 /* Write out the whole kernel process table entry to get the regs. */
158 if((w
=write(fd
, &procentry
, sizeof(procentry
))) != sizeof(procentry
)) {
159 if(w
< 0) printf("write error: %s\n", strerror(errno
));
160 printf( "proc write failed: %d/%d\n", w
, sizeof(procentry
));
164 /* Loop through segments and write the segments themselves out. */
165 for (seg
= 0; seg
< NR_LOCAL_SEGS
; seg
++) {
166 len
= segs
[seg
].mem_len
<< CLICK_SHIFT
;
167 seg_off
= segs
[seg
].mem_vir
<< CLICK_SHIFT
;
168 r
= write_seg(fd
, pid
, seg
, seg_off
, len
);
173 /* Give the core file its final name. */
174 if (rename(core_name
, "core")) {
191 int main(int argc
, char *argv
[])
197 printf("usage: %s <pid>\n", argv
[0]);
203 if (ptrace(T_ATTACH
, pid
, 0, 0) != 0) {
204 perror("ptrace(T_ATTACH)");
208 if (waitpid(pid
, &status
, 0) != pid
) {
213 while (WIFSTOPPED(status
) && WSTOPSIG(status
) != SIGSTOP
) {
214 /* whatever happens here is fine */
215 ptrace(T_RESUME
, pid
, 0, WSTOPSIG(status
));
217 if (waitpid(pid
, &status
, 0) != pid
) {
223 if (!WIFSTOPPED(status
)) {
224 fprintf(stderr
, "process died while attaching\n");
230 if (ptrace(T_DETACH
, pid
, 0, 0)) {
231 fprintf(stderr
, "warning, detaching failed (%s)\n",