2 * fs/proc/kcore.c kernel ELF/AOUT core dumper
4 * Modelled on fs/exec.c:aout_core_dump()
5 * Jeremy Fitzhardinge <jeremy@sw.oz.au>
6 * Implemented by David Howells <David.Howells@nexor.co.uk>
7 * Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@sco.com>
10 #include <linux/config.h>
12 #include <linux/proc_fs.h>
13 #include <linux/user.h>
14 #include <linux/a.out.h>
15 #include <linux/elf.h>
16 #include <linux/elfcore.h>
17 #include <asm/uaccess.h>
19 #ifdef CONFIG_KCORE_AOUT
20 ssize_t
read_kcore(struct file
* file
, char * buf
,
21 size_t count
, loff_t
*ppos
)
23 unsigned long p
= *ppos
, memsize
;
28 #if defined (__i386__) || defined (__mc68000__)
29 # define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
31 # define FIRST_MAPPED 0
34 memset(&dump
, 0, sizeof(struct user
));
36 dump
.u_dsize
= max_mapnr
;
37 #if defined (__i386__)
38 dump
.start_code
= PAGE_OFFSET
;
41 dump
.start_data
= PAGE_OFFSET
;
44 memsize
= (max_mapnr
+ 1) << PAGE_SHIFT
;
47 if (count
> memsize
- p
)
51 if (p
< sizeof(struct user
) && count
> 0) {
53 if (p
+ count1
> sizeof(struct user
))
54 count1
= sizeof(struct user
)-p
;
55 pnt
= (char *) &dump
+ p
;
56 copy_to_user(buf
,(void *) pnt
, count1
);
63 if (count
> 0 && p
< PAGE_SIZE
+ FIRST_MAPPED
) {
64 count1
= PAGE_SIZE
+ FIRST_MAPPED
- p
;
67 clear_user(buf
, count1
);
74 copy_to_user(buf
, (void *) (PAGE_OFFSET
+p
-PAGE_SIZE
), count
);
83 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
85 /* An ELF note in memory */
94 extern char saved_command_line
[];
96 /*****************************************************************************/
98 * determine size of ELF note
100 static int notesize(struct memelfnote
*en
)
104 sz
= sizeof(struct elf_note
);
105 sz
+= roundup(strlen(en
->name
), 4);
106 sz
+= roundup(en
->datasz
, 4);
109 } /* end notesize() */
111 /*****************************************************************************/
113 * store a note in the header buffer
115 static char *storenote(struct memelfnote
*men
, char *bufp
)
119 #define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
121 en
.n_namesz
= strlen(men
->name
);
122 en
.n_descsz
= men
->datasz
;
123 en
.n_type
= men
->type
;
125 DUMP_WRITE(&en
, sizeof(en
));
126 DUMP_WRITE(men
->name
, en
.n_namesz
);
128 /* XXX - cast from long long to long to avoid need for libgcc.a */
129 bufp
= (char*) roundup((unsigned long)bufp
,4);
130 DUMP_WRITE(men
->data
, men
->datasz
);
131 bufp
= (char*) roundup((unsigned long)bufp
,4);
136 } /* end storenote() */
138 /*****************************************************************************/
140 * store an ELF coredump header in the supplied buffer
141 * - assume the memory image is the size specified
143 static void elf_kcore_store_hdr(char *bufp
, size_t size
, off_t dataoff
)
145 struct elf_prstatus prstatus
; /* NT_PRSTATUS */
146 struct elf_prpsinfo psinfo
; /* NT_PRPSINFO */
147 struct elf_phdr
*nhdr
, *dhdr
;
149 struct memelfnote notes
[3];
152 /* acquire an ELF header block from the buffer */
153 elf
= (struct elfhdr
*) bufp
;
154 bufp
+= sizeof(*elf
);
155 offset
+= sizeof(*elf
);
158 memcpy(elf
->e_ident
,ELFMAG
,SELFMAG
);
159 elf
->e_ident
[EI_CLASS
] = ELF_CLASS
;
160 elf
->e_ident
[EI_DATA
] = ELF_DATA
;
161 elf
->e_ident
[EI_VERSION
]= EV_CURRENT
;
162 memset(elf
->e_ident
+EI_PAD
,0,EI_NIDENT
-EI_PAD
);
164 elf
->e_type
= ET_CORE
;
165 elf
->e_machine
= ELF_ARCH
;
166 elf
->e_version
= EV_CURRENT
;
168 elf
->e_phoff
= sizeof(*elf
);
171 elf
->e_ehsize
= sizeof(*elf
);
172 elf
->e_phentsize
= sizeof(struct elf_phdr
);
173 elf
->e_phnum
= 2; /* no. of segments */
178 /* acquire an ELF program header blocks from the buffer for notes */
179 nhdr
= (struct elf_phdr
*) bufp
;
180 bufp
+= sizeof(*nhdr
);
181 offset
+= sizeof(*nhdr
);
183 /* store program headers for notes dump */
184 nhdr
->p_type
= PT_NOTE
;
192 /* acquire an ELF program header blocks from the buffer for data */
193 dhdr
= (struct elf_phdr
*) bufp
;
194 bufp
+= sizeof(*dhdr
);
195 offset
+= sizeof(*dhdr
);
197 /* store program headers for data dump */
198 dhdr
->p_type
= PT_LOAD
;
199 dhdr
->p_flags
= PF_R
|PF_W
|PF_X
;
200 dhdr
->p_offset
= dataoff
;
201 dhdr
->p_vaddr
= PAGE_OFFSET
;
202 dhdr
->p_paddr
= __pa(PAGE_OFFSET
);
203 dhdr
->p_filesz
= size
;
204 dhdr
->p_memsz
= size
;
205 dhdr
->p_align
= PAGE_SIZE
;
208 * Set up the notes in similar form to SVR4 core dumps made
209 * with info from their /proc.
211 nhdr
->p_offset
= offset
;
214 /* set up the process status */
215 notes
[0].name
= "CORE";
216 notes
[0].type
= NT_PRSTATUS
;
217 notes
[0].datasz
= sizeof(prstatus
);
218 notes
[0].data
= &prstatus
;
220 memset(&prstatus
,0,sizeof(prstatus
));
222 nhdr
->p_filesz
= notesize(¬es
[0]);
223 bufp
= storenote(¬es
[0],bufp
);
225 /* set up the process info */
226 notes
[1].name
= "CORE";
227 notes
[1].type
= NT_PRPSINFO
;
228 notes
[1].datasz
= sizeof(psinfo
);
229 notes
[1].data
= &psinfo
;
231 memset(&psinfo
,0,sizeof(psinfo
));
233 psinfo
.pr_sname
= 'R';
236 strcpy(psinfo
.pr_fname
,"vmlinux");
237 strncpy(psinfo
.pr_psargs
,saved_command_line
,ELF_PRARGSZ
);
239 nhdr
->p_filesz
= notesize(¬es
[1]);
240 bufp
= storenote(¬es
[1],bufp
);
242 /* set up the task structure */
243 notes
[2].name
= "CORE";
244 notes
[2].type
= NT_TASKSTRUCT
;
245 notes
[2].datasz
= sizeof(*current
);
246 notes
[2].data
= current
;
248 nhdr
->p_filesz
= notesize(¬es
[2]);
249 bufp
= storenote(¬es
[2],bufp
);
251 } /* end elf_kcore_store_hdr() */
253 /*****************************************************************************/
255 * read from the ELF header and then kernel memory
257 ssize_t
read_kcore(struct file
*file
, char *buffer
, size_t buflen
,
264 /* work out how much file we allow to be read */
265 size
= ((size_t)high_memory
- PAGE_OFFSET
) + PAGE_SIZE
;
268 /* see if file pointer already beyond EOF */
269 if (buflen
==0 || *fpos
>=size
)
272 /* trim buflen to not go beyond EOF */
273 if (buflen
> size
-*fpos
)
274 buflen
= size
- *fpos
;
276 /* construct an ELF core header if we'll need some of it */
277 if (*fpos
<PAGE_SIZE
) {
279 page
= (char*) __get_free_page(GFP_KERNEL
);
283 tsz
= PAGE_SIZE
-*fpos
;
287 /* create a header */
288 memset(page
,0,PAGE_SIZE
);
289 elf_kcore_store_hdr(page
,size
-PAGE_SIZE
,PAGE_SIZE
);
291 /* copy data to the users buffer */
292 copy_to_user(buffer
,page
,tsz
);
298 free_page((unsigned long) page
);
300 /* leave now if filled buffer already */
305 /* where page 0 not mapped, write zeros into buffer */
306 #if defined (__i386__) || defined (__mc68000__)
307 if (*fpos
< PAGE_SIZE
*2) {
308 /* work out how much to clear */
309 tsz
= PAGE_SIZE
*2 - *fpos
;
313 /* write zeros to buffer */
314 clear_user(buffer
,tsz
);
320 /* leave now if filled buffer already */
326 /* fill the remainder of the buffer from kernel VM space */
327 #if defined (__i386__) || defined (__mc68000__)
328 copy_to_user(buffer
,__va(*fpos
-PAGE_SIZE
),buflen
);
330 copy_to_user(buffer
,__va(*fpos
),buflen
);
336 } /* end read_kcore() */