]> granicus.if.org Git - strace/blob - mem.c
2003-06-26 Roland McGrath <roland@redhat.com>
[strace] / mem.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 2000 PocketPenguins Inc.  Linux for Hitachi SuperH
7  *                    port by Greg Banks <gbanks@pocketpenguins.com>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  *      $Id$
33  */
34
35 #include "defs.h"
36
37 #ifdef LINUX
38 #include <linux/mman.h>
39 #endif
40 #include <sys/mman.h>
41
42 #if defined(LINUX) && defined(I386)
43 #include <asm/ldt.h>
44 #endif
45 #if defined(LINUX) && defined(SH64)
46 #include <asm/page.h>       /* for PAGE_SHIFT */
47 #endif
48
49 #ifdef HAVE_LONG_LONG_OFF_T
50 /*
51  * Ugly hacks for systems that have a long long off_t
52  */
53 #define sys_mmap64      sys_mmap
54 #endif
55
56 int
57 sys_brk(tcp)
58 struct tcb *tcp;
59 {
60         if (entering(tcp)) {
61                 tprintf("%#lx", tcp->u_arg[0]);
62         }
63 #ifdef LINUX
64         return RVAL_HEX;
65 #else
66         return 0;
67 #endif
68 }
69
70 int
71 sys_sbrk(tcp)
72 struct tcb *tcp;
73 {
74         if (entering(tcp)) {
75                 tprintf("%lu", tcp->u_arg[0]);
76         }
77         return RVAL_HEX;
78 }
79
80 static struct xlat mmap_prot[] = {
81         { PROT_NONE,    "PROT_NONE",    },
82         { PROT_READ,    "PROT_READ"     },
83         { PROT_WRITE,   "PROT_WRITE"    },
84         { PROT_EXEC,    "PROT_EXEC"     },
85         { 0,            NULL            },
86 };
87
88 static struct xlat mmap_flags[] = {
89         { MAP_SHARED,   "MAP_SHARED"    },
90         { MAP_PRIVATE,  "MAP_PRIVATE"   },
91         { MAP_FIXED,    "MAP_FIXED"     },
92 #ifdef MAP_ANONYMOUS
93         { MAP_ANONYMOUS,"MAP_ANONYMOUS" },
94 #endif
95 #ifdef MAP_RENAME
96         { MAP_RENAME,   "MAP_RENAME"    },
97 #endif
98 #ifdef MAP_NORESERVE
99         { MAP_NORESERVE,"MAP_NORESERVE" },
100 #endif
101 #ifdef MAP_POPULATE
102         { MAP_POPULATE, "MAP_POPULATE" },
103 #endif
104 #ifdef MAP_NONBLOCK
105         { MAP_NONBLOCK, "MAP_NONBLOCK" },
106 #endif
107         /*
108          * XXX - this was introduced in SunOS 4.x to distinguish between
109          * the old pre-4.x "mmap()", which:
110          *
111          *      only let you map devices with an "mmap" routine (e.g.,
112          *      frame buffers) in;
113          *
114          *      required you to specify the mapping address;
115          *
116          *      returned 0 on success and -1 on failure;
117          *
118          * memory and which, and the 4.x "mmap()" which:
119          *
120          *      can map plain files;
121          *
122          *      can be asked to pick where to map the file;
123          *
124          *      returns the address where it mapped the file on success
125          *      and -1 on failure.
126          *
127          * It's not actually used in source code that calls "mmap()"; the
128          * "mmap()" routine adds it for you.
129          *
130          * It'd be nice to come up with some way of eliminating it from
131          * the flags, e.g. reporting calls *without* it as "old_mmap()"
132          * and calls with it as "mmap()".
133          */
134 #ifdef _MAP_NEW
135         { _MAP_NEW,     "_MAP_NEW"      },
136 #endif
137 #ifdef MAP_GROWSDOWN
138         { MAP_GROWSDOWN,"MAP_GROWSDOWN" },
139 #endif
140 #ifdef MAP_DENYWRITE
141         { MAP_DENYWRITE,"MAP_DENYWRITE" },
142 #endif
143 #ifdef MAP_EXECUTABLE
144         { MAP_EXECUTABLE,"MAP_EXECUTABLE"},
145 #endif
146 #ifdef MAP_INHERIT
147         { MAP_INHERIT,"MAP_INHERIT"     },
148 #endif
149 #ifdef MAP_FILE
150         { MAP_FILE,"MAP_FILE"},
151 #endif
152 #ifdef MAP_LOCKED
153         { MAP_LOCKED,"MAP_LOCKED"},
154 #endif
155         /* FreeBSD ones */
156 #ifdef MAP_ANON
157         { MAP_ANON,             "MAP_ANON"      },
158 #endif
159 #ifdef MAP_HASSEMAPHORE
160         { MAP_HASSEMAPHORE,     "MAP_HASSEMAPHORE"      },
161 #endif
162 #ifdef MAP_STACK
163         { MAP_STACK,            "MAP_STACK"     },
164 #endif
165 #ifdef MAP_NOSYNC
166         { MAP_NOSYNC,           "MAP_NOSYNC"    },
167 #endif
168 #ifdef MAP_NOCORE
169         { MAP_NOCORE,           "MAP_NOCORE"    },
170 #endif
171         { 0,            NULL            },
172 };
173
174 #if !HAVE_LONG_LONG_OFF_T
175 static
176 int
177 print_mmap(tcp,u_arg)
178 struct tcb *tcp;
179 long *u_arg;
180 {
181         if (entering(tcp)) {
182                 /* addr */
183                 if (!u_arg[0])
184                         tprintf("NULL, ");
185                 else
186                         tprintf("%#lx, ", u_arg[0]);
187                 /* len */
188                 tprintf("%lu, ", u_arg[1]);
189                 /* prot */
190                 printflags(mmap_prot, u_arg[2]);
191                 tprintf(", ");
192                 /* flags */
193 #ifdef MAP_TYPE
194                 printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
195                 addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
196 #else
197                 printflags(mmap_flags, u_arg[3]);
198 #endif
199                 /* fd (is always int, not long) */
200                 tprintf(", %d, ", (int)u_arg[4]);
201                 /* offset */
202                 tprintf("%#lx", u_arg[5]);
203         }
204         return RVAL_HEX;
205 }
206
207 #ifdef LINUX
208 int sys_old_mmap(tcp)
209 struct tcb *tcp;
210 {
211     long u_arg[6];
212
213 #if     defined(IA64)
214     int i, v;
215     /*
216      *  IA64 processes never call this routine, they only use the
217      *  new `sys_mmap' interface.  This code converts the integer
218      *  arguments that the IA32 process pushed onto the stack into
219      *  longs.
220      *
221      *  Note that addresses with bit 31 set will be sign extended.
222      *  Fortunately, those addresses are not currently being generated
223      *  for IA32 processes so it's not a problem.
224      */
225     for (i = 0; i < 6; i++)
226         if (umove(tcp, tcp->u_arg[0] + (i * sizeof(int)), &v) == -1)
227                 return 0;
228         else
229                 u_arg[i] = v;
230 #elif defined(SH) || defined(SH64)
231     /* SH has always passed the args in registers */
232     int i;
233     for (i=0; i<6; i++)
234         u_arg[i] = tcp->u_arg[i];
235 #else
236     if (umoven(tcp, tcp->u_arg[0], sizeof u_arg, (char *) u_arg) == -1)
237             return 0;
238 #endif  // defined(IA64)
239     return print_mmap(tcp, u_arg);
240
241 }
242 #endif
243
244 int
245 sys_mmap(tcp)
246 struct tcb *tcp;
247 {
248 #if defined(LINUX) && defined(SH64)
249     /*
250      * Old mmap differs from new mmap in specifying the
251      * offset in units of bytes rather than pages.  We
252      * pretend it's in byte units so the user only ever
253      * sees bytes in the printout.
254      */
255     tcp->u_arg[5] <<= PAGE_SHIFT;
256 #endif
257     return print_mmap(tcp, tcp->u_arg);
258 }
259 #endif /* !HAVE_LONG_LONG_OFF_T */
260
261 #if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
262 int
263 sys_mmap64(tcp)
264 struct tcb *tcp;
265 {
266 #ifdef linux
267 #ifdef ALPHA
268         long *u_arg = tcp->u_arg;
269 #else /* !ALPHA */
270         long u_arg[7];
271 #endif /* !ALPHA */
272 #else /* !linux */
273         long *u_arg = tcp->u_arg;
274 #endif /* !linux */
275
276         if (entering(tcp)) {
277 #ifdef linux
278 #ifndef ALPHA
279                 if (umoven(tcp, tcp->u_arg[0], sizeof u_arg,
280                                 (char *) u_arg) == -1)
281                         return 0;
282 #endif /* ALPHA */
283 #endif /* linux */
284                 ALIGN64 (tcp, 5);       /* FreeBSD wierdies */
285
286                 /* addr */
287                 tprintf("%#lx, ", u_arg[0]);
288                 /* len */
289                 tprintf("%lu, ", u_arg[1]);
290                 /* prot */
291                 printflags(mmap_prot, u_arg[2]);
292                 tprintf(", ");
293                 /* flags */
294 #ifdef MAP_TYPE
295                 printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
296                 addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
297 #else
298                 printflags(mmap_flags, u_arg[3]);
299 #endif
300                 /* fd */
301                 tprintf(", %ld, ", u_arg[4]);
302                 /* offset */
303                 tprintf("%#llx", LONG_LONG(u_arg[5], u_arg[6]));
304         }
305         return RVAL_HEX;
306 }
307 #endif
308
309
310 int
311 sys_munmap(tcp)
312 struct tcb *tcp;
313 {
314         if (entering(tcp)) {
315                 tprintf("%#lx, %lu",
316                         tcp->u_arg[0], tcp->u_arg[1]);
317         }
318         return 0;
319 }
320
321 int
322 sys_mprotect(tcp)
323 struct tcb *tcp;
324 {
325         if (entering(tcp)) {
326                 tprintf("%#lx, %lu, ",
327                         tcp->u_arg[0], tcp->u_arg[1]);
328                 if (!printflags(mmap_prot, tcp->u_arg[2]))
329                         tprintf("PROT_???");
330         }
331         return 0;
332 }
333
334 #ifdef LINUX
335
336 static struct xlat mremap_flags[] = {
337         { MREMAP_MAYMOVE,       "MREMAP_MAYMOVE"        },
338         { 0,                    NULL                    }
339 };
340
341 int
342 sys_mremap(tcp)
343 struct tcb *tcp;
344 {
345         if (entering(tcp)) {
346                 tprintf("%#lx, %lu, %lu, ", tcp->u_arg[0], tcp->u_arg[1],
347                         tcp->u_arg[2]);
348                 printflags(mremap_flags, tcp->u_arg[3]);
349         }
350         return RVAL_HEX;
351 }
352
353 static struct xlat madvise_flags[] = {
354 #ifdef MADV_NORMAL
355         { MADV_NORMAL,          "MADV_NORMAL" },
356 #endif
357 #ifdef MADZV_RANDOM
358         { MADV_RANDOM,          "MADV_RANDOM" },
359 #endif
360 #ifdef MADV_SEQUENTIAL
361         { MADV_SEQUENTIAL,      "MADV_SEQUENTIAL" },
362 #endif
363 #ifdef MADV_WILLNEED
364         { MADV_WILLNEED,        "MADV_WILLNEED" },
365 #endif
366 #ifdef MADV_DONTNED
367         { MADV_DONTNEED,        "MADV_DONTNEED" },
368 #endif
369         { 0,                    NULL },
370 };
371
372
373 int
374 sys_madvise(tcp)
375 struct tcb *tcp;
376 {
377         if (entering(tcp)) {
378                 tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
379                 printflags(madvise_flags, tcp->u_arg[2]);
380         }
381         return 0;
382 }
383
384
385 static struct xlat mlockall_flags[] = {
386 #ifdef MCL_CURRENT
387         { MCL_CURRENT,  "MCL_CURRENT" },
388 #endif
389 #ifdef MCL_FUTURE
390         { MCL_FUTURE,   "MCL_FUTURE" },
391 #endif
392         { 0,            NULL}
393 };
394
395 int
396 sys_mlockall(tcp)
397 struct tcb *tcp;
398 {
399         if (entering(tcp)) {
400                 printflags(mlockall_flags, tcp->u_arg[0]);
401         }
402         return 0;
403 }
404
405
406 #endif /* LINUX */
407
408 #ifdef MS_ASYNC
409
410 static struct xlat mctl_sync[] = {
411 #ifdef MS_SYNC
412         { MS_SYNC,      "MS_SYNC"       },
413 #endif
414         { MS_ASYNC,     "MS_ASYNC"      },
415         { MS_INVALIDATE,"MS_INVALIDATE" },
416         { 0,            NULL            },
417 };
418
419 int
420 sys_msync(tcp)
421 struct tcb *tcp;
422 {
423         if (entering(tcp)) {
424                 /* addr */
425                 tprintf("%#lx", tcp->u_arg[0]);
426                 /* len */
427                 tprintf(", %lu, ", tcp->u_arg[1]);
428                 /* flags */
429                 if (!printflags(mctl_sync, tcp->u_arg[2]))
430                         tprintf("MS_???");
431         }
432         return 0;
433 }
434
435 #endif /* MS_ASYNC */
436
437 #ifdef MC_SYNC
438
439 static struct xlat mctl_funcs[] = {
440         { MC_LOCK,      "MC_LOCK"       },
441         { MC_LOCKAS,    "MC_LOCKAS"     },
442         { MC_SYNC,      "MC_SYNC"       },
443         { MC_UNLOCK,    "MC_UNLOCK"     },
444         { MC_UNLOCKAS,  "MC_UNLOCKAS"   },
445         { 0,            NULL            },
446 };
447
448 static struct xlat mctl_lockas[] = {
449         { MCL_CURRENT,  "MCL_CURRENT"   },
450         { MCL_FUTURE,   "MCL_FUTURE"    },
451         { 0,            NULL            },
452 };
453
454 int
455 sys_mctl(tcp)
456 struct tcb *tcp;
457 {
458         int arg, function;
459
460         if (entering(tcp)) {
461                 /* addr */
462                 tprintf("%#lx", tcp->u_arg[0]);
463                 /* len */
464                 tprintf(", %lu, ", tcp->u_arg[1]);
465                 /* function */
466                 function = tcp->u_arg[2];
467                 if (!printflags(mctl_funcs, function))
468                         tprintf("MC_???");
469                 /* arg */
470                 arg = tcp->u_arg[3];
471                 tprintf(", ");
472                 switch (function) {
473                 case MC_SYNC:
474                         if (!printflags(mctl_sync, arg))
475                                 tprintf("MS_???");
476                         break;
477                 case MC_LOCKAS:
478                         if (!printflags(mctl_lockas, arg))
479                                 tprintf("MCL_???");
480                         break;
481                 default:
482                         tprintf("%#x", arg);
483                         break;
484                 }
485         }
486         return 0;
487 }
488
489 #endif /* MC_SYNC */
490
491 int
492 sys_mincore(tcp)
493 struct tcb *tcp;
494 {
495         int i, len;
496         char *vec = NULL;
497
498         if (entering(tcp)) {
499                 tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
500         } else {
501                 len = tcp->u_arg[1];
502                 if (syserror(tcp) || tcp->u_arg[2] == 0 ||
503                         (vec = malloc((u_int)len)) == NULL ||
504                         umoven(tcp, tcp->u_arg[2], len, vec) < 0)
505                         tprintf("%#lx", tcp->u_arg[2]);
506                 else {
507                         tprintf("[");
508                         for (i = 0; i < len; i++) {
509                                 if (abbrev(tcp) && i >= max_strlen) {
510                                         tprintf("...");
511                                         break;
512                                 }
513                                 tprintf((vec[i] & 1) ? "1" : "0");
514                         }
515                         tprintf("]");
516                 }
517                 if (vec)
518                         free(vec);
519         }
520         return 0;
521 }
522
523 int
524 sys_getpagesize(tcp)
525 struct tcb *tcp;
526 {
527         if (exiting(tcp))
528                 return RVAL_HEX;
529         return 0;
530 }
531
532 #if defined(LINUX) && defined(__i386__)
533 void
534 print_ldt_entry (ldt_entry)
535 struct modify_ldt_ldt_s *ldt_entry;
536 {
537         tprintf("base_addr:%#08lx, "
538                 "limit:%d, "
539                 "seg_32bit:%d, "
540                 "contents:%d, "
541                 "read_exec_only:%d, "
542                 "limit_in_pages:%d, "
543                 "seg_not_present:%d, "
544                 "useable:%d}",
545                 ldt_entry->base_addr,
546                 ldt_entry->limit,
547                 ldt_entry->seg_32bit,
548                 ldt_entry->contents,
549                 ldt_entry->read_exec_only,
550                 ldt_entry->limit_in_pages,
551                 ldt_entry->seg_not_present,
552                 ldt_entry->useable);
553 }
554
555 int
556 sys_modify_ldt(tcp)
557 struct tcb *tcp;
558 {
559         if (entering(tcp)) {
560                 struct modify_ldt_ldt_s copy;
561                 tprintf("%ld", tcp->u_arg[0]);
562                 if (tcp->u_arg[1] == 0
563                                 || tcp->u_arg[2] != sizeof (struct modify_ldt_ldt_s)
564                                 || umove(tcp, tcp->u_arg[1], &copy) == -1)
565                         tprintf(", %lx", tcp->u_arg[1]);
566                 else {
567                         tprintf(", {entry_number:%d, ", copy.entry_number);
568                         if (!verbose(tcp))
569                                 tprintf("...}");
570                         else {
571                                 print_ldt_entry(&copy);
572                         }
573                 }
574                 tprintf(", %lu", tcp->u_arg[2]);
575         }
576         return 0;
577 }
578
579 int
580 sys_set_thread_area(tcp)
581 struct tcb *tcp;
582 {
583         struct modify_ldt_ldt_s copy;
584         if (entering(tcp)) {
585                 if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
586                         if (copy.entry_number == -1)
587                                 tprintf("{entry_number:%d -> ",
588                                         copy.entry_number);
589                         else
590                                 tprintf("{entry_number:");
591                 }
592         } else {
593                 if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
594                         tprintf("%d, ", copy.entry_number);
595                         if (!verbose(tcp))
596                                 tprintf("...}");
597                         else {
598                                 print_ldt_entry(&copy);
599                         }
600                 } else {
601                         tprintf("%lx", tcp->u_arg[0]);
602                 }
603         }
604         return 0;
605
606 }
607
608 int
609 sys_get_thread_area(tcp)
610 struct tcb *tcp;
611 {
612         struct modify_ldt_ldt_s copy;
613         if (exiting(tcp)) {
614                 if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
615                         tprintf("{entry_number:%d, ", copy.entry_number);
616                         if (!verbose(tcp))
617                                 tprintf("...}");
618                         else {
619                                 print_ldt_entry(&copy);
620                         }
621                 } else {
622                         tprintf("%lx", tcp->u_arg[0]);
623                 }
624         }
625         return 0;
626
627 }
628 #endif /* LINUX && __i386__ */
629
630 #if defined(LINUX)
631 int
632 sys_remap_file_pages(tcp)
633 struct tcb *tcp;
634 {
635         if (entering(tcp)) {
636                 tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
637                 printflags(mmap_prot, tcp->u_arg[2]);
638                 tprintf(", %lu, ", tcp->u_arg[3]);
639 #ifdef MAP_TYPE
640                 printxval(mmap_flags, tcp->u_arg[4] & MAP_TYPE, "MAP_???");
641                 addflags(mmap_flags, tcp->u_arg[4] & ~MAP_TYPE);
642 #else
643                 printflags(mmap_flags, tcp->u_arg[4]);
644 #endif
645         }
646         return 0;
647 }
648 #endif