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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [binfmt_aout.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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