OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [proc/] [kcore.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      fs/proc/kcore.c kernel ELF/AOUT core dumper
3
 *
4
 *      Modelled on fs/exec.c:aout_core_dump()
5
 *      Jeremy Fitzhardinge <jeremy@sw.oz.au>
6
 *      ELF version written by David Howells <David.Howells@nexor.co.uk>
7
 *      Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@veritas.com>
8
 *      Support to dump vmalloc'd areas (ELF only), Tigran Aivazian <tigran@veritas.com>
9
 *      Safe accesses to vmalloc/direct-mapped discontiguous areas, Kanoj Sarcar <kanoj@sgi.com>
10
 */
11
 
12
#include <linux/config.h>
13
#include <linux/mm.h>
14
#include <linux/proc_fs.h>
15
#include <linux/user.h>
16
#include <linux/a.out.h>
17
#include <linux/elf.h>
18
#include <linux/elfcore.h>
19
#include <linux/vmalloc.h>
20
#include <linux/highmem.h>
21
#include <asm/uaccess.h>
22
#include <asm/io.h>
23
 
24
 
25
static int open_kcore(struct inode * inode, struct file * filp)
26
{
27
        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
28
}
29
 
30
static loff_t lseek_kcore(struct file * file, loff_t offset, int origin);
31
 
32
static ssize_t read_kcore(struct file *, char *, size_t, loff_t *);
33
 
34
struct file_operations proc_kcore_operations = {
35
        read:           read_kcore,
36
        open:           open_kcore,
37
        llseek:         lseek_kcore,
38
};
39
 
40
#ifdef CONFIG_KCORE_AOUT
41
static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *ppos)
42
{
43
        unsigned long long p = *ppos, memsize;
44
        ssize_t read;
45
        ssize_t count1;
46
        char * pnt;
47
        struct user dump;
48
#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__)
49
#       define FIRST_MAPPED     PAGE_SIZE       /* we don't have page 0 mapped on x86.. */
50
#else
51
#       define FIRST_MAPPED     0
52
#endif
53
 
54
        memset(&dump, 0, sizeof(struct user));
55
        dump.magic = CMAGIC;
56
        dump.u_dsize = (virt_to_phys(high_memory) >> PAGE_SHIFT);
57
#if defined (__i386__) || defined(__x86_64__)
58
        dump.start_code = PAGE_OFFSET;
59
#endif
60
#ifdef __alpha__
61
        dump.start_data = PAGE_OFFSET;
62
#endif
63
 
64
        memsize = virt_to_phys(high_memory);
65
        if (p >= memsize)
66
                return 0;
67
        if (count > memsize - p)
68
                count = memsize - p;
69
        read = 0;
70
 
71
        if (p < sizeof(struct user) && count > 0) {
72
                count1 = count;
73
                if (p + count1 > sizeof(struct user))
74
                        count1 = sizeof(struct user)-p;
75
                pnt = (char *) &dump + p;
76
                if (copy_to_user(buf,(void *) pnt, count1))
77
                        return -EFAULT;
78
                buf += count1;
79
                p += count1;
80
                count -= count1;
81
                read += count1;
82
        }
83
 
84
        if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
85
                count1 = PAGE_SIZE + FIRST_MAPPED - p;
86
                if (count1 > count)
87
                        count1 = count;
88
                if (clear_user(buf, count1))
89
                        return -EFAULT;
90
                buf += count1;
91
                p += count1;
92
                count -= count1;
93
                read += count1;
94
        }
95
        if (count > 0) {
96
                if (copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count))
97
                        return -EFAULT;
98
                read += count;
99
        }
100
        *ppos += read;
101
        return read;
102
}
103
#else /* CONFIG_KCORE_AOUT */
104
 
105
#define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
106
 
107
/* An ELF note in memory */
108
struct memelfnote
109
{
110
        const char *name;
111
        int type;
112
        unsigned int datasz;
113
        void *data;
114
};
115
 
116
extern char saved_command_line[];
117
 
118
static unsigned long get_kcore_size(int *num_vma, size_t *elf_buflen)
119
{
120
        unsigned long try, size;
121
        struct vm_struct *m;
122
 
123
        *num_vma = 0;
124
        size = ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
125
        if (!vmlist) {
126
                *elf_buflen = PAGE_SIZE;
127
                return (size);
128
        }
129
 
130
        for (m=vmlist; m; m=m->next) {
131
                try = (unsigned long)m->addr + m->size;
132
                if (try > size)
133
                        size = try;
134
                *num_vma = *num_vma + 1;
135
        }
136
        *elf_buflen =   sizeof(struct elfhdr) +
137
                        (*num_vma + 2)*sizeof(struct elf_phdr) +
138
                        3 * sizeof(struct memelfnote);
139
        *elf_buflen = PAGE_ALIGN(*elf_buflen);
140
        return (size - PAGE_OFFSET + *elf_buflen);
141
}
142
 
143
 
144
/*****************************************************************************/
145
/*
146
 * determine size of ELF note
147
 */
148
static int notesize(struct memelfnote *en)
149
{
150
        int sz;
151
 
152
        sz = sizeof(struct elf_note);
153
        sz += roundup(strlen(en->name), 4);
154
        sz += roundup(en->datasz, 4);
155
 
156
        return sz;
157
} /* end notesize() */
158
 
159
/*****************************************************************************/
160
/*
161
 * store a note in the header buffer
162
 */
163
static char *storenote(struct memelfnote *men, char *bufp)
164
{
165
        struct elf_note en;
166
 
167
#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
168
 
169
        en.n_namesz = strlen(men->name);
170
        en.n_descsz = men->datasz;
171
        en.n_type = men->type;
172
 
173
        DUMP_WRITE(&en, sizeof(en));
174
        DUMP_WRITE(men->name, en.n_namesz);
175
 
176
        /* XXX - cast from long long to long to avoid need for libgcc.a */
177
        bufp = (char*) roundup((unsigned long)bufp,4);
178
        DUMP_WRITE(men->data, men->datasz);
179
        bufp = (char*) roundup((unsigned long)bufp,4);
180
 
181
#undef DUMP_WRITE
182
 
183
        return bufp;
184
} /* end storenote() */
185
 
186
/*
187
 * store an ELF coredump header in the supplied buffer
188
 * num_vma is the number of elements in vmlist
189
 */
190
static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
191
{
192
        struct elf_prstatus prstatus;   /* NT_PRSTATUS */
193
        struct elf_prpsinfo prpsinfo;   /* NT_PRPSINFO */
194
        struct elf_phdr *nhdr, *phdr;
195
        struct elfhdr *elf;
196
        struct memelfnote notes[3];
197
        off_t offset = 0;
198
        struct vm_struct *m;
199
 
200
        /* setup ELF header */
201
        elf = (struct elfhdr *) bufp;
202
        bufp += sizeof(struct elfhdr);
203
        offset += sizeof(struct elfhdr);
204
        memcpy(elf->e_ident, ELFMAG, SELFMAG);
205
        elf->e_ident[EI_CLASS]  = ELF_CLASS;
206
        elf->e_ident[EI_DATA]   = ELF_DATA;
207
        elf->e_ident[EI_VERSION]= EV_CURRENT;
208
        memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
209
        elf->e_type     = ET_CORE;
210
        elf->e_machine  = ELF_ARCH;
211
        elf->e_version  = EV_CURRENT;
212
        elf->e_entry    = 0;
213
        elf->e_phoff    = sizeof(struct elfhdr);
214
        elf->e_shoff    = 0;
215
        elf->e_flags    = 0;
216
        elf->e_ehsize   = sizeof(struct elfhdr);
217
        elf->e_phentsize= sizeof(struct elf_phdr);
218
        elf->e_phnum    = 2 + num_vma;
219
        elf->e_shentsize= 0;
220
        elf->e_shnum    = 0;
221
        elf->e_shstrndx = 0;
222
 
223
        /* setup ELF PT_NOTE program header */
224
        nhdr = (struct elf_phdr *) bufp;
225
        bufp += sizeof(struct elf_phdr);
226
        offset += sizeof(struct elf_phdr);
227
        nhdr->p_type    = PT_NOTE;
228
        nhdr->p_offset  = 0;
229
        nhdr->p_vaddr   = 0;
230
        nhdr->p_paddr   = 0;
231
        nhdr->p_filesz  = 0;
232
        nhdr->p_memsz   = 0;
233
        nhdr->p_flags   = 0;
234
        nhdr->p_align   = 0;
235
 
236
        /* setup ELF PT_LOAD program header for the
237
         * virtual range 0xc0000000 -> high_memory */
238
        phdr = (struct elf_phdr *) bufp;
239
        bufp += sizeof(struct elf_phdr);
240
        offset += sizeof(struct elf_phdr);
241
        phdr->p_type    = PT_LOAD;
242
        phdr->p_flags   = PF_R|PF_W|PF_X;
243
        phdr->p_offset  = dataoff;
244
        phdr->p_vaddr   = PAGE_OFFSET;
245
        phdr->p_paddr   = __pa(PAGE_OFFSET);
246
        phdr->p_filesz  = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET);
247
        phdr->p_align   = PAGE_SIZE;
248
 
249
        /* setup ELF PT_LOAD program header for every vmalloc'd area */
250
        for (m=vmlist; m; m=m->next) {
251
                if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */
252
                        continue;
253
 
254
                phdr = (struct elf_phdr *) bufp;
255
                bufp += sizeof(struct elf_phdr);
256
                offset += sizeof(struct elf_phdr);
257
 
258
                phdr->p_type    = PT_LOAD;
259
                phdr->p_flags   = PF_R|PF_W|PF_X;
260
                phdr->p_offset  = (size_t)m->addr - PAGE_OFFSET + dataoff;
261
                phdr->p_vaddr   = (size_t)m->addr;
262
                phdr->p_paddr   = __pa(m->addr);
263
                phdr->p_filesz  = phdr->p_memsz = m->size;
264
                phdr->p_align   = PAGE_SIZE;
265
        }
266
 
267
        /*
268
         * Set up the notes in similar form to SVR4 core dumps made
269
         * with info from their /proc.
270
         */
271
        nhdr->p_offset  = offset;
272
 
273
        /* set up the process status */
274
        notes[0].name = "CORE";
275
        notes[0].type = NT_PRSTATUS;
276
        notes[0].datasz = sizeof(struct elf_prstatus);
277
        notes[0].data = &prstatus;
278
 
279
        memset(&prstatus, 0, sizeof(struct elf_prstatus));
280
 
281
        nhdr->p_filesz  = notesize(&notes[0]);
282
        bufp = storenote(&notes[0], bufp);
283
 
284
        /* set up the process info */
285
        notes[1].name   = "CORE";
286
        notes[1].type   = NT_PRPSINFO;
287
        notes[1].datasz = sizeof(struct elf_prpsinfo);
288
        notes[1].data   = &prpsinfo;
289
 
290
        memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
291
        prpsinfo.pr_state       = 0;
292
        prpsinfo.pr_sname       = 'R';
293
        prpsinfo.pr_zomb        = 0;
294
 
295
        strcpy(prpsinfo.pr_fname, "vmlinux");
296
        strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
297
 
298
        nhdr->p_filesz  = notesize(&notes[1]);
299
        bufp = storenote(&notes[1], bufp);
300
 
301
        /* set up the task structure */
302
        notes[2].name   = "CORE";
303
        notes[2].type   = NT_TASKSTRUCT;
304
        notes[2].datasz = sizeof(struct task_struct);
305
        notes[2].data   = current;
306
 
307
        nhdr->p_filesz  = notesize(&notes[2]);
308
        bufp = storenote(&notes[2], bufp);
309
 
310
} /* end elf_kcore_store_hdr() */
311
 
312
/*****************************************************************************/
313
/*
314
 * read from the ELF header and then kernel memory
315
 */
316
static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t *fpos)
317
{
318
        ssize_t acc = 0;
319
        unsigned long size, tsz;
320
        size_t elf_buflen;
321
        int num_vma;
322
        unsigned long start;
323
 
324
        read_lock(&vmlist_lock);
325
        proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
326
        if (buflen == 0 || (unsigned long long)*fpos >= size) {
327
                read_unlock(&vmlist_lock);
328
                return 0;
329
        }
330
 
331
        /* trim buflen to not go beyond EOF */
332
        if (buflen > size - *fpos)
333
                buflen = size - *fpos;
334
 
335
        /* construct an ELF core header if we'll need some of it */
336
        if (*fpos < elf_buflen) {
337
                char * elf_buf;
338
 
339
                tsz = elf_buflen - *fpos;
340
                if (buflen < tsz)
341
                        tsz = buflen;
342
                elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
343
                if (!elf_buf) {
344
                        read_unlock(&vmlist_lock);
345
                        return -ENOMEM;
346
                }
347
                memset(elf_buf, 0, elf_buflen);
348
                elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen);
349
                read_unlock(&vmlist_lock);
350
                if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
351
                        kfree(elf_buf);
352
                        return -EFAULT;
353
                }
354
                kfree(elf_buf);
355
                buflen -= tsz;
356
                *fpos += tsz;
357
                buffer += tsz;
358
                acc += tsz;
359
 
360
                /* leave now if filled buffer already */
361
                if (buflen == 0)
362
                        return acc;
363
        } else
364
                read_unlock(&vmlist_lock);
365
 
366
        /* where page 0 not mapped, write zeros into buffer */
367
#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__)
368
        if (*fpos < PAGE_SIZE + elf_buflen) {
369
                /* work out how much to clear */
370
                tsz = PAGE_SIZE + elf_buflen - *fpos;
371
                if (buflen < tsz)
372
                        tsz = buflen;
373
 
374
                /* write zeros to buffer */
375
                if (clear_user(buffer, tsz))
376
                        return -EFAULT;
377
                buflen -= tsz;
378
                *fpos += tsz;
379
                buffer += tsz;
380
                acc += tsz;
381
 
382
                /* leave now if filled buffer already */
383
                if (buflen == 0)
384
                        return tsz;
385
        }
386
#endif
387
 
388
        /*
389
         * Fill the remainder of the buffer from kernel VM space.
390
         * We said in the ELF header that the data which starts
391
         * at 'elf_buflen' is virtual address PAGE_OFFSET. --rmk
392
         */
393
        start = PAGE_OFFSET + (*fpos - elf_buflen);
394
        if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
395
                tsz = buflen;
396
        while (buflen) {
397
                int err;
398
 
399
                if ((start > PAGE_OFFSET) && (start < (unsigned long)high_memory)) {
400
                        if (kern_addr_valid(start)) {
401
                                err = copy_to_user(buffer, (char *)start, tsz);
402
                        } else {
403
                                err = clear_user(buffer, tsz);
404
                        }
405
                } else {
406
                        char * elf_buf;
407
                        struct vm_struct *m;
408
                        unsigned long curstart = start;
409
                        unsigned long cursize = tsz;
410
 
411
                        elf_buf = kmalloc(tsz, GFP_KERNEL);
412
                        if (!elf_buf)
413
                                return -ENOMEM;
414
                        memset(elf_buf, 0, tsz);
415
 
416
                        read_lock(&vmlist_lock);
417
                        for (m=vmlist; m && cursize; m=m->next) {
418
                                unsigned long vmstart;
419
                                unsigned long vmsize;
420
                                unsigned long msize = m->size - PAGE_SIZE;
421
 
422
                                if (((unsigned long)m->addr + msize) <
423
                                                                curstart)
424
                                        continue;
425
                                if ((unsigned long)m->addr > (curstart +
426
                                                                cursize))
427
                                        break;
428
                                vmstart = (curstart < (unsigned long)m->addr ?
429
                                        (unsigned long)m->addr : curstart);
430
                                if (((unsigned long)m->addr + msize) >
431
                                                        (curstart + cursize))
432
                                        vmsize = curstart + cursize - vmstart;
433
                                else
434
                                        vmsize = (unsigned long)m->addr +
435
                                                        msize - vmstart;
436
                                curstart = vmstart + vmsize;
437
                                cursize -= vmsize;
438
                                /* don't dump ioremap'd stuff! (TA) */
439
                                if (m->flags & VM_IOREMAP)
440
                                        continue;
441
                                memcpy(elf_buf + (vmstart - start),
442
                                        (char *)vmstart, vmsize);
443
                        }
444
                        read_unlock(&vmlist_lock);
445
                        err = copy_to_user(buffer, elf_buf, tsz);
446
                                kfree(elf_buf);
447
                        }
448
                if (err)
449
                                        return -EFAULT;
450
                buflen -= tsz;
451
                *fpos += tsz;
452
                buffer += tsz;
453
                acc += tsz;
454
                start += tsz;
455
                tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
456
        }
457
 
458
        return acc;
459
}
460
#endif /* CONFIG_KCORE_AOUT */
461
 
462
static loff_t lseek_kcore(struct file * file, loff_t offset, int origin)
463
{
464
        switch (origin) {
465
                case 2:
466
                        offset += file->f_dentry->d_inode->i_size;
467
                        break;
468
                case 1:
469
                        offset += file->f_pos;
470
        }
471
        /* RED-PEN user can fake an error here by setting offset to >=-4095 && <0  */
472
        file->f_pos = offset;
473
        return offset;
474
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.