| #include "defs.h" |
| #include <dirent.h> |
| |
| struct kernel_dirent { |
| unsigned long d_ino; |
| unsigned long d_off; |
| unsigned short d_reclen; |
| char d_name[1]; |
| }; |
| |
| static void |
| print_old_dirent(struct tcb *tcp, long addr) |
| { |
| #ifdef SH64 |
| typedef struct kernel_dirent old_dirent_t; |
| #else |
| typedef struct { |
| uint32_t d_ino; |
| uint32_t d_off; |
| unsigned short d_reclen; |
| char d_name[1]; |
| } old_dirent_t; |
| #endif |
| old_dirent_t d; |
| |
| if (!verbose(tcp) || umove(tcp, addr, &d) < 0) { |
| tprintf("%#lx", addr); |
| return; |
| } |
| |
| tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=\"", |
| (unsigned long) d.d_ino, (unsigned long) d.d_off, d.d_reclen); |
| if (d.d_reclen > 256) |
| d.d_reclen = 256; |
| printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen); |
| tprints("\"}"); |
| } |
| |
| int |
| sys_readdir(struct tcb *tcp) |
| { |
| if (entering(tcp)) { |
| printfd(tcp, tcp->u_arg[0]); |
| tprints(", "); |
| } else { |
| if (syserror(tcp) || tcp->u_rval == 0 || !verbose(tcp)) |
| tprintf("%#lx", tcp->u_arg[1]); |
| else |
| print_old_dirent(tcp, tcp->u_arg[1]); |
| /* Not much point in printing this out, it is always 1. */ |
| if (tcp->u_arg[2] != 1) |
| tprintf(", %lu", tcp->u_arg[2]); |
| } |
| return 0; |
| } |
| |
| #include "xlat/direnttypes.h" |
| |
| int |
| sys_getdents(struct tcb *tcp) |
| { |
| unsigned int i, len, dents = 0; |
| char *buf; |
| |
| if (entering(tcp)) { |
| printfd(tcp, tcp->u_arg[0]); |
| tprints(", "); |
| return 0; |
| } |
| if (syserror(tcp) || !verbose(tcp)) { |
| tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); |
| return 0; |
| } |
| |
| /* Beware of insanely large or too small values in tcp->u_rval */ |
| if (tcp->u_rval > 1024*1024) |
| len = 1024*1024; |
| else if (tcp->u_rval < (int) sizeof(struct kernel_dirent)) |
| len = 0; |
| else |
| len = tcp->u_rval; |
| |
| if (len) { |
| buf = malloc(len); |
| if (!buf) |
| die_out_of_memory(); |
| if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { |
| tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); |
| free(buf); |
| return 0; |
| } |
| } else { |
| buf = NULL; |
| } |
| |
| if (!abbrev(tcp)) |
| tprints("{"); |
| for (i = 0; len && i <= len - sizeof(struct kernel_dirent); ) { |
| struct kernel_dirent *d = (struct kernel_dirent *) &buf[i]; |
| |
| if (!abbrev(tcp)) { |
| int oob = d->d_reclen < sizeof(struct kernel_dirent) || |
| i + d->d_reclen - 1 >= len; |
| int d_name_len = oob ? len - i : d->d_reclen; |
| d_name_len -= offsetof(struct kernel_dirent, d_name) + 1; |
| |
| tprintf("%s{d_ino=%lu, d_off=%lu, ", |
| i ? " " : "", d->d_ino, d->d_off); |
| tprintf("d_reclen=%u, d_name=\"%.*s\", d_type=", |
| d->d_reclen, d_name_len, d->d_name); |
| if (oob) |
| tprints("?"); |
| else |
| printxval(direnttypes, buf[i + d->d_reclen - 1], "DT_???"); |
| tprints("}"); |
| } |
| dents++; |
| if (d->d_reclen < sizeof(struct kernel_dirent)) { |
| tprints("/* d_reclen < sizeof(struct kernel_dirent) */"); |
| break; |
| } |
| i += d->d_reclen; |
| } |
| if (!abbrev(tcp)) |
| tprints("}"); |
| else |
| tprintf("/* %u entries */", dents); |
| tprintf(", %lu", tcp->u_arg[2]); |
| free(buf); |
| return 0; |
| } |
| |
| int |
| sys_getdents64(struct tcb *tcp) |
| { |
| /* the minimum size of a valid dirent64 structure */ |
| const unsigned int d_name_offset = offsetof(struct dirent64, d_name); |
| |
| unsigned int i, len, dents = 0; |
| char *buf; |
| |
| if (entering(tcp)) { |
| printfd(tcp, tcp->u_arg[0]); |
| tprints(", "); |
| return 0; |
| } |
| if (syserror(tcp) || !verbose(tcp)) { |
| tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); |
| return 0; |
| } |
| |
| /* Beware of insanely large or too small tcp->u_rval */ |
| if (tcp->u_rval > 1024*1024) |
| len = 1024*1024; |
| else if (tcp->u_rval < (int) d_name_offset) |
| len = 0; |
| else |
| len = tcp->u_rval; |
| |
| if (len) { |
| buf = malloc(len); |
| if (!buf) |
| die_out_of_memory(); |
| if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) { |
| tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]); |
| free(buf); |
| return 0; |
| } |
| } else { |
| buf = NULL; |
| } |
| |
| if (!abbrev(tcp)) |
| tprints("{"); |
| for (i = 0; len && i <= len - d_name_offset; ) { |
| struct dirent64 *d = (struct dirent64 *) &buf[i]; |
| if (!abbrev(tcp)) { |
| int d_name_len; |
| if (d->d_reclen >= d_name_offset |
| && i + d->d_reclen <= len) { |
| d_name_len = d->d_reclen - d_name_offset; |
| } else { |
| d_name_len = len - i - d_name_offset; |
| } |
| |
| tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64 |
| ", d_reclen=%u, d_type=", |
| i ? " " : "", |
| d->d_ino, |
| d->d_off, |
| d->d_reclen); |
| printxval(direnttypes, d->d_type, "DT_???"); |
| tprintf(", d_name=\"%.*s\"}", |
| d_name_len, d->d_name); |
| } |
| if (d->d_reclen < d_name_offset) { |
| tprints("/* d_reclen < offsetof(struct dirent64, d_name) */"); |
| break; |
| } |
| i += d->d_reclen; |
| dents++; |
| } |
| if (!abbrev(tcp)) |
| tprints("}"); |
| else |
| tprintf("/* %u entries */", dents); |
| tprintf(", %lu", tcp->u_arg[2]); |
| free(buf); |
| return 0; |
| } |