From: Dmitry V. Levin Date: Sun, 8 Jan 2017 17:43:21 +0000 (+0000) Subject: sg_io: decode structures on exiting syscall in case of syserror X-Git-Tag: v4.16~65 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=84ecd6365189cca5b2402546df4d92e388a1611c;p=strace sg_io: decode structures on exiting syscall in case of syserror The SCSI driver, starting with kernel commit v2.6.25-rc1~1230^2~78, translates its "struct request.errors" to ioctl errors after filling in all the output members of the SG_IO header structure. As there is no easy way to tell SCSI layer errors from other syscall errors, decode the structure on exiting syscall in case of syserror, too. * scsi.c (scsi_ioctl): Do not call set_tcb_priv_ulong, use get_tcb_priv_data instead of get_tcb_priv_ulong, call decode_sg_io unconditionally. * sg_io_v3.c (decode_request): Save a copy of struct_sg_io_hdr using set_tcb_priv_data. (decode_response): Restore it using get_tcb_priv_data. Print its i/o fields when umove call fails. Pass IOV_DECODE_STR to tprint_iov_upto unconditionally. * sg_io_v4.c (decode_request): Save a copy of struct sg_io_v4 using set_tcb_priv_data. (decode_response): Restore it using get_tcb_priv_data. Print its i/o fields when umove call fails. Pass IOV_DECODE_STR to tprint_iov_upto unconditionally. --- diff --git a/scsi.c b/scsi.c index 3e90d91c..2f93de1e 100644 --- a/scsi.c +++ b/scsi.c @@ -56,24 +56,22 @@ int scsi_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg) { - uint32_t iid; - if (SG_IO != code) return RVAL_DECODED; if (entering(tcp)) { + uint32_t iid; + tprints(", "); if (umove_or_printaddr(tcp, arg, &iid)) { return RVAL_DECODED | 1; } else { - set_tcb_priv_ulong(tcp, iid); return decode_sg_io(tcp, iid, arg); } } else { - if (!syserror(tcp)) { - iid = get_tcb_priv_ulong(tcp); - decode_sg_io(tcp, iid, arg); - } + uint32_t *piid = get_tcb_priv_data(tcp); + if (piid) + decode_sg_io(tcp, *piid, arg); tprints("}"); return RVAL_DECODED | 1; } diff --git a/sg_io_v3.c b/sg_io_v3.c index 18a00584..2c1045c5 100644 --- a/sg_io_v3.c +++ b/sg_io_v3.c @@ -92,20 +92,35 @@ decode_request(struct tcb *const tcp, const kernel_ulong_t arg) print_sg_io_buffer(tcp, ptr_to_kulong(sg_io.dxferp), sg_io.dxfer_len); } + + struct_sg_io_hdr *entering_sg_io = malloc(sizeof(*entering_sg_io)); + if (entering_sg_io) { + memcpy(entering_sg_io, &sg_io, sizeof(sg_io)); + entering_sg_io->interface_id = (unsigned char) 'S'; + set_tcb_priv_data(tcp, entering_sg_io, free); + } + return 1; } static int decode_response(struct tcb *const tcp, const kernel_ulong_t arg) { + struct_sg_io_hdr *entering_sg_io = get_tcb_priv_data(tcp); struct_sg_io_hdr sg_io; if (umove(tcp, arg, &sg_io) < 0) { - tprints(", ???"); + /* print i/o fields fetched on entering syscall */ + if (entering_sg_io->dxfer_direction == SG_DXFER_FROM_DEV) { + tprints(", dxferp="); + printaddr(ptr_to_kulong(entering_sg_io->dxferp)); + } + tprints(", sbp="); + printaddr(ptr_to_kulong(entering_sg_io->sbp)); return RVAL_DECODED | 1; } - if (sg_io.interface_id != (unsigned char) 'S') { + if (sg_io.interface_id != entering_sg_io->interface_id) { tprintf(" => interface_id=%u", sg_io.interface_id); return RVAL_DECODED | 1; } @@ -114,17 +129,22 @@ decode_response(struct tcb *const tcp, const kernel_ulong_t arg) sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) { uint32_t din_len = sg_io.dxfer_len; - if (sg_io.resid > 0) + if (sg_io.resid > 0 && (unsigned int) sg_io.resid <= din_len) din_len -= sg_io.resid; - tprints(", dxferp="); - if (sg_io.iovec_count) - tprint_iov_upto(tcp, sg_io.iovec_count, - ptr_to_kulong(sg_io.dxferp), - syserror(tcp) ? IOV_DECODE_ADDR : - IOV_DECODE_STR, din_len); - else - print_sg_io_buffer(tcp, ptr_to_kulong(sg_io.dxferp), - din_len); + if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV) { + tprints(", dxferp="); + } else if (din_len) { + tprints(" => dxferp="); + } + if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV || din_len) { + if (sg_io.iovec_count) + tprint_iov_upto(tcp, sg_io.iovec_count, + ptr_to_kulong(sg_io.dxferp), + IOV_DECODE_STR, din_len); + else + print_sg_io_buffer(tcp, ptr_to_kulong(sg_io.dxferp), + din_len); + } } tprintf(", status=%#x", sg_io.status); tprintf(", masked_status=%#x", sg_io.masked_status); diff --git a/sg_io_v4.c b/sg_io_v4.c index 4563ff55..c1ef38cd 100644 --- a/sg_io_v4.c +++ b/sg_io_v4.c @@ -82,21 +82,34 @@ decode_request(struct tcb *const tcp, const kernel_ulong_t arg) tprints(", flags="); printflags(bsg_flags, sg_io.flags, "BSG_FLAG_???"); tprintf(", usr_ptr=%#" PRI__x64, sg_io.usr_ptr); + + struct sg_io_v4 *entering_sg_io = malloc(sizeof(*entering_sg_io)); + if (entering_sg_io) { + memcpy(entering_sg_io, &sg_io, sizeof(sg_io)); + entering_sg_io->guard = (unsigned char) 'Q'; + set_tcb_priv_data(tcp, entering_sg_io, free); + } + return 1; } static int decode_response(struct tcb *const tcp, const kernel_ulong_t arg) { + struct sg_io_v4 *entering_sg_io = get_tcb_priv_data(tcp); struct sg_io_v4 sg_io; uint32_t din_len; if (umove(tcp, arg, &sg_io) < 0) { - tprints(", ???"); + /* print i/o fields fetched on entering syscall */ + tprints(", response="); + printaddr(entering_sg_io->response); + tprints(", din_xferp="); + printaddr(entering_sg_io->din_xferp); return RVAL_DECODED | 1; } - if (sg_io.guard != (unsigned char) 'Q') { + if (sg_io.guard != entering_sg_io->guard) { tprintf(" => guard=%u", sg_io.guard); return RVAL_DECODED | 1; } @@ -104,12 +117,11 @@ decode_response(struct tcb *const tcp, const kernel_ulong_t arg) tprintf(", response_len=%u, response=", sg_io.response_len); print_sg_io_buffer(tcp, sg_io.response, sg_io.response_len); din_len = sg_io.din_xfer_len; - if (sg_io.din_resid > 0) + if (sg_io.din_resid > 0 && (unsigned int) sg_io.din_resid <= din_len) din_len -= sg_io.din_resid; tprints(", din_xferp="); if (sg_io.din_iovec_count) tprint_iov_upto(tcp, sg_io.din_iovec_count, sg_io.din_xferp, - syserror(tcp) ? IOV_DECODE_ADDR : IOV_DECODE_STR, din_len); else print_sg_io_buffer(tcp, sg_io.din_xferp, din_len);