Fix select decoding on e.g. 32-bit ppc process by 64-bit strace.
Added next_set_bit() function which finds the next set bit,
properly taking into account word size of the traced process.
Use it in decode_select() instead of fd_isset().
Also, properly round fdsize up to word size of traced process,
not to strace's word size.
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
diff --git a/desc.c b/desc.c
index 3957226..04f1164 100644
--- a/desc.c
+++ b/desc.c
@@ -477,22 +477,6 @@
}
#endif
-/* FD_ISSET from libc would abort for large fd if built with
- * debug flags/library hacks which enforce array bound checks
- * (fd_set contains a fixed-size array of longs).
- * We need to use a homegrown replacement.
- */
-static inline int
-fd_isset(unsigned fd, fd_set *fds)
-{
- /* Using unsigned types to avoid signed divisions and shifts,
- * which are slow(er) on many CPUs.
- */
- const unsigned bpl = 8 * sizeof(long);
- unsigned long *s = (unsigned long *) fds;
- return s[fd / bpl] & (1UL << (fd % bpl));
-}
-
static int
decode_select(struct tcb *tcp, long *args, enum bitness_t bitness)
{
@@ -518,7 +502,7 @@
* We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
* Instead of args[0], use nfds for fd count, fdsize for array lengths.
*/
- fdsize = (((nfds + 7) / 8) + sizeof(long)-1) & -sizeof(long);
+ fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
if (entering(tcp)) {
tprintf("%d", (int) args[0]);
@@ -543,12 +527,13 @@
continue;
}
tprints(", [");
- for (j = 0, sep = ""; j < nfds; j++) {
- if (fd_isset(j, fds)) {
- tprints(sep);
- printfd(tcp, j);
- sep = " ";
- }
+ for (j = 0, sep = "";; j++) {
+ j = next_set_bit(fds, j, nfds);
+ if (j < 0)
+ break;
+ tprints(sep);
+ printfd(tcp, j);
+ sep = " ";
}
tprints("]");
}
@@ -583,26 +568,27 @@
arg = args[i+1];
if (!arg || umoven(tcp, arg, fdsize, (char *) fds) < 0)
continue;
- for (j = 0; j < nfds; j++) {
- if (fd_isset(j, fds)) {
- /* +2 chars needed at the end: ']',NUL */
- if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
- if (first) {
- outptr += sprintf(outptr, "%s%s [%u",
- sep,
- i == 0 ? "in" : i == 1 ? "out" : "except",
- j
- );
- first = 0;
- sep = ", ";
- }
- else {
- outptr += sprintf(outptr, " %u", j);
- }
+ for (j = 0;; j++) {
+ j = next_set_bit(fds, j, nfds);
+ if (j < 0)
+ break;
+ /* +2 chars needed at the end: ']',NUL */
+ if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
+ if (first) {
+ outptr += sprintf(outptr, "%s%s [%u",
+ sep,
+ i == 0 ? "in" : i == 1 ? "out" : "except",
+ j
+ );
+ first = 0;
+ sep = ", ";
}
- if (--ready_fds == 0)
- break;
+ else {
+ outptr += sprintf(outptr, " %u", j);
+ }
}
+ if (--ready_fds == 0)
+ break;
}
if (outptr != outstr)
*outptr++ = ']';