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

Subversion Repositories or1k

[/] [or1k/] [tags/] [LINUX_2_4_26_OR32/] [linux/] [linux-2.4/] [fs/] [binfmt_aout.c] - Blame information for rev 1780

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

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/binfmt_aout.c
3
 *
4
 *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
5
 */
6
 
7
#include <linux/module.h>
8
 
9
#include <linux/sched.h>
10
#include <linux/kernel.h>
11
#include <linux/mm.h>
12
#include <linux/mman.h>
13
#include <linux/a.out.h>
14
#include <linux/errno.h>
15
#include <linux/signal.h>
16
#include <linux/string.h>
17
#include <linux/fs.h>
18
#include <linux/file.h>
19
#include <linux/stat.h>
20
#include <linux/fcntl.h>
21
#include <linux/ptrace.h>
22
#include <linux/user.h>
23
#include <linux/slab.h>
24
#include <linux/binfmts.h>
25
#include <linux/personality.h>
26
#include <linux/init.h>
27
 
28
#include <asm/system.h>
29
#include <asm/uaccess.h>
30
#include <asm/pgalloc.h>
31
 
32
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
33
static int load_aout_library(struct file*);
34
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file);
35
 
36
extern void dump_thread(struct pt_regs *, struct user *);
37
 
38
static struct linux_binfmt aout_format = {
39
        NULL, THIS_MODULE, load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
40
};
41
 
42
static void set_brk(unsigned long start, unsigned long end)
43
{
44
        start = PAGE_ALIGN(start);
45
        end = PAGE_ALIGN(end);
46
        if (end <= start)
47
                return;
48
        do_brk(start, end - start);
49
}
50
 
51
/*
52
 * These are the only things you should do on a core-file: use only these
53
 * macros to write out all the necessary info.
54
 */
55
 
56
static int dump_write(struct file *file, const void *addr, int nr)
57
{
58
        return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
59
}
60
 
61
#define DUMP_WRITE(addr, nr)    \
62
        if (!dump_write(file, (void *)(addr), (nr))) \
63
                goto end_coredump;
64
 
65
#define DUMP_SEEK(offset) \
66
if (file->f_op->llseek) { \
67
        if (file->f_op->llseek(file,(offset),0) != (offset)) \
68
                goto end_coredump; \
69
} else file->f_pos = (offset)
70
 
71
/*
72
 * Routine writes a core dump image in the current directory.
73
 * Currently only a stub-function.
74
 *
75
 * Note that setuid/setgid files won't make a core-dump if the uid/gid
76
 * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable"
77
 * field, which also makes sure the core-dumps won't be recursive if the
78
 * dumping of the process results in another error..
79
 */
80
 
81
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
82
{
83
        mm_segment_t fs;
84
        int has_dumped = 0;
85
        unsigned long dump_start, dump_size;
86
        struct user dump;
87
#if defined(__alpha__)
88
#       define START_DATA(u)    (u.start_data)
89
#elif defined(__arm__)
90
#       define START_DATA(u)    ((u.u_tsize << PAGE_SHIFT) + u.start_code)
91
#elif defined(__sparc__)
92
#       define START_DATA(u)    (u.u_tsize)
93
#elif defined(__i386__) || defined(__mc68000__) || defined(__arch_um__)
94
#       define START_DATA(u)    (u.u_tsize << PAGE_SHIFT)
95
#endif
96
#ifdef __sparc__
97
#       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
98
#else
99
#       define START_STACK(u)   (u.start_stack)
100
#endif
101
 
102
        fs = get_fs();
103
        set_fs(KERNEL_DS);
104
        has_dumped = 1;
105
        current->flags |= PF_DUMPCORE;
106
        strncpy(dump.u_comm, current->comm, sizeof(current->comm));
107
#ifndef __sparc__
108
        dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
109
#endif
110
        dump.signal = signr;
111
        dump_thread(regs, &dump);
112
 
113
/* If the size of the dump file exceeds the rlimit, then see what would happen
114
   if we wrote the stack, but not the data area.  */
115
#ifdef __sparc__
116
        if ((dump.u_dsize+dump.u_ssize) >
117
            current->rlim[RLIMIT_CORE].rlim_cur)
118
                dump.u_dsize = 0;
119
#else
120
        if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
121
            current->rlim[RLIMIT_CORE].rlim_cur)
122
                dump.u_dsize = 0;
123
#endif
124
 
125
/* Make sure we have enough room to write the stack and data areas. */
126
#ifdef __sparc__
127
        if ((dump.u_ssize) >
128
            current->rlim[RLIMIT_CORE].rlim_cur)
129
                dump.u_ssize = 0;
130
#else
131
        if ((dump.u_ssize+1) * PAGE_SIZE >
132
            current->rlim[RLIMIT_CORE].rlim_cur)
133
                dump.u_ssize = 0;
134
#endif
135
 
136
/* make sure we actually have a data and stack area to dump */
137
        set_fs(USER_DS);
138
#ifdef __sparc__
139
        if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
140
                dump.u_dsize = 0;
141
        if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
142
                dump.u_ssize = 0;
143
#else
144
        if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
145
                dump.u_dsize = 0;
146
        if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
147
                dump.u_ssize = 0;
148
#endif
149
 
150
        set_fs(KERNEL_DS);
151
/* struct user */
152
        DUMP_WRITE(&dump,sizeof(dump));
153
/* Now dump all of the user data.  Include malloced stuff as well */
154
#ifndef __sparc__
155
        DUMP_SEEK(PAGE_SIZE);
156
#endif
157
/* now we start writing out the user space info */
158
        set_fs(USER_DS);
159
/* Dump the data area */
160
        if (dump.u_dsize != 0) {
161
                dump_start = START_DATA(dump);
162
#ifdef __sparc__
163
                dump_size = dump.u_dsize;
164
#else
165
                dump_size = dump.u_dsize << PAGE_SHIFT;
166
#endif
167
                DUMP_WRITE(dump_start,dump_size);
168
        }
169
/* Now prepare to dump the stack area */
170
        if (dump.u_ssize != 0) {
171
                dump_start = START_STACK(dump);
172
#ifdef __sparc__
173
                dump_size = dump.u_ssize;
174
#else
175
                dump_size = dump.u_ssize << PAGE_SHIFT;
176
#endif
177
                DUMP_WRITE(dump_start,dump_size);
178
        }
179
/* Finally dump the task struct.  Not be used by gdb, but could be useful */
180
        set_fs(KERNEL_DS);
181
        DUMP_WRITE(current,sizeof(*current));
182
end_coredump:
183
        set_fs(fs);
184
        return has_dumped;
185
}
186
 
187
/*
188
 * create_aout_tables() parses the env- and arg-strings in new user
189
 * memory and creates the pointer tables from them, and puts their
190
 * addresses on the "stack", returning the new stack pointer value.
191
 */
192
static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
193
{
194
        char **argv, **envp;
195
        unsigned long * sp;
196
        int argc = bprm->argc;
197
        int envc = bprm->envc;
198
 
199
        sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
200
#ifdef __sparc__
201
        /* This imposes the proper stack alignment for a new process. */
202
        sp = (unsigned long *) (((unsigned long) sp) & ~7);
203
        if ((envc+argc+3)&1) --sp;
204
#endif
205
#ifdef __alpha__
206
/* whee.. test-programs are so much fun. */
207
        put_user(0, --sp);
208
        put_user(0, --sp);
209
        if (bprm->loader) {
210
                put_user(0, --sp);
211
                put_user(0x3eb, --sp);
212
                put_user(bprm->loader, --sp);
213
                put_user(0x3ea, --sp);
214
        }
215
        put_user(bprm->exec, --sp);
216
        put_user(0x3e9, --sp);
217
#endif
218
        sp -= envc+1;
219
        envp = (char **) sp;
220
        sp -= argc+1;
221
        argv = (char **) sp;
222
#if defined(__i386__) || defined(__mc68000__) || defined(__arm__) || defined(__arch_um__)
223
        put_user((unsigned long) envp,--sp);
224
        put_user((unsigned long) argv,--sp);
225
#endif
226
        put_user(argc,--sp);
227
        current->mm->arg_start = (unsigned long) p;
228
        while (argc-->0) {
229
                char c;
230
                put_user(p,argv++);
231
                do {
232
                        get_user(c,p++);
233
                } while (c);
234
        }
235
        put_user(NULL,argv);
236
        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
237
        while (envc-->0) {
238
                char c;
239
                put_user(p,envp++);
240
                do {
241
                        get_user(c,p++);
242
                } while (c);
243
        }
244
        put_user(NULL,envp);
245
        current->mm->env_end = (unsigned long) p;
246
        return sp;
247
}
248
 
249
/*
250
 * These are the functions used to load a.out style executables and shared
251
 * libraries.  There is no binary dependent code anywhere else.
252
 */
253
 
254
static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
255
{
256
        struct exec ex;
257
        unsigned long error;
258
        unsigned long fd_offset;
259
        unsigned long rlim;
260
        int retval;
261
 
262
        ex = *((struct exec *) bprm->buf);              /* exec-header */
263
        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
264
             N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
265
            N_TRSIZE(ex) || N_DRSIZE(ex) ||
266
            bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
267
                return -ENOEXEC;
268
        }
269
 
270
        fd_offset = N_TXTOFF(ex);
271
 
272
        /* Check initial limits. This avoids letting people circumvent
273
         * size limits imposed on them by creating programs with large
274
         * arrays in the data or bss.
275
         */
276
        rlim = current->rlim[RLIMIT_DATA].rlim_cur;
277
        if (rlim >= RLIM_INFINITY)
278
                rlim = ~0;
279
        if (ex.a_data + ex.a_bss > rlim)
280
                return -ENOMEM;
281
 
282
        /* Flush all traces of the currently running executable */
283
        retval = flush_old_exec(bprm);
284
        if (retval)
285
                return retval;
286
 
287
        /* OK, This is the point of no return */
288
#if defined(__alpha__)
289
        SET_AOUT_PERSONALITY(bprm, ex);
290
#elif defined(__sparc__)
291
        set_personality(PER_SUNOS);
292
#if !defined(__sparc_v9__)
293
        memcpy(&current->thread.core_exec, &ex, sizeof(struct exec));
294
#endif
295
#else
296
        set_personality(PER_LINUX);
297
#endif
298
 
299
        current->mm->end_code = ex.a_text +
300
                (current->mm->start_code = N_TXTADDR(ex));
301
        current->mm->end_data = ex.a_data +
302
                (current->mm->start_data = N_DATADDR(ex));
303
        current->mm->brk = ex.a_bss +
304
                (current->mm->start_brk = N_BSSADDR(ex));
305
 
306
        current->mm->rss = 0;
307
        current->mm->mmap = NULL;
308
        compute_creds(bprm);
309
        current->flags &= ~PF_FORKNOEXEC;
310
#ifdef __sparc__
311
        if (N_MAGIC(ex) == NMAGIC) {
312
                loff_t pos = fd_offset;
313
                /* Fuck me plenty... */
314
                /* <AOL></AOL> */
315
                error = do_brk(N_TXTADDR(ex), ex.a_text);
316
                bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
317
                          ex.a_text, &pos);
318
                error = do_brk(N_DATADDR(ex), ex.a_data);
319
                bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
320
                          ex.a_data, &pos);
321
                goto beyond_if;
322
        }
323
#endif
324
 
325
        if (N_MAGIC(ex) == OMAGIC) {
326
                unsigned long text_addr, map_size;
327
                loff_t pos;
328
 
329
                text_addr = N_TXTADDR(ex);
330
 
331
#if defined(__alpha__) || defined(__sparc__)
332
                pos = fd_offset;
333
                map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1;
334
#else
335
                pos = 32;
336
                map_size = ex.a_text+ex.a_data;
337
#endif
338
 
339
                error = do_brk(text_addr & PAGE_MASK, map_size);
340
                if (error != (text_addr & PAGE_MASK)) {
341
                        send_sig(SIGKILL, current, 0);
342
                        return error;
343
                }
344
 
345
                error = bprm->file->f_op->read(bprm->file, (char *)text_addr,
346
                          ex.a_text+ex.a_data, &pos);
347
                if ((signed long)error < 0) {
348
                        send_sig(SIGKILL, current, 0);
349
                        return error;
350
                }
351
 
352
                flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
353
        } else {
354
                static unsigned long error_time, error_time2;
355
                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
356
                    (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
357
                {
358
                        printk(KERN_NOTICE "executable not page aligned\n");
359
                        error_time2 = jiffies;
360
                }
361
 
362
                if ((fd_offset & ~PAGE_MASK) != 0 &&
363
                    (jiffies-error_time) > 5*HZ)
364
                {
365
                        printk(KERN_WARNING
366
                               "fd_offset is not page aligned. Please convert program: %s\n",
367
                               bprm->file->f_dentry->d_name.name);
368
                        error_time = jiffies;
369
                }
370
 
371
                if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
372
                        loff_t pos = fd_offset;
373
                        do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
374
                        bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
375
                                        ex.a_text+ex.a_data, &pos);
376
                        flush_icache_range((unsigned long) N_TXTADDR(ex),
377
                                           (unsigned long) N_TXTADDR(ex) +
378
                                           ex.a_text+ex.a_data);
379
                        goto beyond_if;
380
                }
381
 
382
                down_write(&current->mm->mmap_sem);
383
                error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
384
                        PROT_READ | PROT_EXEC,
385
                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
386
                        fd_offset);
387
                up_write(&current->mm->mmap_sem);
388
 
389
                if (error != N_TXTADDR(ex)) {
390
                        send_sig(SIGKILL, current, 0);
391
                        return error;
392
                }
393
 
394
                down_write(&current->mm->mmap_sem);
395
                error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
396
                                PROT_READ | PROT_WRITE | PROT_EXEC,
397
                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
398
                                fd_offset + ex.a_text);
399
                up_write(&current->mm->mmap_sem);
400
                if (error != N_DATADDR(ex)) {
401
                        send_sig(SIGKILL, current, 0);
402
                        return error;
403
                }
404
        }
405
beyond_if:
406
        set_binfmt(&aout_format);
407
 
408
        set_brk(current->mm->start_brk, current->mm->brk);
409
 
410
        retval = setup_arg_pages(bprm);
411
        if (retval < 0) {
412
                /* Someone check-me: is this error path enough? */
413
                send_sig(SIGKILL, current, 0);
414
                return retval;
415
        }
416
 
417
        current->mm->start_stack =
418
                (unsigned long) create_aout_tables((char *) bprm->p, bprm);
419
#ifdef __alpha__
420
        regs->gp = ex.a_gpvalue;
421
#endif
422
        start_thread(regs, ex.a_entry, current->mm->start_stack);
423
        if (current->ptrace & PT_PTRACED)
424
                send_sig(SIGTRAP, current, 0);
425
        return 0;
426
}
427
 
428
static int load_aout_library(struct file *file)
429
{
430
        struct inode * inode;
431
        unsigned long bss, start_addr, len;
432
        unsigned long error;
433
        int retval;
434
        struct exec ex;
435
 
436
        inode = file->f_dentry->d_inode;
437
 
438
        retval = -ENOEXEC;
439
        error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
440
        if (error != sizeof(ex))
441
                goto out;
442
 
443
        /* We come in here for the regular a.out style of shared libraries */
444
        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
445
            N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
446
            inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
447
                goto out;
448
        }
449
 
450
        if (N_FLAGS(ex))
451
                goto out;
452
 
453
        /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
454
           this off to get the starting address for the page */
455
 
456
        start_addr =  ex.a_entry & 0xfffff000;
457
 
458
        if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
459
                static unsigned long error_time;
460
                loff_t pos = N_TXTOFF(ex);
461
 
462
                if ((jiffies-error_time) > 5*HZ)
463
                {
464
                        printk(KERN_WARNING
465
                               "N_TXTOFF is not page aligned. Please convert library: %s\n",
466
                               file->f_dentry->d_name.name);
467
                        error_time = jiffies;
468
                }
469
 
470
                do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
471
 
472
                file->f_op->read(file, (char *)start_addr,
473
                        ex.a_text + ex.a_data, &pos);
474
                flush_icache_range((unsigned long) start_addr,
475
                                   (unsigned long) start_addr + ex.a_text + ex.a_data);
476
 
477
                retval = 0;
478
                goto out;
479
        }
480
        /* Now use mmap to map the library into memory. */
481
        down_write(&current->mm->mmap_sem);
482
        error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
483
                        PROT_READ | PROT_WRITE | PROT_EXEC,
484
                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
485
                        N_TXTOFF(ex));
486
        up_write(&current->mm->mmap_sem);
487
        retval = error;
488
        if (error != start_addr)
489
                goto out;
490
 
491
        len = PAGE_ALIGN(ex.a_text + ex.a_data);
492
        bss = ex.a_text + ex.a_data + ex.a_bss;
493
        if (bss > len) {
494
                error = do_brk(start_addr + len, bss - len);
495
                retval = error;
496
                if (error != start_addr + len)
497
                        goto out;
498
        }
499
        retval = 0;
500
out:
501
        return retval;
502
}
503
 
504
static int __init init_aout_binfmt(void)
505
{
506
        return register_binfmt(&aout_format);
507
}
508
 
509
static void __exit exit_aout_binfmt(void)
510
{
511
        unregister_binfmt(&aout_format);
512
}
513
 
514
EXPORT_NO_SYMBOLS;
515
 
516
module_init(init_aout_binfmt);
517
module_exit(exit_aout_binfmt);
518
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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