github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/pkg/strace/syscall_linux.go (about) 1 // Copyright 2018 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package strace 16 17 import ( 18 "encoding/binary" 19 "fmt" 20 "os" 21 "strconv" 22 "syscall" 23 "time" 24 25 "github.com/u-root/u-root/pkg/abi" 26 "golang.org/x/sys/unix" 27 ) 28 29 func path(t *Tracer, addr Addr) string { 30 path, err := t.ReadString(addr, unix.PathMax) 31 if err != nil { 32 return fmt.Sprintf("%#x (error decoding path: %s)", addr, err) 33 } 34 return fmt.Sprintf("%#x %s", addr, path) 35 } 36 func utimensTimespec(t *Tracer, addr Addr) string { 37 if addr == 0 { 38 return "null" 39 } 40 41 var tim unix.Timespec 42 if _, err := t.Read(addr, &tim); err != nil { 43 return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err) 44 } 45 46 var ns string 47 switch tim.Nsec { 48 case unix.UTIME_NOW: 49 ns = "UTIME_NOW" 50 case unix.UTIME_OMIT: 51 ns = "UTIME_OMIT" 52 default: 53 ns = fmt.Sprintf("%v", tim.Nsec) 54 } 55 return fmt.Sprintf("%#x {sec=%v nsec=%s}", addr, tim.Sec, ns) 56 } 57 58 func timespec(t *Tracer, addr Addr) string { 59 if addr == 0 { 60 return "null" 61 } 62 63 var tim unix.Timespec 64 if _, err := t.Read(addr, &tim); err != nil { 65 return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err) 66 } 67 return fmt.Sprintf("%#x {sec=%v nsec=%v}", addr, tim.Sec, tim.Nsec) 68 } 69 70 func timeval(t *Tracer, addr Addr) string { 71 if addr == 0 { 72 return "null" 73 } 74 75 var tim unix.Timeval 76 if _, err := t.Read(addr, &tim); err != nil { 77 return fmt.Sprintf("%#x (error decoding timeval: %s)", addr, err) 78 } 79 80 return fmt.Sprintf("%#x {sec=%v usec=%v}", addr, tim.Sec, tim.Usec) 81 } 82 83 func utimbuf(t *Tracer, addr Addr) string { 84 if addr == 0 { 85 return "null" 86 } 87 88 var utim syscall.Utimbuf 89 if _, err := t.Read(addr, &utim); err != nil { 90 return fmt.Sprintf("%#x (error decoding utimbuf: %s)", addr, err) 91 } 92 93 return fmt.Sprintf("%#x {actime=%v, modtime=%v}", addr, utim.Actime, utim.Modtime) 94 } 95 96 func fileMode(mode uint32) string { 97 return fmt.Sprintf("%#09o", mode&0x1ff) 98 } 99 100 func stat(t *Tracer, addr Addr) string { 101 if addr == 0 { 102 return "null" 103 } 104 105 var stat unix.Stat_t 106 if _, err := t.Read(addr, &stat); err != nil { 107 return fmt.Sprintf("%#x (error decoding stat: %s)", addr, err) 108 } 109 return fmt.Sprintf("%#x {dev=%d, ino=%d, mode=%s, nlink=%d, uid=%d, gid=%d, rdev=%d, size=%d, blksize=%d, blocks=%d, atime=%s, mtime=%s, ctime=%s}", addr, stat.Dev, stat.Ino, fileMode(stat.Mode), stat.Nlink, stat.Uid, stat.Gid, stat.Rdev, stat.Size, stat.Blksize, stat.Blocks, time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)), time.Unix(int64(stat.Mtim.Sec), int64(stat.Mtim.Nsec)), time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))) 110 } 111 112 func itimerval(t *Tracer, addr Addr) string { 113 if addr == 0 { 114 return "null" 115 } 116 117 interval := timeval(t, addr) 118 value := timeval(t, addr+Addr(binary.Size(unix.Timeval{}))) 119 return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value) 120 } 121 122 func itimerspec(t *Tracer, addr Addr) string { 123 if addr == 0 { 124 return "null" 125 } 126 127 interval := timespec(t, addr) 128 value := timespec(t, addr+Addr(binary.Size(unix.Timespec{}))) 129 return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value) 130 } 131 132 func stringVector(t *Tracer, addr Addr) string { 133 vs, err := t.ReadStringVector(addr, ExecMaxElemSize, ExecMaxTotalSize) 134 if err != nil { 135 return fmt.Sprintf("%#x {error copying vector: %v}", addr, err) 136 } 137 return fmt.Sprintf("%q", vs) 138 /* 139 vec := []string{} 140 s := fmt.Sprintf("%#x [", addr) 141 for i, v := range vec { 142 if i != 0 { 143 s += ", " 144 } 145 s += fmt.Sprintf("%q", v) 146 } 147 s += "]" 148 return s 149 */ 150 } 151 152 func rusage(t *Tracer, addr Addr) string { 153 if addr == 0 { 154 return "null" 155 } 156 157 var ru unix.Rusage 158 if _, err := t.Read(addr, &ru); err != nil { 159 return fmt.Sprintf("%#x (error decoding rusage: %s)", addr, err) 160 } 161 return fmt.Sprintf("%#x %+v", addr, ru) 162 } 163 164 // pre fills in the pre-execution arguments for a system call. If an argument 165 // cannot be interpreted before the system call is executed, then a hex value 166 // will be used. Note that a full output slice will always be provided, that is 167 // len(return) == len(args). 168 func (i *SyscallInfo) pre(t *Tracer, r *TraceRecord, maximumBlobSize uint) []string { 169 var output []string 170 args := r.Args 171 for arg := range args { 172 if arg >= len(i.format) { 173 break 174 } 175 switch i.format[arg] { 176 case WriteBuffer: 177 output = append(output, dump(t, args[arg].Pointer(), args[arg+1].SizeT(), maximumBlobSize)) 178 case WriteIOVec: 179 output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), true /* content */, uint64(maximumBlobSize))) 180 case IOVec: 181 output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), false /* content */, uint64(maximumBlobSize))) 182 case SendMsgHdr: 183 output = append(output, msghdr(t, args[arg].Pointer(), true /* content */, uint64(maximumBlobSize))) 184 case RecvMsgHdr: 185 output = append(output, msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize))) 186 case Path: 187 output = append(output, path(t, args[arg].Pointer())) 188 case ExecveStringVector: 189 output = append(output, stringVector(t, args[arg].Pointer())) 190 case SockAddr: 191 output = append(output, sockAddr(t, args[arg].Pointer(), uint32(args[arg+1].Uint64()))) 192 case SockLen: 193 output = append(output, sockLenPointer(t, args[arg].Pointer())) 194 case SockFamily: 195 output = append(output, abi.SocketFamily.Parse(uint64(args[arg].Int()))) 196 case SockType: 197 output = append(output, abi.SockType(args[arg].Int())) 198 case SockProtocol: 199 output = append(output, abi.SockProtocol(args[arg-2].Int(), args[arg].Int())) 200 case SockFlags: 201 output = append(output, abi.SockFlags(args[arg].Int())) 202 case Timespec: 203 output = append(output, timespec(t, args[arg].Pointer())) 204 case UTimeTimespec: 205 output = append(output, utimensTimespec(t, args[arg].Pointer())) 206 case ItimerVal: 207 output = append(output, itimerval(t, args[arg].Pointer())) 208 case ItimerSpec: 209 output = append(output, itimerspec(t, args[arg].Pointer())) 210 case Timeval: 211 output = append(output, timeval(t, args[arg].Pointer())) 212 case Utimbuf: 213 output = append(output, utimbuf(t, args[arg].Pointer())) 214 case CloneFlags: 215 output = append(output, abi.CloneFlagSet.Parse(uint64(args[arg].Uint()))) 216 case OpenFlags: 217 output = append(output, abi.Open(uint64(args[arg].Uint()))) 218 case Mode: 219 output = append(output, os.FileMode(args[arg].Uint()).String()) 220 case FutexOp: 221 output = append(output, abi.Futex(uint64(args[arg].Uint()))) 222 case PtraceRequest: 223 output = append(output, abi.PtraceRequestSet.Parse(args[arg].Uint64())) 224 case ItimerType: 225 output = append(output, abi.ItimerTypes.Parse(uint64(args[arg].Int()))) 226 case Oct: 227 output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8)) 228 case Hex: 229 fallthrough 230 default: 231 output = append(output, "0x"+strconv.FormatUint(args[arg].Uint64(), 16)) 232 } 233 } 234 235 return output 236 } 237 238 // post fills in the post-execution arguments for a system call. This modifies 239 // the given output slice in place with arguments that may only be interpreted 240 // after the system call has been executed. 241 func (i *SyscallInfo) post(t *Tracer, args SyscallArguments, rval SyscallArgument, output []string, maximumBlobSize uint) { 242 for arg := range output { 243 if arg >= len(i.format) { 244 break 245 } 246 switch i.format[arg] { 247 case ReadBuffer: 248 output[arg] = dump(t, args[arg].Pointer(), uint(rval.Uint64()), maximumBlobSize) 249 case ReadIOVec: 250 printLength := rval.Uint() 251 if printLength > uint32(maximumBlobSize) { 252 printLength = uint32(maximumBlobSize) 253 } 254 output[arg] = iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), true /* content */, uint64(printLength)) 255 case WriteIOVec, IOVec, WriteBuffer: 256 // We already have a big blast from write. 257 output[arg] = "..." 258 case SendMsgHdr: 259 output[arg] = msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize)) 260 case RecvMsgHdr: 261 output[arg] = msghdr(t, args[arg].Pointer(), true /* content */, uint64(maximumBlobSize)) 262 case PostPath: 263 output[arg] = path(t, args[arg].Pointer()) 264 case PipeFDs: 265 output[arg] = fdpair(t, args[arg].Pointer()) 266 case Uname: 267 output[arg] = uname(t, args[arg].Pointer()) 268 case Stat: 269 output[arg] = stat(t, args[arg].Pointer()) 270 case PostSockAddr: 271 output[arg] = postSockAddr(t, args[arg].Pointer(), args[arg+1].Pointer()) 272 case SockLen: 273 output[arg] = sockLenPointer(t, args[arg].Pointer()) 274 case PostTimespec: 275 output[arg] = timespec(t, args[arg].Pointer()) 276 case PostItimerVal: 277 output[arg] = itimerval(t, args[arg].Pointer()) 278 case PostItimerSpec: 279 output[arg] = itimerspec(t, args[arg].Pointer()) 280 case Timeval: 281 output[arg] = timeval(t, args[arg].Pointer()) 282 case Rusage: 283 output[arg] = rusage(t, args[arg].Pointer()) 284 } 285 } 286 } 287 288 // printEntry prints the given system call entry. 289 func (i *SyscallInfo) printEnter(t *Tracer, r *TraceRecord) string { 290 t.output = i.pre(t, r, LogMaximumSize) 291 o := t.output 292 switch len(o) { 293 case 0: 294 return fmt.Sprintf("%s E %s()", t.Name, i.name) 295 case 1: 296 return fmt.Sprintf("%s E %s(%s)", t.Name, i.name, o[0]) 297 case 2: 298 return fmt.Sprintf("%s E %s(%s, %s)", t.Name, i.name, o[0], o[1]) 299 case 3: 300 return fmt.Sprintf("%s E %s(%s, %s, %s)", t.Name, i.name, o[0], o[1], o[2]) 301 case 4: 302 return fmt.Sprintf("%s E %s(%s, %s, %s, %s)", t.Name, i.name, o[0], o[1], o[2], o[3]) 303 case 5: 304 return fmt.Sprintf("%s E %s(%s, %s, %s, %s, %s)", t.Name, i.name, o[0], o[1], o[2], o[3], o[4]) 305 case 6: 306 return fmt.Sprintf("%s E %s(%s, %s, %s, %s, %s, %s)", t.Name, i.name, o[0], o[1], o[2], o[3], o[4], o[5]) 307 default: 308 return fmt.Sprintf("%s E %s(%s, %s, %s, %s, %s, %s, ...)", t.Name, i.name, o[0], o[1], o[2], o[3], o[4], o[5]) 309 } 310 311 } 312 313 func sysCallEnter(t *Tracer, r *TraceRecord) { 314 i := defaultSyscallInfo(r.Sysno) 315 if v, ok := syscalls[uintptr(r.Sysno)]; ok { 316 *i = v 317 } 318 r.Out = i.printEnter(t, r) 319 } 320 321 func sysCallExit(t *Tracer, r *TraceRecord) { 322 i := defaultSyscallInfo(r.Sysno) 323 if v, ok := syscalls[uintptr(r.Sysno)]; ok { 324 *i = v 325 } 326 r.Out = i.printExit(t, r.Time, r.Args, r.Ret[0], r.Err, r.Errno) 327 } 328 329 // SysCall takes a Tracer and a TraceRecord and adds prettyprint to the TraceRecord. 330 func SysCall(t *Tracer, r *TraceRecord) { 331 if r.EX == Enter { 332 sysCallEnter(t, r) 333 return 334 } 335 sysCallExit(t, r) 336 } 337 338 // printExit prints the given system call exit. 339 func (i *SyscallInfo) printExit(t *Tracer, elapsed time.Duration, args SyscallArguments, retval SyscallArgument, err error, errno int) string { 340 o := t.output 341 var rval string 342 if err == nil { 343 // Fill in the output after successful execution. 344 i.post(t, args, retval, o, LogMaximumSize) 345 rval = fmt.Sprintf("%#x (%v)", retval, elapsed) 346 } else { 347 rval = fmt.Sprintf("%#x errno=%d (%s) (%v)", retval, errno, err, elapsed) 348 } 349 350 switch len(o) { 351 case 0: 352 return fmt.Sprintf("%s X %s() = %s", t.Name, i.name, rval) 353 case 1: 354 return fmt.Sprintf("%s X %s(%s) = %s", t.Name, i.name, o[0], rval) 355 case 2: 356 return fmt.Sprintf("%s X %s(%s, %s) = %s", t.Name, i.name, o[0], o[1], rval) 357 case 3: 358 return fmt.Sprintf("%s X %s(%s, %s, %s) = %s", t.Name, i.name, o[0], o[1], o[2], rval) 359 case 4: 360 return fmt.Sprintf("%s X %s(%s, %s, %s, %s) = %s", t.Name, i.name, o[0], o[1], o[2], o[3], rval) 361 case 5: 362 return fmt.Sprintf("%s X %s(%s, %s, %s, %s, %s) = %s", t.Name, i.name, o[0], o[1], o[2], o[3], o[4], rval) 363 case 6: 364 return fmt.Sprintf("%s X %s(%s, %s, %s, %s, %s, %s) = %s", t.Name, i.name, o[0], o[1], o[2], o[3], o[4], o[5], rval) 365 default: 366 return fmt.Sprintf("%s X %s(%s, %s, %s, %s, %s, %s, ...) = %s", t.Name, i.name, o[0], o[1], o[2], o[3], o[4], o[5], rval) 367 } 368 }