]> granicus.if.org Git - strace/blob - sg_io_v3.c
clone: fix print_tls_arg on x86
[strace] / sg_io_v3.c
1 /*
2  * Copyright (c) 2007 Vladimir Nadvornik <nadvornik@suse.cz>
3  * Copyright (c) 2007-2018 Dmitry V. Levin <ldv@altlinux.org>
4  * Copyright (c) 2015 Bart Van Assche <bart.vanassche@sandisk.com>
5  * All rights reserved.
6  *
7  * SPDX-License-Identifier: LGPL-2.1-or-later
8  */
9
10 #include "defs.h"
11
12 #ifdef HAVE_SCSI_SG_H
13
14 # include DEF_MPERS_TYPE(struct_sg_io_hdr)
15
16 # include <scsi/sg.h>
17
18 typedef struct sg_io_hdr struct_sg_io_hdr;
19
20 #endif /* HAVE_SCSI_SG_H */
21
22 #include MPERS_DEFS
23
24 #include "xlat/sg_io_info.h"
25
26 #ifdef HAVE_SCSI_SG_H
27 # include "print_fields.h"
28 # include "xlat/sg_io_dxfer_direction.h"
29 # include "xlat/sg_io_flags.h"
30
31 static void
32 print_sg_io_buffer(struct tcb *const tcp, const kernel_ulong_t addr,
33                    const unsigned int data_size, const unsigned int iovec_count)
34 {
35         if (iovec_count) {
36                 tprint_iov_upto(tcp, iovec_count, addr, IOV_DECODE_STR,
37                                 data_size);
38         } else {
39                 printstr_ex(tcp, addr, data_size, QUOTE_FORCE_HEX);
40         }
41 }
42
43 # define PRINT_FIELD_SG_IO_BUFFER(prefix_, where_, field_, size_, count_, tcp_) \
44         do {                                                                    \
45                 STRACE_PRINTF("%s%s=", (prefix_), #field_);                     \
46                 print_sg_io_buffer((tcp_), (mpers_ptr_t)((where_).field_),      \
47                                    (size_), (count_));                          \
48         } while (0)
49
50 static int
51 decode_request(struct tcb *const tcp, const kernel_ulong_t arg)
52 {
53         struct_sg_io_hdr sg_io;
54         static const size_t skip_iid =
55                 offsetof(struct_sg_io_hdr, dxfer_direction);
56
57         tprints("{interface_id='S', ");
58         if (umoven_or_printaddr(tcp, arg + skip_iid, sizeof(sg_io) - skip_iid,
59                                 &sg_io.dxfer_direction)) {
60                 tprints("}");
61                 return RVAL_IOCTL_DECODED;
62         }
63
64         PRINT_FIELD_XVAL("", sg_io, dxfer_direction, sg_io_dxfer_direction,
65                          "SG_DXFER_???");
66         PRINT_FIELD_U(", ", sg_io, cmd_len);
67         PRINT_FIELD_SG_IO_BUFFER(", ", sg_io, cmdp, sg_io.cmd_len, 0, tcp);
68         PRINT_FIELD_U(", ", sg_io, mx_sb_len);
69         PRINT_FIELD_U(", ", sg_io, iovec_count);
70         PRINT_FIELD_U(", ", sg_io, dxfer_len);
71         PRINT_FIELD_U(", ", sg_io, timeout);
72         PRINT_FIELD_FLAGS(", ", sg_io, flags, sg_io_flags, "SG_FLAG_???");
73
74         if (sg_io.dxfer_direction == SG_DXFER_TO_DEV ||
75             sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
76                 PRINT_FIELD_SG_IO_BUFFER(", ", sg_io, dxferp, sg_io.dxfer_len, sg_io.iovec_count, tcp);
77         }
78
79         struct_sg_io_hdr *entering_sg_io = malloc(sizeof(*entering_sg_io));
80         if (entering_sg_io) {
81                 memcpy(entering_sg_io, &sg_io, sizeof(sg_io));
82                 entering_sg_io->interface_id = (unsigned char) 'S';
83                 set_tcb_priv_data(tcp, entering_sg_io, free);
84         }
85
86         return 0;
87 }
88
89 static int
90 decode_response(struct tcb *const tcp, const kernel_ulong_t arg)
91 {
92         struct_sg_io_hdr *entering_sg_io = get_tcb_priv_data(tcp);
93         struct_sg_io_hdr sg_io;
94
95         if (umove(tcp, arg, &sg_io) < 0) {
96                 /* print i/o fields fetched on entering syscall */
97                 if (entering_sg_io->dxfer_direction == SG_DXFER_FROM_DEV)
98                         PRINT_FIELD_PTR(", ", *entering_sg_io, dxferp);
99                 PRINT_FIELD_PTR(", ", *entering_sg_io, sbp);
100                 return RVAL_IOCTL_DECODED;
101         }
102
103         if (sg_io.interface_id != entering_sg_io->interface_id) {
104                 PRINT_FIELD_U(" => ", sg_io, interface_id);
105                 return RVAL_IOCTL_DECODED;
106         }
107
108         if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV ||
109             sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
110                 uint32_t din_len = sg_io.dxfer_len;
111                 const char *prefix = NULL;
112
113                 if (sg_io.resid > 0 && (unsigned int) sg_io.resid <= din_len)
114                         din_len -= sg_io.resid;
115
116                 if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV)
117                         prefix = ", ";
118                 else if (din_len)
119                         prefix = " => ";
120
121                 if (prefix) {
122                         tprints(prefix);
123                         PRINT_FIELD_SG_IO_BUFFER("", sg_io, dxferp, din_len,
124                                                  sg_io.iovec_count, tcp);
125                 }
126         }
127         PRINT_FIELD_X(", ", sg_io, status);
128         PRINT_FIELD_X(", ", sg_io, masked_status);
129         PRINT_FIELD_X(", ", sg_io, msg_status);
130         PRINT_FIELD_U(", ", sg_io, sb_len_wr);
131         PRINT_FIELD_SG_IO_BUFFER(", ", sg_io, sbp, sg_io.sb_len_wr, 0, tcp);
132         PRINT_FIELD_X(", ", sg_io, host_status);
133         PRINT_FIELD_X(", ", sg_io, driver_status);
134         PRINT_FIELD_D(", ", sg_io, resid);
135         PRINT_FIELD_U(", ", sg_io, duration);
136         PRINT_FIELD_FLAGS(", ", sg_io, info, sg_io_info, "SG_INFO_???");
137
138         return RVAL_IOCTL_DECODED;
139 }
140
141 #else /* !HAVE_SCSI_SG_H */
142
143 static int
144 decode_request(struct tcb *const tcp, const kernel_ulong_t arg)
145 {
146         tprints("{interface_id='S', ...}");
147         return RVAL_IOCTL_DECODED;
148 }
149
150 static int
151 decode_response(struct tcb *const tcp, const kernel_ulong_t arg)
152 {
153         return 0;
154 }
155
156 #endif
157
158 MPERS_PRINTER_DECL(int, decode_sg_io_v3,
159                    struct tcb *const tcp, const kernel_ulong_t arg)
160 {
161         return entering(tcp) ? decode_request(tcp, arg)
162                              : decode_response(tcp, arg);
163 }