github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/strace/syscall_linux.go (about) 1 // Copyright 2018 Google LLC. 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/strace/internal/abi" 26 "golang.org/x/sys/unix" 27 ) 28 29 // Task is a Linux process. 30 type Task interface { 31 // Read reads from the process at Addr to the interface{} 32 // and returns a byte count and error. 33 Read(addr Addr, v interface{}) (int, error) 34 35 // Name is a human-readable process identifier. E.g. PID or argv[0]. 36 Name() string 37 } 38 39 func path(t Task, addr Addr) string { 40 path, err := ReadString(t, addr, unix.PathMax) 41 if err != nil { 42 return fmt.Sprintf("%#x (error decoding path: %s)", addr, err) 43 } 44 return fmt.Sprintf("%#x %s", addr, path) 45 } 46 47 func utimensTimespec(t Task, addr Addr) string { 48 if addr == 0 { 49 return "null" 50 } 51 52 var tim unix.Timespec 53 if _, err := t.Read(addr, &tim); err != nil { 54 return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err) 55 } 56 57 var ns string 58 switch tim.Nsec { 59 case unix.UTIME_NOW: 60 ns = "UTIME_NOW" 61 case unix.UTIME_OMIT: 62 ns = "UTIME_OMIT" 63 default: 64 ns = fmt.Sprintf("%v", tim.Nsec) 65 } 66 return fmt.Sprintf("%#x {sec=%v nsec=%s}", addr, tim.Sec, ns) 67 } 68 69 func timespec(t Task, addr Addr) string { 70 if addr == 0 { 71 return "null" 72 } 73 74 var tim unix.Timespec 75 if _, err := t.Read(addr, &tim); err != nil { 76 return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err) 77 } 78 return fmt.Sprintf("%#x {sec=%v nsec=%v}", addr, tim.Sec, tim.Nsec) 79 } 80 81 func timeval(t Task, addr Addr) string { 82 if addr == 0 { 83 return "null" 84 } 85 86 var tim unix.Timeval 87 if _, err := t.Read(addr, &tim); err != nil { 88 return fmt.Sprintf("%#x (error decoding timeval: %s)", addr, err) 89 } 90 91 return fmt.Sprintf("%#x {sec=%v usec=%v}", addr, tim.Sec, tim.Usec) 92 } 93 94 func utimbuf(t Task, addr Addr) string { 95 if addr == 0 { 96 return "null" 97 } 98 99 var utim syscall.Utimbuf 100 if _, err := t.Read(addr, &utim); err != nil { 101 return fmt.Sprintf("%#x (error decoding utimbuf: %s)", addr, err) 102 } 103 104 return fmt.Sprintf("%#x {actime=%v, modtime=%v}", addr, utim.Actime, utim.Modtime) 105 } 106 107 func fileMode(mode uint32) string { 108 return fmt.Sprintf("%#09o", mode&0x1ff) 109 } 110 111 func stat(t Task, addr Addr) string { 112 if addr == 0 { 113 return "null" 114 } 115 116 var stat unix.Stat_t 117 if _, err := t.Read(addr, &stat); err != nil { 118 return fmt.Sprintf("%#x (error decoding stat: %s)", addr, err) 119 } 120 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))) 121 } 122 123 func itimerval(t Task, addr Addr) string { 124 if addr == 0 { 125 return "null" 126 } 127 128 interval := timeval(t, addr) 129 value := timeval(t, addr+Addr(binary.Size(unix.Timeval{}))) 130 return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value) 131 } 132 133 func itimerspec(t Task, addr Addr) string { 134 if addr == 0 { 135 return "null" 136 } 137 138 interval := timespec(t, addr) 139 value := timespec(t, addr+Addr(binary.Size(unix.Timespec{}))) 140 return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value) 141 } 142 143 func stringVector(t Task, addr Addr) string { 144 vs, err := ReadStringVector(t, addr, ExecMaxElemSize, ExecMaxTotalSize) 145 if err != nil { 146 return fmt.Sprintf("%#x {error copying vector: %v}", addr, err) 147 } 148 return fmt.Sprintf("%q", vs) 149 } 150 151 func rusage(t Task, addr Addr) string { 152 if addr == 0 { 153 return "null" 154 } 155 156 var ru unix.Rusage 157 if _, err := t.Read(addr, &ru); err != nil { 158 return fmt.Sprintf("%#x (error decoding rusage: %s)", addr, err) 159 } 160 return fmt.Sprintf("%#x %+v", addr, ru) 161 } 162 163 // pre fills in the pre-execution arguments for a system call. If an argument 164 // cannot be interpreted before the system call is executed, then a hex value 165 // will be used. Note that a full output slice will always be provided, that is 166 // len(return) == len(args). 167 func (i *SyscallInfo) pre(t Task, args SyscallArguments, maximumBlobSize uint) []string { 168 var output []string 169 for arg := range args { 170 if arg >= len(i.format) { 171 break 172 } 173 switch i.format[arg] { 174 case WriteBuffer: 175 output = append(output, dump(t, args[arg].Pointer(), args[arg+1].SizeT(), maximumBlobSize)) 176 case WriteIOVec: 177 output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), true /* content */, uint64(maximumBlobSize))) 178 case IOVec: 179 output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), false /* content */, uint64(maximumBlobSize))) 180 case SendMsgHdr: 181 output = append(output, msghdr(t, args[arg].Pointer(), true /* content */, uint64(maximumBlobSize))) 182 case RecvMsgHdr: 183 output = append(output, msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize))) 184 case Path: 185 output = append(output, path(t, args[arg].Pointer())) 186 case ExecveStringVector: 187 output = append(output, stringVector(t, args[arg].Pointer())) 188 case SockAddr: 189 output = append(output, sockAddr(t, args[arg].Pointer(), uint32(args[arg+1].Uint64()))) 190 case SockLen: 191 output = append(output, sockLenPointer(t, args[arg].Pointer())) 192 case SockFamily: 193 output = append(output, abi.SocketFamily.Parse(uint64(args[arg].Int()))) 194 case SockType: 195 output = append(output, abi.SockType(args[arg].Int())) 196 case SockProtocol: 197 output = append(output, abi.SockProtocol(args[arg-2].Int(), args[arg].Int())) 198 case SockFlags: 199 output = append(output, abi.SockFlags(args[arg].Int())) 200 case Timespec: 201 output = append(output, timespec(t, args[arg].Pointer())) 202 case UTimeTimespec: 203 output = append(output, utimensTimespec(t, args[arg].Pointer())) 204 case ItimerVal: 205 output = append(output, itimerval(t, args[arg].Pointer())) 206 case ItimerSpec: 207 output = append(output, itimerspec(t, args[arg].Pointer())) 208 case Timeval: 209 output = append(output, timeval(t, args[arg].Pointer())) 210 case Utimbuf: 211 output = append(output, utimbuf(t, args[arg].Pointer())) 212 case CloneFlags: 213 output = append(output, abi.CloneFlagSet.Parse(uint64(args[arg].Uint()))) 214 case OpenFlags: 215 output = append(output, abi.Open(uint64(args[arg].Uint()))) 216 case Mode: 217 output = append(output, os.FileMode(args[arg].Uint()).String()) 218 case FutexOp: 219 output = append(output, abi.Futex(uint64(args[arg].Uint()))) 220 case PtraceRequest: 221 output = append(output, abi.PtraceRequestSet.Parse(args[arg].Uint64())) 222 case ItimerType: 223 output = append(output, abi.ItimerTypes.Parse(uint64(args[arg].Int()))) 224 case Oct: 225 output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8)) 226 case Hex: 227 fallthrough 228 default: 229 output = append(output, "0x"+strconv.FormatUint(args[arg].Uint64(), 16)) 230 } 231 } 232 233 return output 234 } 235 236 // post fills in the post-execution arguments for a system call. This modifies 237 // the given output slice in place with arguments that may only be interpreted 238 // after the system call has been executed. 239 func (i *SyscallInfo) post(t Task, args SyscallArguments, rval SyscallArgument, output []string, maximumBlobSize uint) { 240 for arg := range output { 241 if arg >= len(i.format) { 242 break 243 } 244 switch i.format[arg] { 245 case ReadBuffer: 246 output[arg] = dump(t, args[arg].Pointer(), uint(rval.Uint64()), maximumBlobSize) 247 case ReadIOVec: 248 printLength := rval.Uint() 249 if printLength > uint32(maximumBlobSize) { 250 printLength = uint32(maximumBlobSize) 251 } 252 output[arg] = iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), true /* content */, uint64(printLength)) 253 case WriteIOVec, IOVec, WriteBuffer: 254 // We already have a big blast from write. 255 output[arg] = "..." 256 case SendMsgHdr: 257 output[arg] = msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize)) 258 case RecvMsgHdr: 259 output[arg] = msghdr(t, args[arg].Pointer(), true /* content */, uint64(maximumBlobSize)) 260 case PostPath: 261 output[arg] = path(t, args[arg].Pointer()) 262 case PipeFDs: 263 output[arg] = fdpair(t, args[arg].Pointer()) 264 case Uname: 265 output[arg] = uname(t, args[arg].Pointer()) 266 case Stat: 267 output[arg] = stat(t, args[arg].Pointer()) 268 case PostSockAddr: 269 output[arg] = postSockAddr(t, args[arg].Pointer(), args[arg+1].Pointer()) 270 case SockLen: 271 output[arg] = sockLenPointer(t, args[arg].Pointer()) 272 case PostTimespec: 273 output[arg] = timespec(t, args[arg].Pointer()) 274 case PostItimerVal: 275 output[arg] = itimerval(t, args[arg].Pointer()) 276 case PostItimerSpec: 277 output[arg] = itimerspec(t, args[arg].Pointer()) 278 case Timeval: 279 output[arg] = timeval(t, args[arg].Pointer()) 280 case Rusage: 281 output[arg] = rusage(t, args[arg].Pointer()) 282 } 283 } 284 } 285 286 // printEntry prints the given system call entry. 287 func (i *SyscallInfo) printEnter(t Task, args SyscallArguments) string { 288 o := i.pre(t, args, LogMaximumSize) 289 switch len(o) { 290 case 0: 291 return fmt.Sprintf("%s E %s()", t.Name(), i.name) 292 case 1: 293 return fmt.Sprintf("%s E %s(%s)", t.Name(), i.name, o[0]) 294 case 2: 295 return fmt.Sprintf("%s E %s(%s, %s)", t.Name(), i.name, o[0], o[1]) 296 case 3: 297 return fmt.Sprintf("%s E %s(%s, %s, %s)", t.Name(), i.name, o[0], o[1], o[2]) 298 case 4: 299 return fmt.Sprintf("%s E %s(%s, %s, %s, %s)", t.Name(), i.name, o[0], o[1], o[2], o[3]) 300 case 5: 301 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]) 302 case 6: 303 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]) 304 default: 305 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]) 306 } 307 308 } 309 310 func SysCallEnter(t Task, s *SyscallEvent) string { 311 i := defaultSyscallInfo(s.Sysno) 312 if v, ok := syscalls[uintptr(s.Sysno)]; ok { 313 *i = v 314 } 315 return i.printEnter(t, s.Args) 316 } 317 318 func SysCallExit(t Task, s *SyscallEvent) string { 319 i := defaultSyscallInfo(s.Sysno) 320 if v, ok := syscalls[uintptr(s.Sysno)]; ok { 321 *i = v 322 } 323 return i.printExit(t, s.Duration, s.Args, s.Ret[0], s.Errno) 324 } 325 326 // printExit prints the given system call exit. 327 func (i *SyscallInfo) printExit(t Task, elapsed time.Duration, args SyscallArguments, retval SyscallArgument, errno unix.Errno) string { 328 // Eventually, we'll be able to cache o and look at the entry record's output. 329 o := i.pre(t, args, LogMaximumSize) 330 var rval string 331 if errno == 0 { 332 // Fill in the output after successful execution. 333 i.post(t, args, retval, o, LogMaximumSize) 334 rval = fmt.Sprintf("%#x (%v)", retval.Uint64(), elapsed) 335 } else { 336 rval = fmt.Sprintf("%s (%#x) (%v)", errno, errno, elapsed) 337 } 338 339 switch len(o) { 340 case 0: 341 return fmt.Sprintf("%s X %s() = %s", t.Name(), i.name, rval) 342 case 1: 343 return fmt.Sprintf("%s X %s(%s) = %s", t.Name(), i.name, o[0], rval) 344 case 2: 345 return fmt.Sprintf("%s X %s(%s, %s) = %s", t.Name(), i.name, o[0], o[1], rval) 346 case 3: 347 return fmt.Sprintf("%s X %s(%s, %s, %s) = %s", t.Name(), i.name, o[0], o[1], o[2], rval) 348 case 4: 349 return fmt.Sprintf("%s X %s(%s, %s, %s, %s) = %s", t.Name(), i.name, o[0], o[1], o[2], o[3], rval) 350 case 5: 351 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) 352 case 6: 353 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) 354 default: 355 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) 356 } 357 }