]> granicus.if.org Git - strace/blob - dirent.c
Fix ioctl entries on 32-bit architectures with 64-bit aligned structures
[strace] / dirent.c
1 #include "defs.h"
2 #include <dirent.h>
3
4 #define D_NAME_LEN_MAX 256
5
6 struct kernel_dirent {
7         unsigned long   d_ino;
8         unsigned long   d_off;
9         unsigned short  d_reclen;
10         char            d_name[1];
11 };
12
13 static void
14 print_old_dirent(struct tcb *tcp, long addr)
15 {
16 #ifdef SH64
17         typedef struct kernel_dirent old_dirent_t;
18 #else
19         typedef struct {
20                 uint32_t        d_ino;
21                 uint32_t        d_off;
22                 unsigned short  d_reclen;
23                 char            d_name[1];
24         } old_dirent_t;
25 #endif
26         old_dirent_t d;
27
28         if (!verbose(tcp) || umove(tcp, addr, &d) < 0) {
29                 tprintf("%#lx", addr);
30                 return;
31         }
32
33         tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
34                 (unsigned long) d.d_ino, (unsigned long) d.d_off, d.d_reclen);
35         if (d.d_reclen > D_NAME_LEN_MAX)
36                 d.d_reclen = D_NAME_LEN_MAX;
37         printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen);
38         tprints("}");
39 }
40
41 SYS_FUNC(readdir)
42 {
43         if (entering(tcp)) {
44                 printfd(tcp, tcp->u_arg[0]);
45                 tprints(", ");
46         } else {
47                 if (syserror(tcp) || tcp->u_rval == 0 || !verbose(tcp))
48                         tprintf("%#lx", tcp->u_arg[1]);
49                 else
50                         print_old_dirent(tcp, tcp->u_arg[1]);
51                 /* Not much point in printing this out, it is always 1. */
52                 if (tcp->u_arg[2] != 1)
53                         tprintf(", %lu", tcp->u_arg[2]);
54         }
55         return 0;
56 }
57
58 #include "xlat/direnttypes.h"
59
60 SYS_FUNC(getdents)
61 {
62         unsigned int i, len, dents = 0;
63         char *buf;
64
65         if (entering(tcp)) {
66                 printfd(tcp, tcp->u_arg[0]);
67                 tprints(", ");
68                 return 0;
69         }
70         if (syserror(tcp) || !verbose(tcp)) {
71                 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
72                 return 0;
73         }
74
75         /* Beware of insanely large or too small values in tcp->u_rval */
76         if (tcp->u_rval > 1024*1024)
77                 len = 1024*1024;
78         else if (tcp->u_rval < (int) sizeof(struct kernel_dirent))
79                 len = 0;
80         else
81                 len = tcp->u_rval;
82
83         if (len) {
84                 buf = malloc(len);
85                 if (!buf)
86                         die_out_of_memory();
87                 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
88                         tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
89                         free(buf);
90                         return 0;
91                 }
92         } else {
93                 buf = NULL;
94         }
95
96         if (!abbrev(tcp))
97                 tprints("{");
98         for (i = 0; len && i <= len - sizeof(struct kernel_dirent); ) {
99                 struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
100
101                 if (!abbrev(tcp)) {
102                         int oob = d->d_reclen < sizeof(struct kernel_dirent) ||
103                                   i + d->d_reclen - 1 >= len;
104                         int d_name_len = oob ? len - i : d->d_reclen;
105                         d_name_len -= offsetof(struct kernel_dirent, d_name) + 1;
106                         if (d_name_len > D_NAME_LEN_MAX)
107                                 d_name_len = D_NAME_LEN_MAX;
108
109                         tprintf("%s{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
110                                 i ? " " : "", d->d_ino, d->d_off, d->d_reclen);
111
112                         if (print_quoted_string(d->d_name, d_name_len,
113                                                 QUOTE_0_TERMINATED) > 0) {
114                                 tprints("...");
115                         }
116
117                         tprints(", d_type=");
118                         if (oob)
119                                 tprints("?");
120                         else
121                                 printxval(direnttypes, buf[i + d->d_reclen - 1], "DT_???");
122                         tprints("}");
123                 }
124                 dents++;
125                 if (d->d_reclen < sizeof(struct kernel_dirent)) {
126                         tprints("/* d_reclen < sizeof(struct kernel_dirent) */");
127                         break;
128                 }
129                 i += d->d_reclen;
130         }
131         if (!abbrev(tcp))
132                 tprints("}");
133         else
134                 tprintf("/* %u entries */", dents);
135         tprintf(", %lu", tcp->u_arg[2]);
136         free(buf);
137         return 0;
138 }
139
140 SYS_FUNC(getdents64)
141 {
142         /* the minimum size of a valid dirent64 structure */
143         const unsigned int d_name_offset = offsetof(struct dirent64, d_name);
144
145         unsigned int i, len, dents = 0;
146         char *buf;
147
148         if (entering(tcp)) {
149                 printfd(tcp, tcp->u_arg[0]);
150                 tprints(", ");
151                 return 0;
152         }
153         if (syserror(tcp) || !verbose(tcp)) {
154                 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
155                 return 0;
156         }
157
158         /* Beware of insanely large or too small tcp->u_rval */
159         if (tcp->u_rval > 1024*1024)
160                 len = 1024*1024;
161         else if (tcp->u_rval < (int) d_name_offset)
162                 len = 0;
163         else
164                 len = tcp->u_rval;
165
166         if (len) {
167                 buf = malloc(len);
168                 if (!buf)
169                         die_out_of_memory();
170                 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
171                         tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
172                         free(buf);
173                         return 0;
174                 }
175         } else {
176                 buf = NULL;
177         }
178
179         if (!abbrev(tcp))
180                 tprints("{");
181         for (i = 0; len && i <= len - d_name_offset; ) {
182                 struct dirent64 *d = (struct dirent64 *) &buf[i];
183                 if (!abbrev(tcp)) {
184                         int d_name_len;
185                         if (d->d_reclen >= d_name_offset
186                             && i + d->d_reclen <= len) {
187                                 d_name_len = d->d_reclen - d_name_offset;
188                         } else {
189                                 d_name_len = len - i - d_name_offset;
190                         }
191                         if (d_name_len > D_NAME_LEN_MAX)
192                                 d_name_len = D_NAME_LEN_MAX;
193
194                         tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
195                                 ", d_reclen=%u, d_type=",
196                                 i ? " " : "",
197                                 d->d_ino,
198                                 d->d_off,
199                                 d->d_reclen);
200                         printxval(direnttypes, d->d_type, "DT_???");
201
202                         tprints(", d_name=");
203                         if (print_quoted_string(d->d_name, d_name_len,
204                                                 QUOTE_0_TERMINATED) > 0) {
205                                 tprints("...");
206                         }
207
208                         tprints("}");
209                 }
210                 if (d->d_reclen < d_name_offset) {
211                         tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
212                         break;
213                 }
214                 i += d->d_reclen;
215                 dents++;
216         }
217         if (!abbrev(tcp))
218                 tprints("}");
219         else
220                 tprintf("/* %u entries */", dents);
221         tprintf(", %lu", tcp->u_arg[2]);
222         free(buf);
223         return 0;
224 }