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  }