]> granicus.if.org Git - strace/blob - mem.c
2003-09-25 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 #ifdef PROT_SEM
86         { PROT_SEM,     "PROT_SEM"      },
87 #endif
88 #ifdef PROT_GROWSDOWN
89         { PROT_GROWSDOWN,"PROT_GROWSDOWN"},
90 #endif
91 #ifdef PROT_GROWSUP
92         { PROT_GROWSUP, "PROT_GROWSUP"  },
93 #endif
94         { 0,            NULL            },
95 };
96
97 static struct xlat mmap_flags[] = {
98         { MAP_SHARED,   "MAP_SHARED"    },
99         { MAP_PRIVATE,  "MAP_PRIVATE"   },
100         { MAP_FIXED,    "MAP_FIXED"     },
101 #ifdef MAP_ANONYMOUS
102         { MAP_ANONYMOUS,"MAP_ANONYMOUS" },
103 #endif
104 #ifdef MAP_RENAME
105         { MAP_RENAME,   "MAP_RENAME"    },
106 #endif
107 #ifdef MAP_NORESERVE
108         { MAP_NORESERVE,"MAP_NORESERVE" },
109 #endif
110 #ifdef MAP_POPULATE
111         { MAP_POPULATE, "MAP_POPULATE" },
112 #endif
113 #ifdef MAP_NONBLOCK
114         { MAP_NONBLOCK, "MAP_NONBLOCK" },
115 #endif
116         /*
117          * XXX - this was introduced in SunOS 4.x to distinguish between
118          * the old pre-4.x "mmap()", which:
119          *
120          *      only let you map devices with an "mmap" routine (e.g.,
121          *      frame buffers) in;
122          *
123          *      required you to specify the mapping address;
124          *
125          *      returned 0 on success and -1 on failure;
126          *
127          * memory and which, and the 4.x "mmap()" which:
128          *
129          *      can map plain files;
130          *
131          *      can be asked to pick where to map the file;
132          *
133          *      returns the address where it mapped the file on success
134          *      and -1 on failure.
135          *
136          * It's not actually used in source code that calls "mmap()"; the
137          * "mmap()" routine adds it for you.
138          *
139          * It'd be nice to come up with some way of eliminating it from
140          * the flags, e.g. reporting calls *without* it as "old_mmap()"
141          * and calls with it as "mmap()".
142          */
143 #ifdef _MAP_NEW
144         { _MAP_NEW,     "_MAP_NEW"      },
145 #endif
146 #ifdef MAP_GROWSDOWN
147         { MAP_GROWSDOWN,"MAP_GROWSDOWN" },
148 #endif
149 #ifdef MAP_DENYWRITE
150         { MAP_DENYWRITE,"MAP_DENYWRITE" },
151 #endif
152 #ifdef MAP_EXECUTABLE
153         { MAP_EXECUTABLE,"MAP_EXECUTABLE"},
154 #endif
155 #ifdef MAP_INHERIT
156         { MAP_INHERIT,"MAP_INHERIT"     },
157 #endif
158 #ifdef MAP_FILE
159         { MAP_FILE,"MAP_FILE"},
160 #endif
161 #ifdef MAP_LOCKED
162         { MAP_LOCKED,"MAP_LOCKED"},
163 #endif
164         /* FreeBSD ones */
165 #ifdef MAP_ANON
166         { MAP_ANON,             "MAP_ANON"      },
167 #endif
168 #ifdef MAP_HASSEMAPHORE
169         { MAP_HASSEMAPHORE,     "MAP_HASSEMAPHORE"      },
170 #endif
171 #ifdef MAP_STACK
172         { MAP_STACK,            "MAP_STACK"     },
173 #endif
174 #ifdef MAP_NOSYNC
175         { MAP_NOSYNC,           "MAP_NOSYNC"    },
176 #endif
177 #ifdef MAP_NOCORE
178         { MAP_NOCORE,           "MAP_NOCORE"    },
179 #endif
180         { 0,            NULL            },
181 };
182
183 #if !HAVE_LONG_LONG_OFF_T
184 static
185 int
186 print_mmap(tcp,u_arg)
187 struct tcb *tcp;
188 long *u_arg;
189 {
190         if (entering(tcp)) {
191                 /* addr */
192                 if (!u_arg[0])
193                         tprintf("NULL, ");
194                 else
195                         tprintf("%#lx, ", u_arg[0]);
196                 /* len */
197                 tprintf("%lu, ", u_arg[1]);
198                 /* prot */
199                 printflags(mmap_prot, u_arg[2]);
200                 tprintf(", ");
201                 /* flags */
202 #ifdef MAP_TYPE
203                 printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
204                 addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
205 #else
206                 printflags(mmap_flags, u_arg[3]);
207 #endif
208                 /* fd (is always int, not long) */
209                 tprintf(", %d, ", (int)u_arg[4]);
210                 /* offset */
211                 tprintf("%#lx", u_arg[5]);
212         }
213         return RVAL_HEX;
214 }
215
216 #ifdef LINUX
217 int sys_old_mmap(tcp)
218 struct tcb *tcp;
219 {
220     long u_arg[6];
221
222 #if     defined(IA64)
223     int i, v;
224     /*
225      *  IA64 processes never call this routine, they only use the
226      *  new `sys_mmap' interface.  This code converts the integer
227      *  arguments that the IA32 process pushed onto the stack into
228      *  longs.
229      *
230      *  Note that addresses with bit 31 set will be sign extended.
231      *  Fortunately, those addresses are not currently being generated
232      *  for IA32 processes so it's not a problem.
233      */
234     for (i = 0; i < 6; i++)
235         if (umove(tcp, tcp->u_arg[0] + (i * sizeof(int)), &v) == -1)
236                 return 0;
237         else
238                 u_arg[i] = v;
239 #elif defined(SH) || defined(SH64)
240     /* SH has always passed the args in registers */
241     int i;
242     for (i=0; i<6; i++)
243         u_arg[i] = tcp->u_arg[i];
244 #else
245     if (umoven(tcp, tcp->u_arg[0], sizeof u_arg, (char *) u_arg) == -1)
246             return 0;
247 #endif  // defined(IA64)
248     return print_mmap(tcp, u_arg);
249
250 }
251 #endif
252
253 int
254 sys_mmap(tcp)
255 struct tcb *tcp;
256 {
257 #if defined(LINUX) && defined(SH64)
258     /*
259      * Old mmap differs from new mmap in specifying the
260      * offset in units of bytes rather than pages.  We
261      * pretend it's in byte units so the user only ever
262      * sees bytes in the printout.
263      */
264     tcp->u_arg[5] <<= PAGE_SHIFT;
265 #endif
266     return print_mmap(tcp, tcp->u_arg);
267 }
268 #endif /* !HAVE_LONG_LONG_OFF_T */
269
270 #if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
271 int
272 sys_mmap64(tcp)
273 struct tcb *tcp;
274 {
275 #ifdef linux
276 #ifdef ALPHA
277         long *u_arg = tcp->u_arg;
278 #else /* !ALPHA */
279         long u_arg[7];
280 #endif /* !ALPHA */
281 #else /* !linux */
282         long *u_arg = tcp->u_arg;
283 #endif /* !linux */
284
285         if (entering(tcp)) {
286 #ifdef linux
287 #ifndef ALPHA
288                 if (umoven(tcp, tcp->u_arg[0], sizeof u_arg,
289                                 (char *) u_arg) == -1)
290                         return 0;
291 #endif /* ALPHA */
292 #endif /* linux */
293                 ALIGN64 (tcp, 5);       /* FreeBSD wierdies */
294
295                 /* addr */
296                 tprintf("%#lx, ", u_arg[0]);
297                 /* len */
298                 tprintf("%lu, ", u_arg[1]);
299                 /* prot */
300                 printflags(mmap_prot, u_arg[2]);
301                 tprintf(", ");
302                 /* flags */
303 #ifdef MAP_TYPE
304                 printxval(mmap_flags, u_arg[3] & MAP_TYPE, "MAP_???");
305                 addflags(mmap_flags, u_arg[3] & ~MAP_TYPE);
306 #else
307                 printflags(mmap_flags, u_arg[3]);
308 #endif
309                 /* fd */
310                 tprintf(", %ld, ", u_arg[4]);
311                 /* offset */
312                 tprintf("%#llx", LONG_LONG(u_arg[5], u_arg[6]));
313         }
314         return RVAL_HEX;
315 }
316 #endif
317
318
319 int
320 sys_munmap(tcp)
321 struct tcb *tcp;
322 {
323         if (entering(tcp)) {
324                 tprintf("%#lx, %lu",
325                         tcp->u_arg[0], tcp->u_arg[1]);
326         }
327         return 0;
328 }
329
330 int
331 sys_mprotect(tcp)
332 struct tcb *tcp;
333 {
334         if (entering(tcp)) {
335                 tprintf("%#lx, %lu, ",
336                         tcp->u_arg[0], tcp->u_arg[1]);
337                 if (!printflags(mmap_prot, tcp->u_arg[2]))
338                         tprintf("PROT_???");
339         }
340         return 0;
341 }
342
343 #ifdef LINUX
344
345 static struct xlat mremap_flags[] = {
346         { MREMAP_MAYMOVE,       "MREMAP_MAYMOVE"        },
347         { 0,                    NULL                    }
348 };
349
350 int
351 sys_mremap(tcp)
352 struct tcb *tcp;
353 {
354         if (entering(tcp)) {
355                 tprintf("%#lx, %lu, %lu, ", tcp->u_arg[0], tcp->u_arg[1],
356                         tcp->u_arg[2]);
357                 printflags(mremap_flags, tcp->u_arg[3]);
358         }
359         return RVAL_HEX;
360 }
361
362 static struct xlat madvise_flags[] = {
363 #ifdef MADV_NORMAL
364         { MADV_NORMAL,          "MADV_NORMAL" },
365 #endif
366 #ifdef MADZV_RANDOM
367         { MADV_RANDOM,          "MADV_RANDOM" },
368 #endif
369 #ifdef MADV_SEQUENTIAL
370         { MADV_SEQUENTIAL,      "MADV_SEQUENTIAL" },
371 #endif
372 #ifdef MADV_WILLNEED
373         { MADV_WILLNEED,        "MADV_WILLNEED" },
374 #endif
375 #ifdef MADV_DONTNED
376         { MADV_DONTNEED,        "MADV_DONTNEED" },
377 #endif
378         { 0,                    NULL },
379 };
380
381
382 int
383 sys_madvise(tcp)
384 struct tcb *tcp;
385 {
386         if (entering(tcp)) {
387                 tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
388                 printflags(madvise_flags, tcp->u_arg[2]);
389         }
390         return 0;
391 }
392
393
394 static struct xlat mlockall_flags[] = {
395 #ifdef MCL_CURRENT
396         { MCL_CURRENT,  "MCL_CURRENT" },
397 #endif
398 #ifdef MCL_FUTURE
399         { MCL_FUTURE,   "MCL_FUTURE" },
400 #endif
401         { 0,            NULL}
402 };
403
404 int
405 sys_mlockall(tcp)
406 struct tcb *tcp;
407 {
408         if (entering(tcp)) {
409                 printflags(mlockall_flags, tcp->u_arg[0]);
410         }
411         return 0;
412 }
413
414
415 #endif /* LINUX */
416
417 #ifdef MS_ASYNC
418
419 static struct xlat mctl_sync[] = {
420 #ifdef MS_SYNC
421         { MS_SYNC,      "MS_SYNC"       },
422 #endif
423         { MS_ASYNC,     "MS_ASYNC"      },
424         { MS_INVALIDATE,"MS_INVALIDATE" },
425         { 0,            NULL            },
426 };
427
428 int
429 sys_msync(tcp)
430 struct tcb *tcp;
431 {
432         if (entering(tcp)) {
433                 /* addr */
434                 tprintf("%#lx", tcp->u_arg[0]);
435                 /* len */
436                 tprintf(", %lu, ", tcp->u_arg[1]);
437                 /* flags */
438                 if (!printflags(mctl_sync, tcp->u_arg[2]))
439                         tprintf("MS_???");
440         }
441         return 0;
442 }
443
444 #endif /* MS_ASYNC */
445
446 #ifdef MC_SYNC
447
448 static struct xlat mctl_funcs[] = {
449         { MC_LOCK,      "MC_LOCK"       },
450         { MC_LOCKAS,    "MC_LOCKAS"     },
451         { MC_SYNC,      "MC_SYNC"       },
452         { MC_UNLOCK,    "MC_UNLOCK"     },
453         { MC_UNLOCKAS,  "MC_UNLOCKAS"   },
454         { 0,            NULL            },
455 };
456
457 static struct xlat mctl_lockas[] = {
458         { MCL_CURRENT,  "MCL_CURRENT"   },
459         { MCL_FUTURE,   "MCL_FUTURE"    },
460         { 0,            NULL            },
461 };
462
463 int
464 sys_mctl(tcp)
465 struct tcb *tcp;
466 {
467         int arg, function;
468
469         if (entering(tcp)) {
470                 /* addr */
471                 tprintf("%#lx", tcp->u_arg[0]);
472                 /* len */
473                 tprintf(", %lu, ", tcp->u_arg[1]);
474                 /* function */
475                 function = tcp->u_arg[2];
476                 if (!printflags(mctl_funcs, function))
477                         tprintf("MC_???");
478                 /* arg */
479                 arg = tcp->u_arg[3];
480                 tprintf(", ");
481                 switch (function) {
482                 case MC_SYNC:
483                         if (!printflags(mctl_sync, arg))
484                                 tprintf("MS_???");
485                         break;
486                 case MC_LOCKAS:
487                         if (!printflags(mctl_lockas, arg))
488                                 tprintf("MCL_???");
489                         break;
490                 default:
491                         tprintf("%#x", arg);
492                         break;
493                 }
494         }
495         return 0;
496 }
497
498 #endif /* MC_SYNC */
499
500 int
501 sys_mincore(tcp)
502 struct tcb *tcp;
503 {
504         int i, len;
505         char *vec = NULL;
506
507         if (entering(tcp)) {
508                 tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
509         } else {
510                 len = tcp->u_arg[1];
511                 if (syserror(tcp) || tcp->u_arg[2] == 0 ||
512                         (vec = malloc((u_int)len)) == NULL ||
513                         umoven(tcp, tcp->u_arg[2], len, vec) < 0)
514                         tprintf("%#lx", tcp->u_arg[2]);
515                 else {
516                         tprintf("[");
517                         for (i = 0; i < len; i++) {
518                                 if (abbrev(tcp) && i >= max_strlen) {
519                                         tprintf("...");
520                                         break;
521                                 }
522                                 tprintf((vec[i] & 1) ? "1" : "0");
523                         }
524                         tprintf("]");
525                 }
526                 if (vec)
527                         free(vec);
528         }
529         return 0;
530 }
531
532 int
533 sys_getpagesize(tcp)
534 struct tcb *tcp;
535 {
536         if (exiting(tcp))
537                 return RVAL_HEX;
538         return 0;
539 }
540
541 #if defined(LINUX) && defined(__i386__)
542 void
543 print_ldt_entry (ldt_entry)
544 struct modify_ldt_ldt_s *ldt_entry;
545 {
546         tprintf("base_addr:%#08lx, "
547                 "limit:%d, "
548                 "seg_32bit:%d, "
549                 "contents:%d, "
550                 "read_exec_only:%d, "
551                 "limit_in_pages:%d, "
552                 "seg_not_present:%d, "
553                 "useable:%d}",
554                 ldt_entry->base_addr,
555                 ldt_entry->limit,
556                 ldt_entry->seg_32bit,
557                 ldt_entry->contents,
558                 ldt_entry->read_exec_only,
559                 ldt_entry->limit_in_pages,
560                 ldt_entry->seg_not_present,
561                 ldt_entry->useable);
562 }
563
564 int
565 sys_modify_ldt(tcp)
566 struct tcb *tcp;
567 {
568         if (entering(tcp)) {
569                 struct modify_ldt_ldt_s copy;
570                 tprintf("%ld", tcp->u_arg[0]);
571                 if (tcp->u_arg[1] == 0
572                                 || tcp->u_arg[2] != sizeof (struct modify_ldt_ldt_s)
573                                 || umove(tcp, tcp->u_arg[1], &copy) == -1)
574                         tprintf(", %lx", tcp->u_arg[1]);
575                 else {
576                         tprintf(", {entry_number:%d, ", copy.entry_number);
577                         if (!verbose(tcp))
578                                 tprintf("...}");
579                         else {
580                                 print_ldt_entry(&copy);
581                         }
582                 }
583                 tprintf(", %lu", tcp->u_arg[2]);
584         }
585         return 0;
586 }
587
588 int
589 sys_set_thread_area(tcp)
590 struct tcb *tcp;
591 {
592         struct modify_ldt_ldt_s copy;
593         if (entering(tcp)) {
594                 if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
595                         if (copy.entry_number == -1)
596                                 tprintf("{entry_number:%d -> ",
597                                         copy.entry_number);
598                         else
599                                 tprintf("{entry_number:");
600                 }
601         } else {
602                 if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
603                         tprintf("%d, ", copy.entry_number);
604                         if (!verbose(tcp))
605                                 tprintf("...}");
606                         else {
607                                 print_ldt_entry(&copy);
608                         }
609                 } else {
610                         tprintf("%lx", tcp->u_arg[0]);
611                 }
612         }
613         return 0;
614
615 }
616
617 int
618 sys_get_thread_area(tcp)
619 struct tcb *tcp;
620 {
621         struct modify_ldt_ldt_s copy;
622         if (exiting(tcp)) {
623                 if (umove(tcp, tcp->u_arg[0], &copy) != -1) {
624                         tprintf("{entry_number:%d, ", copy.entry_number);
625                         if (!verbose(tcp))
626                                 tprintf("...}");
627                         else {
628                                 print_ldt_entry(&copy);
629                         }
630                 } else {
631                         tprintf("%lx", tcp->u_arg[0]);
632                 }
633         }
634         return 0;
635
636 }
637 #endif /* LINUX && __i386__ */
638
639 #if defined(LINUX)
640 int
641 sys_remap_file_pages(tcp)
642 struct tcb *tcp;
643 {
644         if (entering(tcp)) {
645                 tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
646                 printflags(mmap_prot, tcp->u_arg[2]);
647                 tprintf(", %lu, ", tcp->u_arg[3]);
648 #ifdef MAP_TYPE
649                 printxval(mmap_flags, tcp->u_arg[4] & MAP_TYPE, "MAP_???");
650                 addflags(mmap_flags, tcp->u_arg[4] & ~MAP_TYPE);
651 #else
652                 printflags(mmap_flags, tcp->u_arg[4]);
653 #endif
654         }
655         return 0;
656 }
657 #endif