github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/osutil/strace/strace.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package strace 21 22 import ( 23 "fmt" 24 "os/exec" 25 "os/user" 26 "path/filepath" 27 28 "github.com/snapcore/snapd/dirs" 29 "github.com/snapcore/snapd/osutil" 30 ) 31 32 // These syscalls are excluded because they make strace hang on all or 33 // some architectures (gettimeofday on arm64). 34 var excludedSyscalls = "!select,pselect6,_newselect,clock_gettime,sigaltstack,gettid,gettimeofday,nanosleep" 35 36 // Command returns how to run strace in the users context with the 37 // right set of excluded system calls. 38 func Command(extraStraceOpts []string, traceeCmd ...string) (*exec.Cmd, error) { 39 current, err := user.Current() 40 if err != nil { 41 return nil, err 42 } 43 sudoPath, err := exec.LookPath("sudo") 44 if err != nil { 45 return nil, fmt.Errorf("cannot use strace without sudo: %s", err) 46 } 47 48 // Try strace from the snap first, we use new syscalls like 49 // "_newselect" that are known to not work with the strace of e.g. 50 // ubuntu 14.04. 51 // 52 // TODO: some architectures do not have some syscalls (e.g. 53 // s390x does not have _newselect). In 54 // https://github.com/strace/strace/issues/57 options are 55 // discussed. We could use "-e trace=?syscall" but that is 56 // only available since strace 4.17 which is not even in 57 // ubutnu 17.10. 58 var stracePath string 59 cand := filepath.Join(dirs.SnapMountDir, "strace-static", "current", "bin", "strace") 60 if osutil.FileExists(cand) { 61 stracePath = cand 62 } 63 if stracePath == "" { 64 stracePath, err = exec.LookPath("strace") 65 if err != nil { 66 return nil, fmt.Errorf("cannot find an installed strace, please try 'snap install strace-static'") 67 } 68 } 69 70 args := []string{ 71 sudoPath, 72 "-E", 73 stracePath, 74 "-u", current.Username, 75 "-f", 76 "-e", excludedSyscalls, 77 } 78 args = append(args, extraStraceOpts...) 79 args = append(args, traceeCmd...) 80 81 return &exec.Cmd{ 82 Path: sudoPath, 83 Args: args, 84 }, nil 85 } 86 87 // TraceExecCommand returns an exec.Cmd suitable for tracking timings of 88 // execve{,at}() calls 89 func TraceExecCommand(straceLogPath string, origCmd ...string) (*exec.Cmd, error) { 90 extraStraceOpts := []string{"-ttt", "-e", "trace=execve,execveat", "-o", fmt.Sprintf("%s", straceLogPath)} 91 92 return Command(extraStraceOpts, origCmd...) 93 }