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  }