Import 2.3.26pre2
[davej-history.git] / fs / proc / kcore.c
blobefe22c0b0e96969a8c1803be70b968946bed6bce
1 /*
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>
8 */
10 #include <linux/config.h>
11 #include <linux/mm.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;
24 ssize_t read;
25 ssize_t count1;
26 char * pnt;
27 struct user dump;
28 #if defined (__i386__) || defined (__mc68000__)
29 # define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
30 #else
31 # define FIRST_MAPPED 0
32 #endif
34 memset(&dump, 0, sizeof(struct user));
35 dump.magic = CMAGIC;
36 dump.u_dsize = max_mapnr;
37 #if defined (__i386__)
38 dump.start_code = PAGE_OFFSET;
39 #endif
40 #ifdef __alpha__
41 dump.start_data = PAGE_OFFSET;
42 #endif
44 memsize = (max_mapnr + 1) << PAGE_SHIFT;
45 if (p >= memsize)
46 return 0;
47 if (count > memsize - p)
48 count = memsize - p;
49 read = 0;
51 if (p < sizeof(struct user) && count > 0) {
52 count1 = count;
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);
57 buf += count1;
58 p += count1;
59 count -= count1;
60 read += count1;
63 if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
64 count1 = PAGE_SIZE + FIRST_MAPPED - p;
65 if (count1 > count)
66 count1 = count;
67 clear_user(buf, count1);
68 buf += count1;
69 p += count1;
70 count -= count1;
71 read += count1;
73 if (count > 0) {
74 copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
75 read += count;
77 *ppos += read;
78 return read;
80 #else
83 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
85 /* An ELF note in memory */
86 struct memelfnote
88 const char *name;
89 int type;
90 unsigned int datasz;
91 void *data;
94 extern char saved_command_line[];
96 /*****************************************************************************/
98 * determine size of ELF note
100 static int notesize(struct memelfnote *en)
102 int sz;
104 sz = sizeof(struct elf_note);
105 sz += roundup(strlen(en->name), 4);
106 sz += roundup(en->datasz, 4);
108 return sz;
109 } /* end notesize() */
111 /*****************************************************************************/
113 * store a note in the header buffer
115 static char *storenote(struct memelfnote *men, char *bufp)
117 struct elf_note en;
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);
133 #undef DUMP_WRITE
135 return bufp;
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;
148 struct elfhdr *elf;
149 struct memelfnote notes[3];
150 off_t offset = 0;
152 /* acquire an ELF header block from the buffer */
153 elf = (struct elfhdr *) bufp;
154 bufp += sizeof(*elf);
155 offset += sizeof(*elf);
157 /* set up header */
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;
167 elf->e_entry = 0;
168 elf->e_phoff = sizeof(*elf);
169 elf->e_shoff = 0;
170 elf->e_flags = 0;
171 elf->e_ehsize = sizeof(*elf);
172 elf->e_phentsize= sizeof(struct elf_phdr);
173 elf->e_phnum = 2; /* no. of segments */
174 elf->e_shentsize= 0;
175 elf->e_shnum = 0;
176 elf->e_shstrndx = 0;
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;
185 nhdr->p_offset = 0;
186 nhdr->p_vaddr = 0;
187 nhdr->p_paddr = 0;
188 nhdr->p_memsz = 0;
189 nhdr->p_flags = 0;
190 nhdr->p_align = 0;
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;
212 nhdr->p_filesz = 0;
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(&notes[0]);
223 bufp = storenote(&notes[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));
232 psinfo.pr_state = 0;
233 psinfo.pr_sname = 'R';
234 psinfo.pr_zomb = 0;
236 strcpy(psinfo.pr_fname,"vmlinux");
237 strncpy(psinfo.pr_psargs,saved_command_line,ELF_PRARGSZ);
239 nhdr->p_filesz = notesize(&notes[1]);
240 bufp = storenote(&notes[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(&notes[2]);
249 bufp = storenote(&notes[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,
258 loff_t *fpos)
260 ssize_t acc;
261 size_t size, tsz;
262 char *page;
264 /* work out how much file we allow to be read */
265 size = ((size_t)high_memory - PAGE_OFFSET) + PAGE_SIZE;
266 acc = 0;
268 /* see if file pointer already beyond EOF */
269 if (buflen==0 || *fpos>=size)
270 return 0;
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) {
278 /* get a buffer */
279 page = (char*) __get_free_page(GFP_KERNEL);
280 if (!page)
281 return -ENOMEM;
283 tsz = PAGE_SIZE-*fpos;
284 if (buflen < tsz)
285 tsz = buflen;
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);
293 buflen -= tsz;
294 *fpos += tsz;
295 buffer += tsz;
296 acc += tsz;
298 free_page((unsigned long) page);
300 /* leave now if filled buffer already */
301 if (buflen==0)
302 return tsz;
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;
310 if (buflen < tsz)
311 tsz = buflen;
313 /* write zeros to buffer */
314 clear_user(buffer,tsz);
315 buflen -= tsz;
316 *fpos += tsz;
317 buffer += tsz;
318 acc += tsz;
320 /* leave now if filled buffer already */
321 if (buflen==0)
322 return tsz;
324 #endif
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);
329 #else
330 copy_to_user(buffer,__va(*fpos),buflen);
331 #endif
332 acc += buflen;
334 return acc;
336 } /* end read_kcore() */
337 #endif