├── .github
└── workflows
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .goreleaser.yml
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── compare.png
├── demo.gif
├── filter
└── filter.go
├── go.mod
├── go.sum
├── main.go
├── printer
├── arg.go
├── array.go
├── colours.go
├── error.go
├── hexdump.go
├── object.go
├── printer.go
├── signal.go
└── syscall.go
├── summary.go
├── summary.png
├── testdata
├── execve
│ └── main.go
└── pipe
│ └── main.go
├── tracer
├── annotation
│ ├── access.go
│ ├── arch_prctl.go
│ ├── arg.go
│ ├── bpf.go
│ ├── clockid.go
│ ├── clone.go
│ ├── closerange.go
│ ├── control.go
│ ├── device.go
│ ├── dirent.go
│ ├── epoll.go
│ ├── error.go
│ ├── eventfd.go
│ ├── fadvice.go
│ ├── fallocate.go
│ ├── fanotify.go
│ ├── fcntl.go
│ ├── fd.go
│ ├── flock.go
│ ├── futex.go
│ ├── hex.go
│ ├── ioprio.go
│ ├── ioring.go
│ ├── kcmp.go
│ ├── kexec.go
│ ├── key.go
│ ├── keyring.go
│ ├── landlock.go
│ ├── madvise.go
│ ├── mbind.go
│ ├── membarrier.go
│ ├── memfd.go
│ ├── mlock.go
│ ├── mmap.go
│ ├── module.go
│ ├── mount.go
│ ├── mremap.go
│ ├── msg.go
│ ├── msync.go
│ ├── null.go
│ ├── open.go
│ ├── p2.go
│ ├── perf.go
│ ├── pkey.go
│ ├── prctl.go
│ ├── priority.go
│ ├── prot.go
│ ├── ptrace.go
│ ├── quotactl.go
│ ├── random.go
│ ├── reboot.go
│ ├── rlimit.go
│ ├── rusage.go
│ ├── sched.go
│ ├── seccomp.go
│ ├── sem.go
│ ├── shm.go
│ ├── shutdown.go
│ ├── signal.go
│ ├── sigstack.go
│ ├── socket.go
│ ├── splice.go
│ ├── statx.go
│ ├── syncfilerange.go
│ ├── syslog.go
│ ├── time.go
│ ├── timer.go
│ ├── wait.go
│ ├── whence.go
│ └── x.go
├── args.go
├── decode.go
├── decode_uint_test.go
├── netw
│ ├── netw.go
│ └── proc.go
├── signal.go
├── sys.go
├── sys_amd64.go
├── sys_arm64.go
├── sys_test.go
├── tracer.go
├── type.go
├── type_test.go
├── types_cap.go
├── types_cloneargs.go
├── types_data.go
├── types_epollevent.go
├── types_error.go
├── types_fdset.go
├── types_int.go
├── types_int_ptr.go
├── types_iocb.go
├── types_ioevents.go
├── types_iouring.go
├── types_iovec.go
├── types_itimerspec.go
├── types_itimerval.go
├── types_landlock.go
├── types_mountattr.go
├── types_mqattr.go
├── types_msghdr.go
├── types_openhow.go
├── types_pollfd.go
├── types_rlimit.go
├── types_rusage.go
├── types_schedattr.go
├── types_schedparam.go
├── types_sembuf.go
├── types_shmidds.go
├── types_sigaction.go
├── types_siginfo.go
├── types_sockaddr.go
├── types_sockoptval.go
├── types_stack.go
├── types_stat.go
├── types_statfs.go
├── types_statx.go
├── types_string.go
├── types_sysinfo.go
├── types_timespec.go
├── types_timeval.go
├── types_timex.go
├── types_timezone.go
├── types_tms.go
├── types_uname.go
├── types_userdesc.go
├── types_ustat.go
├── types_utimbuf.go
└── types_waitstatus.go
└── ux.png
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | push:
5 | tags:
6 | - v*
7 |
8 | jobs:
9 | build:
10 | name: releasing
11 | runs-on: ubuntu-22.04
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 | with:
16 | fetch-depth: 0
17 |
18 | - uses: actions/setup-go@v3
19 | with:
20 | go-version: "1.19"
21 | - uses: goreleaser/goreleaser-action@v3
22 | with:
23 | version: latest
24 | args: release --rm-dist
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 | on:
3 | push:
4 | branches:
5 | - main
6 | pull_request:
7 | jobs:
8 | test:
9 | name: tests
10 | runs-on: ${{ matrix.os }}
11 | strategy:
12 | matrix:
13 | os: [ ubuntu-latest ]
14 |
15 | steps:
16 | - uses: actions/checkout@v3
17 | - uses: actions/setup-go@v3
18 | with:
19 | go-version: '1.19'
20 | cache: true
21 | - name: Run tests
22 | run: make test
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | /grace
3 | /dist
4 | /linux
5 | /headers
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | before:
2 | hooks:
3 | - make headers
4 |
5 | builds:
6 | - id: grace
7 | main: .
8 | binary: grace
9 | ldflags:
10 | - "-linkmode external -s -w -extldflags '-fno-PIC -static'"
11 | env:
12 | - CGO_ENABLED=1
13 | - CGO_CFLAGS="-Iheaders/include"
14 | goos:
15 | - linux
16 | goarch:
17 | - "amd64"
18 | changelog:
19 | sort: asc
20 | filters:
21 | exclude:
22 | - "^docs:"
23 | - "^test:"
24 |
25 | archives:
26 | - format: binary
27 | name_template: "{{ .Binary}}-{{ .Os }}-{{ .Arch }}"
28 |
29 | release:
30 | prerelease: auto
31 | github:
32 | owner: liamg
33 | name: grace
34 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Useful Links
4 |
5 | - [List of syscalls with descriptions](https://linuxhint.com/list_of_linux_syscalls/)
6 | - [Syscall table](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md)
7 | - [Another Syscall table](https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/)
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04
2 |
3 | RUN apt-get update -y && apt-get install -y git build-essential golang ca-certificates rsync
4 | RUN git clone --depth 1 https://github.com/torvalds/linux.git /linux
5 | COPY . /src
6 | WORKDIR /src
7 | RUN make test
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | default: build
2 |
3 | .PHONY: clean
4 | clean:
5 | rm -rf headers
6 | rm -rf linux
7 |
8 | .PHONY: test
9 | test: headers
10 | CGO_ENABLED=1 CGO_CFLAGS="-I$$(pwd)/headers/include" go test ./tracer ./printer ./filter
11 |
12 | linux:
13 | git clone --depth 1 https://github.com/torvalds/linux.git ./linux
14 |
15 | headers: linux
16 | cd linux && make headers_install ARCH=x86_64 INSTALL_HDR_PATH=../headers
17 |
18 | .PHONY: build
19 | build: headers
20 | CGO_ENABLED=1 CGO_CFLAGS="-I$$(pwd)/headers/include" go build --ldflags '-linkmode external -extldflags "-static"'
21 |
22 | .PHONY: install
23 | install: headers
24 | CGO_ENABLED=1 CGO_CFLAGS="-I$$(pwd)/headers/include" go install --ldflags '-linkmode external -extldflags "-static"'
25 |
26 | .PHONY: demo
27 | demo: build
28 | ./grace -- cat /dev/null
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # grace
2 |
3 | _grace_ is a tool for monitoring and annotating syscalls for a given process.
4 |
5 | It's essentially a lightweight [strace](https://en.wikipedia.org/wiki/Strace), in Go, with colours and pretty output.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | It's possible to tweak and filter the output to make it quite readable, for example (using `-vnmx`):
16 |
17 |
18 |
19 |
20 |
21 | You can also review a summary of encountered syscalls (and sort by various columns):
22 |
23 |
24 |
25 |
26 |
27 |
28 | ### grace vs. strace
29 |
30 | _grace_ isn't meant to compete with _strace_, it's purely meant to be a user-friendly, lightweight alternative. However, the following should provide a rough idea of what is supported in _grace_ so far.
31 |
32 | Over time grace is meant to become a simpler, more readable alternative to strace (_strace for dummies?_), albeit with reduced functionality/advanced features.
33 |
34 | | Feature | grace | strace |
35 | |---------------------------------------------------------------------------------------|-------|--------|
36 | | Start a program and print all syscalls it makes | ✅ | ✅ |
37 | | Attach to an existing process by `pid` and print all syscalls it makes | ✅ | ✅ |
38 | | Filter syscalls by name, e.g. only show occurrences of the `open` syscall | ✅ | ✅ |
39 | | Filter syscalls using a given path, e.g. only show syscalls that access `/etc/passwd` | ✅ | ✅ |
40 | | Dump I/O for certain file descriptors | ✅ | ✅ |
41 | | Count occurrences and duration of all syscalls and present in a useful format | ✅ | ✅ |
42 | | Print relative/absolute timestamps | ✅ | ✅ |
43 | | Tamper with syscalls | ❌ | ✅ |
44 | | Print extra information about file descriptors, such as path, socket addresses etc. | ✅ | ✅ |
45 | | Print stack traces | ❌ | ✅ |
46 | | Filter by return value | ✅ | ✅ |
47 | | Pretty colours to make output easier to read | ✅ | ❌ |
48 | | Lots of output options and customisation vectors | ✅ | ✅ |
49 | | Output to file | ✅ | ✅ |
50 | | Filter by failing/non-failing syscalls | ✅ | ✅ |
51 |
52 | _NOTE: Please feel free to add important strace features to this table, I'm working with a limited knowledge of strace._
53 |
54 |
55 |
56 | ## Installation
57 |
58 | Grab a statically compiled binary from the [latest release](https://github.com/liamg/grace/releases/latest).
59 |
60 | ## Supported Platforms/Architecture
61 |
62 | Currently only Linux/amd64 is supported. Other architectures coming soon.
63 |
64 | If you'd like to implement a new architecture, you can duplicate `tracer/sys_amd64.go` and convert it to contain the syscall definitions for your arch.
65 |
66 | ### Usage Examples
67 |
68 | #### Trace a program
69 |
70 | ```bash
71 | grace -- cat /dev/null # replace 'cat /dev/null' with your program
72 | ```
73 |
74 | #### Trace an existing process
75 |
76 | ```bash
77 | grace -p 123 # replace 123 with your pid
78 |
79 | # e.g. you could use pgrep to find the pid of a process
80 | grace -p `pgrep ping`
81 | ```
82 |
83 | #### Trace a program and filter by syscall name
84 |
85 | ```bash
86 | grace -f "name=openat" -- cat /dev/null
87 |
88 | # you can also look for multiple syscalls
89 | grace -f "name=openat&name=close" -- cat /dev/null
90 | ```
91 |
92 | #### Trace a program and filter by syscall name and path
93 |
94 | ```bash
95 | grace -f "name=openat&path=/dev/null" -- cat /dev/null
96 | ```
97 |
98 | #### Trace a program and wire up stdin/out/err with the terminal
99 |
100 | ```bash
101 | grace -F -- cat
102 | ```
103 |
104 | #### Trace a program with maximum readability options
105 |
106 | ```bash
107 | grace -vnmx -- cat /dev/null
108 | ```
109 |
110 | #### Trace only failing syscalls
111 |
112 | ```bash
113 | grace -Z -- cat /dev/null
114 | ```
115 |
116 | #### Show a summary of syscalls with durations, counts and errors
117 |
118 | ```bash
119 | grace -S -- cat /dev/null
120 | ```
121 |
122 | ## Build Dependencies
123 |
124 | If you want to build _grace_ yourself instead of using the precompiled binaries, you'll need a recent version of Go (1.19+). Then `make build` is your friend.
125 |
--------------------------------------------------------------------------------
/compare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liamg/grace/a28e5c24b4666a6c6674c152a5435fbde628f6b2/compare.png
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liamg/grace/a28e5c24b4666a6c6674c152a5435fbde628f6b2/demo.gif
--------------------------------------------------------------------------------
/filter/filter.go:
--------------------------------------------------------------------------------
1 | package filter
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 |
8 | "github.com/liamg/grace/tracer"
9 | )
10 |
11 | type Filter struct {
12 | allowNames []string
13 | allowPaths []string
14 | allowReturns []uint64
15 | failingOnly bool
16 | passingOnly bool
17 | }
18 |
19 | func Parse(input string) (*Filter, error) {
20 | filter := NewFilter()
21 | parts := strings.Split(input, "&")
22 | for _, part := range parts {
23 | if part == "" {
24 | continue
25 | }
26 | bits := strings.Split(part, "=")
27 | key := bits[0]
28 | value := bits[len(bits)-1]
29 | switch key {
30 | case "syscall", "name", "trace":
31 | filter.allowNames = append(filter.allowNames, strings.Split(value, ",")...)
32 | case "path":
33 | filter.allowPaths = append(filter.allowPaths, strings.Split(value, ",")...)
34 | case "ret", "retval", "return":
35 | ret, err := parseUint64(value)
36 | if err != nil {
37 | return nil, fmt.Errorf("failed to parse return value filter: %w", err)
38 | }
39 | filter.allowReturns = append(filter.allowReturns, ret)
40 | default:
41 | return nil, fmt.Errorf("invalid filter key: %s", key)
42 | }
43 | }
44 | return filter, nil
45 | }
46 |
47 | func parseUint64(input string) (uint64, error) {
48 | if strings.HasPrefix(input, "0x") {
49 | return strconv.ParseUint(input[2:], 16, 64)
50 | }
51 | return strconv.ParseUint(input, 10, 64)
52 | }
53 |
54 | func NewFilter() *Filter {
55 | return &Filter{}
56 | }
57 |
58 | func (f *Filter) Match(call *tracer.Syscall, exit bool) bool {
59 |
60 | if len(f.allowNames) > 0 {
61 | var match bool
62 | for _, name := range f.allowNames {
63 | if name == call.Name() {
64 | match = true
65 | break
66 | }
67 | }
68 | if !match {
69 | return false
70 | }
71 | }
72 |
73 | if len(f.allowPaths) > 0 {
74 | var match bool
75 | for _, path := range f.allowPaths {
76 | for _, realPath := range call.Paths() {
77 | if realPath == path {
78 | match = true
79 | break
80 | }
81 | }
82 | }
83 | if !match {
84 | return false
85 | }
86 | }
87 |
88 | if len(f.allowReturns) > 0 {
89 | if !exit {
90 | return false
91 | }
92 | var match bool
93 | for _, ret := range f.allowReturns {
94 | if uintptr(ret) == call.Return().Raw() {
95 | match = true
96 | break
97 | }
98 | }
99 | if !match {
100 | return false
101 | }
102 | }
103 |
104 | if (f.passingOnly || f.failingOnly) && !exit {
105 | return false
106 | }
107 |
108 | if f.failingOnly && call.Return().Int() >= 0 {
109 | return false
110 | }
111 |
112 | if f.passingOnly && call.Return().Int() < 0 {
113 | return false
114 | }
115 |
116 | // TODO check more filters
117 |
118 | return true
119 | }
120 |
121 | func (f *Filter) SetFailingOnly(failing bool) {
122 | f.failingOnly = failing
123 | }
124 |
125 | func (f *Filter) SetPassingOnly(passing bool) {
126 | f.passingOnly = passing
127 | }
128 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/liamg/grace
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/aquasecurity/table v1.8.0
7 | github.com/spf13/cobra v1.6.1
8 | github.com/stretchr/testify v1.8.1
9 | golang.org/x/sys v0.1.0
10 | )
11 |
12 | require (
13 | github.com/davecgh/go-spew v1.1.1 // indirect
14 | github.com/inconshreveable/mousetrap v1.0.1 // indirect
15 | github.com/mattn/go-runewidth v0.0.13 // indirect
16 | github.com/pmezard/go-difflib v1.0.0 // indirect
17 | github.com/rivo/uniseg v0.2.0 // indirect
18 | github.com/spf13/pflag v1.0.5 // indirect
19 | golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
20 | gopkg.in/yaml.v3 v3.0.1 // indirect
21 | )
22 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/aquasecurity/table v1.8.0 h1:9ntpSwrUfjrM6/YviArlx/ZBGd6ix8W+MtojQcM7tv0=
2 | github.com/aquasecurity/table v1.8.0/go.mod h1:eqOmvjjB7AhXFgFqpJUEE/ietg7RrMSJZXyTN8E/wZw=
3 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7 | github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
8 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
9 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
10 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
13 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
14 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
15 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
16 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
17 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
18 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
19 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
20 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
21 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
22 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
23 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
24 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
25 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
26 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
27 | golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
28 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
29 | golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
30 | golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
31 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
32 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
33 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
34 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
35 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
36 |
--------------------------------------------------------------------------------
/printer/arg.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/liamg/grace/tracer"
7 | )
8 |
9 | func (p *Printer) PrintArg(arg tracer.Arg, exit bool) {
10 |
11 | var indent int
12 | if p.multiline {
13 | indent = indentSize
14 | }
15 |
16 | if p.multiline {
17 | p.Print(strings.Repeat(" ", indent))
18 | }
19 |
20 | if name := arg.Name(); name != "" {
21 | p.PrintDim("%s: ", name)
22 | }
23 |
24 | p.PrintArgValue(&arg, p.nextColour(), exit, 0, indent)
25 | }
26 |
27 | func (p *Printer) NewLine(indent int) {
28 | p.Print("\n" + strings.Repeat(" ", indent))
29 | }
30 |
31 | func (p *Printer) PrintArgValue(arg *tracer.Arg, colour Colour, exit bool, propCount int, indent int) int {
32 |
33 | if p.rawOutput {
34 | p.PrintColour(colour, "0x%x", arg.Raw())
35 | return propCount
36 | }
37 |
38 | if arg.ReplaceValueWithAnnotation() {
39 | p.PrintColour(colour, "%s", arg.Annotation())
40 | return propCount
41 | }
42 |
43 | switch arg.Type() {
44 | case tracer.ArgTypeData:
45 | data := arg.Data()
46 | if p.maxStringLen > 0 && len(data) > p.maxStringLen {
47 | if p.hexDumpLongStrings {
48 | p.HexDump(arg.Raw(), arg.Data(), indent)
49 | return propCount
50 | }
51 | data = append(data[:p.maxStringLen], []byte("...")...)
52 | }
53 | p.PrintColour(colour, "%q", string(data))
54 | //p.PrintDim(" @ 0x%x", arg.Raw())
55 | case tracer.ArgTypeInt, tracer.ArgTypeLong, tracer.ArgTypeUnsignedInt, tracer.ArgTypeUnsignedLong, tracer.ArgTypeUnknown:
56 | p.PrintColour(colour, "%d", arg.Int())
57 | case tracer.ArgTypeErrorCode:
58 | p.printError(arg)
59 | case tracer.ArgTypeAddress:
60 | p.PrintColour(colour, "0x%x", arg.Raw())
61 | case tracer.ArgTypeObject:
62 | propCount += p.printObject(arg.Object(), colour, exit, propCount, indent)
63 | case tracer.ArgTypeArray:
64 | propCount += p.printArray(arg.Array(), colour, exit, propCount, indent)
65 | default:
66 | p.PrintColour(ColourRed, "UNKNOWN TYPE (raw=%d)", arg.Raw())
67 | }
68 |
69 | if annotation := arg.Annotation(); annotation != "" {
70 | p.PrintDim(" -> %s", annotation)
71 | }
72 |
73 | return propCount
74 | }
75 |
--------------------------------------------------------------------------------
/printer/array.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import "github.com/liamg/grace/tracer"
4 |
5 | func (p *Printer) printArray(arr []tracer.Arg, colour Colour, exit bool, count int, indent int) int {
6 | prevIndent := indent
7 | indent += indentSize
8 | p.PrintColour(colour, "[")
9 |
10 | for i, prop := range arr {
11 | if p.multiline {
12 | p.NewLine(indent)
13 | }
14 | colour := colours[i%len(colours)]
15 | p.PrintDim("%d", i)
16 | p.PrintDim(": ")
17 | count += p.PrintArgValue(&prop, colour, exit, count, indent+indentSize)
18 | if i < len(arr)-1 {
19 | p.PrintDim(", ")
20 | }
21 | if p.maxObjectProperties > 0 && count >= p.maxObjectProperties && count < len(arr) {
22 | p.PrintDim("...")
23 | break
24 | }
25 | count++
26 | }
27 | if p.multiline && len(arr) > 0 {
28 | p.NewLine(prevIndent)
29 | }
30 | p.PrintColour(colour, "]")
31 | return count
32 | }
33 |
--------------------------------------------------------------------------------
/printer/colours.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | type Colour int
4 |
5 | const (
6 | ColourRed Colour = iota + 31
7 | ColourGreen
8 | ColourYellow
9 | ColourBlue
10 | ColourMagenta
11 | ColourCyan
12 | ColourWhite
13 | )
14 |
15 | var ColourDefault Colour = 0
16 |
17 | var colours = []Colour{
18 | ColourBlue,
19 | ColourYellow,
20 | ColourGreen,
21 | }
22 |
23 | func (p *Printer) currentColour() Colour {
24 | return colours[p.colourIndex%len(colours)]
25 | }
26 |
27 | func (p *Printer) nextColour() Colour {
28 | colour := colours[p.colourIndex%len(colours)]
29 | p.colourIndex++
30 | return colour
31 | }
32 |
--------------------------------------------------------------------------------
/printer/hexdump.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import "strings"
4 |
5 | const dumpWidth = 16
6 |
7 | func (p *Printer) HexDump(addr uintptr, data []byte, indent int) {
8 |
9 | var truncatedFrom uintptr
10 | if p.maxHexDumpLen > 0 && len(data) > p.maxHexDumpLen {
11 | truncatedFrom = uintptr(len(data))
12 | data = data[:p.maxHexDumpLen]
13 | }
14 |
15 | startAddr := addr - (addr % dumpWidth)
16 | endAddr := addr + uintptr(len(data))
17 | if endAddr%dumpWidth > 0 {
18 | endAddr += dumpWidth - (endAddr % dumpWidth)
19 | }
20 | p.Print(strings.Repeat(" ", indent))
21 | p.Print("(see below hexdump)")
22 | p.NewLine(indent)
23 | p.Print(" ")
24 | for i := 0; i < dumpWidth; i++ {
25 | p.PrintDim("%02x ", i)
26 | }
27 | for i := startAddr; i < endAddr; i += dumpWidth {
28 | p.NewLine(indent)
29 | p.PrintDim("%16x: ", i)
30 | for j := 0; j < dumpWidth; j++ {
31 | local := (i + uintptr(j)) - addr
32 | if i+uintptr(j) < addr || local >= uintptr(len(data)) {
33 | p.PrintDim(".. ")
34 | } else {
35 | p.PrintColour(ColourRed, "%02x ", data[local])
36 | }
37 | }
38 | for j := 0; j < dumpWidth; j++ {
39 | local := (i + uintptr(j)) - addr
40 | if i+uintptr(j) < addr || local >= uintptr(len(data)) {
41 | p.PrintDim(".")
42 | } else {
43 | c := data[local]
44 | if c < 32 || c > 126 {
45 | c = '.'
46 | }
47 | p.PrintColour(ColourBlue, "%c", c)
48 | }
49 | }
50 | }
51 | if truncatedFrom > 0 {
52 | p.PrintDim("\n... (truncated from %d bytes -> %d bytes) ...", truncatedFrom, p.maxHexDumpLen)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/printer/object.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import (
4 | "github.com/liamg/grace/tracer"
5 | )
6 |
7 | func (p *Printer) printObject(obj *tracer.Object, colour Colour, exit bool, count int, indent int) int {
8 | if obj == nil {
9 | p.PrintDim("NULL")
10 | return count
11 | }
12 | prevIndent := indent
13 | indent += indentSize
14 | p.PrintColour(colour, "%s{", obj.Name)
15 |
16 | for i, prop := range obj.Properties {
17 | if p.multiline {
18 | p.NewLine(indent)
19 | }
20 | colour := colours[i%len(colours)]
21 | p.PrintDim("%s", prop.Name())
22 | p.PrintDim(": ")
23 | count += p.PrintArgValue(&prop, colour, exit, count, indent+indentSize)
24 | if i < len(obj.Properties)-1 {
25 | p.PrintDim(", ")
26 | }
27 | if p.maxObjectProperties > 0 && count >= p.maxObjectProperties {
28 | p.PrintDim("...")
29 | break
30 | }
31 | count++
32 | }
33 | if p.multiline {
34 | p.NewLine(prevIndent)
35 | }
36 | p.PrintColour(colour, "}")
37 | return count
38 | }
39 |
--------------------------------------------------------------------------------
/printer/printer.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "time"
7 |
8 | "github.com/liamg/grace/tracer"
9 | )
10 |
11 | type Printer struct {
12 | w io.Writer
13 | useColours bool
14 | maxStringLen int
15 | hexDumpLongStrings bool
16 | maxHexDumpLen int
17 | maxObjectProperties int
18 | colourIndex int
19 | argProgress int
20 | extraNewLine bool
21 | multiline bool
22 | inSyscall bool
23 | filter Filter
24 | lastEntryMatchedFilter bool
25 | relativeTimestamps bool
26 | absoluteTimestamps bool
27 | startTime time.Time
28 | showNumbers bool
29 | rawOutput bool
30 | }
31 |
32 | type Filter interface {
33 | Match(syscall *tracer.Syscall, exit bool) bool
34 | }
35 |
36 | func New(w io.Writer) *Printer {
37 | return &Printer{
38 | w: w,
39 | useColours: true,
40 | maxStringLen: 32,
41 | hexDumpLongStrings: true,
42 | maxHexDumpLen: 4096,
43 | maxObjectProperties: 2,
44 | startTime: time.Now(),
45 | }
46 | }
47 |
48 | const indentSize = 4
49 |
50 | func (p *Printer) SetUseColours(useColours bool) {
51 | p.useColours = useColours
52 | }
53 |
54 | func (p *Printer) SetMaxStringLen(maxStringLen int) {
55 | p.maxStringLen = maxStringLen
56 | }
57 |
58 | func (p *Printer) SetHexDumpLongStrings(hexDumpLongStrings bool) {
59 | p.hexDumpLongStrings = hexDumpLongStrings
60 | }
61 |
62 | func (p *Printer) SetMaxHexDumpLen(maxHexDumpLen int) {
63 | p.maxHexDumpLen = maxHexDumpLen
64 | }
65 |
66 | func (p *Printer) SetMaxObjectProperties(maxObjectProperties int) {
67 | p.maxObjectProperties = maxObjectProperties
68 | }
69 |
70 | func (p *Printer) SetExtraNewLine(extraNewLine bool) {
71 | p.extraNewLine = extraNewLine
72 | }
73 |
74 | func (p *Printer) SetShowAbsoluteTimestamps(timestamps bool) {
75 | p.absoluteTimestamps = timestamps
76 | }
77 |
78 | func (p *Printer) SetShowRelativeTimestamps(timestamps bool) {
79 | p.relativeTimestamps = timestamps
80 | }
81 |
82 | func (p *Printer) SetMultiLine(multiline bool) {
83 | p.multiline = multiline
84 | }
85 |
86 | func (p *Printer) SetFilter(filter Filter) {
87 | p.filter = filter
88 | }
89 |
90 | func (p *Printer) SetShowSyscallNumber(number bool) {
91 | p.showNumbers = number
92 | }
93 |
94 | func (p *Printer) SetRawOutput(output bool) {
95 | p.rawOutput = output
96 | }
97 |
98 | func (p *Printer) PrefixEvent() {
99 | if p.relativeTimestamps {
100 | p.PrintDim("%12s ", time.Since(p.startTime))
101 | }
102 | if p.absoluteTimestamps {
103 | p.PrintDim("%18s ", time.Now().Format("15:04:05.999999999"))
104 | }
105 | }
106 |
107 | func (p *Printer) Print(format string, args ...interface{}) {
108 | _, _ = fmt.Fprintf(p.w, format, args...)
109 | }
110 |
111 | func (p *Printer) PrintDim(format string, args ...interface{}) {
112 | p.PrintColour(2, format, args...)
113 | }
114 |
115 | func (p *Printer) PrintColour(colour Colour, format string, args ...interface{}) {
116 | if p.useColours {
117 | p.Print("\x1b[%dm", colour)
118 | }
119 | p.Print(format, args...)
120 | if p.useColours {
121 | p.Print("\x1b[0m")
122 | }
123 | }
124 |
125 | func (p *Printer) PrintProcessExit(i int) {
126 | colour := ColourGreen
127 | if i != 0 {
128 | colour = ColourRed
129 | }
130 | if p.inSyscall {
131 | p.PrintDim(" = ?\n")
132 | }
133 | if p.multiline {
134 | p.Print("\n")
135 | }
136 | p.PrintColour(colour, "Process exited with status %d\n", i)
137 | }
138 |
139 | func (p *Printer) PrintAttach(pid int) {
140 | p.PrintColour(ColourYellow, "Attached to process %d\n", pid)
141 | if p.multiline {
142 | p.Print("\n")
143 | }
144 | }
145 |
146 | func (p *Printer) PrintDetach(pid int) {
147 | p.PrintColour(ColourYellow, "Detached from process %d\n", pid)
148 | if p.multiline {
149 | p.Print("\n")
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/printer/signal.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import (
4 | "syscall"
5 |
6 | "github.com/liamg/grace/tracer"
7 | "github.com/liamg/grace/tracer/annotation"
8 | )
9 |
10 | func (p *Printer) PrintSignal(signal *tracer.SigInfo) {
11 | p.PrefixEvent()
12 | p.PrintColour(ColourMagenta, "--> ")
13 | p.PrintColour(
14 | ColourCyan,
15 | "SIGNAL: %s (code=%s, pid=%d, uid=%d)",
16 | annotation.SignalToString(int(signal.Signo)),
17 | annotation.SignalCodeToString(syscall.Signal(signal.Signo), signal.Code),
18 | signal.Pid,
19 | signal.Uid,
20 | )
21 | p.PrintColour(ColourMagenta, " <--\n")
22 | if p.multiline {
23 | p.Print("\n")
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/printer/syscall.go:
--------------------------------------------------------------------------------
1 | package printer
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/liamg/grace/tracer"
7 | )
8 |
9 | func (p *Printer) PrintSyscallEnter(syscall *tracer.Syscall) {
10 | p.printSyscallEnter(syscall, false)
11 | }
12 |
13 | func (p *Printer) printSyscallEnter(syscall *tracer.Syscall, overrideFilter bool) {
14 |
15 | if !overrideFilter {
16 | if p.filter != nil {
17 | if !p.filter.Match(syscall, false) {
18 | p.lastEntryMatchedFilter = false
19 | return
20 | }
21 | }
22 | p.lastEntryMatchedFilter = true
23 | }
24 |
25 | p.PrefixEvent()
26 |
27 | p.colourIndex = 0
28 | p.argProgress = 0
29 |
30 | if p.showNumbers {
31 | p.PrintDim("%4s", fmt.Sprintf("%d ", syscall.Number()))
32 | }
33 |
34 | if syscall.Unknown() {
35 | p.PrintColour(ColourRed, syscall.Name())
36 | } else {
37 | p.PrintColour(ColourDefault, syscall.Name())
38 | }
39 | p.printRemainingArgs(syscall, false)
40 | p.inSyscall = true
41 | }
42 |
43 | func (p *Printer) PrintSyscallExit(syscall *tracer.Syscall) {
44 |
45 | if p.filter != nil {
46 | if !p.lastEntryMatchedFilter && !p.filter.Match(syscall, true) {
47 | return
48 | }
49 | }
50 |
51 | if !p.lastEntryMatchedFilter {
52 | p.printSyscallEnter(syscall, true)
53 | }
54 |
55 | p.printRemainingArgs(syscall, true)
56 | p.PrintDim(" = ")
57 | ret := syscall.Return()
58 | p.PrintArgValue(&ret, ColourGreen, true, 0, 0)
59 | p.Print("\n")
60 | if p.extraNewLine {
61 | p.Print("\n")
62 | }
63 | p.inSyscall = false
64 | }
65 |
66 | func (p *Printer) printRemainingArgs(syscall *tracer.Syscall, exit bool) {
67 | if !exit {
68 | p.PrintDim("(")
69 | }
70 | var remaining []tracer.Arg
71 | if p.argProgress < len(syscall.Args()) {
72 | remaining = syscall.Args()[p.argProgress:]
73 | for i, arg := range remaining {
74 | if !arg.Known() {
75 | break
76 | }
77 | if p.argProgress == 0 && p.multiline {
78 | p.Print("\n")
79 | }
80 | p.PrintArg(arg, exit)
81 | if i < len(remaining)-1 || !syscall.Complete() {
82 | p.PrintDim(", ")
83 | }
84 | p.argProgress++
85 | if p.multiline {
86 | p.Print("\n")
87 | }
88 | }
89 | }
90 |
91 | if ((exit && len(remaining) > 0) || (!exit && p.argProgress == len(syscall.Args()))) && syscall.Complete() {
92 | p.PrintDim(")")
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/summary.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "sort"
7 | "time"
8 |
9 | "github.com/aquasecurity/table"
10 | "github.com/liamg/grace/tracer"
11 | )
12 |
13 | func configureSummary(t *tracer.Tracer, w io.Writer, sortKey string) {
14 |
15 | tracker := &tracker{
16 | counts: make(map[string]int),
17 | errors: make(map[string]int),
18 | durations: make(map[string]time.Duration),
19 | starts: make(map[string]time.Time),
20 | }
21 |
22 | t.SetSyscallEnterHandler(tracker.recordEnter)
23 | t.SetSyscallExitHandler(tracker.recordExit)
24 | t.SetDetachHandler(func(i int) {
25 | tracker.print(w, sortKey)
26 | })
27 | }
28 |
29 | type tracker struct {
30 | counts map[string]int
31 | errors map[string]int
32 | durations map[string]time.Duration
33 | starts map[string]time.Time
34 | }
35 |
36 | func (t *tracker) recordEnter(s *tracer.Syscall) {
37 | t.starts[s.Name()] = time.Now()
38 | }
39 |
40 | func (t *tracker) recordExit(s *tracer.Syscall) {
41 | stop := time.Now()
42 | if start, ok := t.starts[s.Name()]; ok {
43 | t.durations[s.Name()] += stop.Sub(start)
44 | delete(t.starts, s.Name())
45 | }
46 | if s.Return().Int() < 0 {
47 | t.errors[s.Name()]++
48 | }
49 | t.counts[s.Name()]++
50 | }
51 |
52 | func (t *tracker) print(w io.Writer, sortKey string) {
53 |
54 | tab := table.New(w)
55 | tab.SetRowLines(false)
56 | tab.AddHeaders("time %", "seconds", "usecs/call", "count", "errors", "syscall")
57 | tab.SetAlignment(table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignLeft)
58 | tab.SetLineStyle(table.StyleBlue)
59 |
60 | var total time.Duration
61 | for _, duration := range t.durations {
62 | total += duration
63 | }
64 |
65 | type row struct {
66 | sortKey int
67 | cols []string
68 | name string
69 | }
70 |
71 | var rows []row
72 |
73 | for name, count := range t.counts {
74 |
75 | duration := t.durations[name]
76 |
77 | percent := float64(duration) * 100 / float64(total)
78 |
79 | var key int
80 | switch sortKey {
81 | case "count":
82 | key = count
83 | case "time":
84 | key = int(percent * 100000)
85 | case "seconds":
86 | key = int(duration)
87 | case "errors":
88 | key = t.errors[name]
89 |
90 | }
91 |
92 | rows = append(rows, row{
93 | name: name,
94 | sortKey: key,
95 | cols: []string{
96 | fmt.Sprintf("%.2f", percent),
97 | fmt.Sprintf("%.6f", duration.Seconds()),
98 | fmt.Sprintf("%d", duration.Microseconds()/int64(count)),
99 | fmt.Sprintf("%d", count),
100 | fmt.Sprintf("%d", t.errors[name]),
101 | name,
102 | },
103 | })
104 | }
105 |
106 | if sortKey == "" {
107 | sort.Slice(rows, func(i, j int) bool {
108 | return rows[i].name < rows[j].name
109 | })
110 | } else {
111 | sort.Slice(rows, func(i, j int) bool {
112 | return rows[i].sortKey > rows[j].sortKey
113 | })
114 | }
115 |
116 | for _, row := range rows {
117 | tab.AddRow(row.cols...)
118 | }
119 |
120 | tab.Render()
121 | }
122 |
--------------------------------------------------------------------------------
/summary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liamg/grace/a28e5c24b4666a6c6674c152a5435fbde628f6b2/summary.png
--------------------------------------------------------------------------------
/testdata/execve/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 | "syscall"
6 | )
7 |
8 | func main() {
9 | _ = syscall.Exec("/usr/bin/ls", []string{"ls", "/tmp"}, os.Environ())
10 | }
11 |
--------------------------------------------------------------------------------
/testdata/pipe/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "syscall"
6 | )
7 |
8 | func main() {
9 | var buf syscall.Utsname
10 | _ = syscall.Uname(&buf)
11 | printUtsField(buf.Release)
12 | }
13 |
14 | func printUtsField(f [65]int8) {
15 | var str []byte
16 | for i := 0; i < len(f); i++ {
17 | str = append(str, byte(f[i]))
18 | }
19 | fmt.Println(string(str))
20 | }
21 |
--------------------------------------------------------------------------------
/tracer/annotation/access.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func AnnotateAccMode(arg Arg, _ int) {
10 | var joins []string
11 | if arg.Raw() == unix.F_OK {
12 | joins = append(joins, "F_OK")
13 | } else {
14 | if arg.Raw()&unix.R_OK > 0 {
15 | joins = append(joins, "R_OK")
16 | }
17 | if arg.Raw()&unix.W_OK > 0 {
18 | joins = append(joins, "W_OK")
19 | }
20 | if arg.Raw()&unix.X_OK > 0 {
21 | joins = append(joins, "X_OK")
22 | }
23 | }
24 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
25 | }
26 |
--------------------------------------------------------------------------------
/tracer/annotation/arch_prctl.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 |
6 | #ifndef _ASM_X86_PRCTL_H
7 | #define _ASM_X86_PRCTL_H
8 | #define ARCH_SET_GS 0x1001
9 | #define ARCH_SET_FS 0x1002
10 | #define ARCH_GET_FS 0x1003
11 | #define ARCH_GET_GS 0x1004
12 | #endif
13 |
14 | int iARCH_SET_GS = ARCH_SET_GS;
15 | int iARCH_SET_FS = ARCH_SET_FS;
16 | int iARCH_GET_FS = ARCH_GET_FS;
17 | int iARCH_GET_GS = ARCH_GET_GS;
18 | */
19 | import "C"
20 |
21 | var archPrCodes = map[int]string{
22 | int(C.iARCH_SET_GS): "ARCH_SET_GS",
23 | int(C.iARCH_SET_FS): "ARCH_SET_FS",
24 | int(C.iARCH_GET_FS): "ARCH_GET_FS",
25 | int(C.iARCH_GET_GS): "ARCH_GET_GS",
26 | }
27 |
28 | func AnnotateArchPrctrlCode(arg Arg, pid int) {
29 | if s, ok := archPrCodes[int(arg.Raw())]; ok {
30 | arg.SetAnnotation(s, true)
31 | } else {
32 | AnnotateHex(arg, pid)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tracer/annotation/arg.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | type Arg interface {
4 | Raw() uintptr
5 | SetAnnotation(annotation string, replace bool)
6 | }
7 |
--------------------------------------------------------------------------------
/tracer/annotation/bpf.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var bpfCmds = map[int]string{
6 | unix.BPF_MAP_CREATE: "BPF_MAP_CREATE",
7 | unix.BPF_MAP_LOOKUP_ELEM: "BPF_MAP_LOOKUP_ELEM",
8 | unix.BPF_MAP_UPDATE_ELEM: "BPF_MAP_UPDATE_ELEM",
9 | unix.BPF_MAP_DELETE_ELEM: "BPF_MAP_DELETE_ELEM",
10 | unix.BPF_MAP_GET_NEXT_KEY: "BPF_MAP_GET_NEXT_KEY",
11 | unix.BPF_PROG_LOAD: "BPF_PROG_LOAD",
12 | unix.BPF_OBJ_PIN: "BPF_OBJ_PIN",
13 | unix.BPF_OBJ_GET: "BPF_OBJ_GET",
14 | unix.BPF_PROG_ATTACH: "BPF_PROG_ATTACH",
15 | unix.BPF_PROG_DETACH: "BPF_PROG_DETACH",
16 | unix.BPF_PROG_TEST_RUN: "BPF_PROG_TEST_RUN",
17 | unix.BPF_PROG_GET_NEXT_ID: "BPF_PROG_GET_NEXT_ID",
18 | unix.BPF_MAP_GET_NEXT_ID: "BPF_MAP_GET_NEXT_ID",
19 | unix.BPF_PROG_GET_FD_BY_ID: "BPF_PROG_GET_FD_BY_ID",
20 | unix.BPF_MAP_GET_FD_BY_ID: "BPF_MAP_GET_FD_BY_ID",
21 | unix.BPF_OBJ_GET_INFO_BY_FD: "BPF_OBJ_GET_INFO_BY_FD",
22 | unix.BPF_PROG_QUERY: "BPF_PROG_QUERY",
23 | unix.BPF_RAW_TRACEPOINT_OPEN: "BPF_RAW_TRACEPOINT_OPEN",
24 | unix.BPF_BTF_LOAD: "BPF_BTF_LOAD",
25 | unix.BPF_BTF_GET_FD_BY_ID: "BPF_BTF_GET_FD_BY_ID",
26 | unix.BPF_TASK_FD_QUERY: "BPF_TASK_FD_QUERY",
27 | unix.BPF_MAP_LOOKUP_AND_DELETE_ELEM: "BPF_MAP_LOOKUP_AND_DELETE_ELEM",
28 | unix.BPF_MAP_FREEZE: "BPF_MAP_FREEZE",
29 | unix.BPF_BTF_GET_NEXT_ID: "BPF_BTF_GET_NEXT_ID",
30 | unix.BPF_MAP_LOOKUP_BATCH: "BPF_MAP_LOOKUP_BATCH",
31 | unix.BPF_MAP_LOOKUP_AND_DELETE_BATCH: "BPF_MAP_LOOKUP_AND_DELETE_BATCH",
32 | unix.BPF_MAP_UPDATE_BATCH: "BPF_MAP_UPDATE_BATCH",
33 | unix.BPF_MAP_DELETE_BATCH: "BPF_MAP_DELETE_BATCH",
34 | unix.BPF_LINK_CREATE: "BPF_LINK_CREATE",
35 | unix.BPF_LINK_UPDATE: "BPF_LINK_UPDATE",
36 | unix.BPF_LINK_GET_FD_BY_ID: "BPF_LINK_GET_FD_BY_ID",
37 | unix.BPF_LINK_GET_NEXT_ID: "BPF_LINK_GET_NEXT_ID",
38 | unix.BPF_ENABLE_STATS: "BPF_ENABLE_STATS",
39 | unix.BPF_ITER_CREATE: "BPF_ITER_CREATE",
40 | unix.BPF_LINK_DETACH: "BPF_LINK_DETACH",
41 | }
42 |
43 | func AnnotateBPFCmd(arg Arg, _ int) {
44 | if v, ok := bpfCmds[int(arg.Raw())]; ok {
45 | arg.SetAnnotation(v, true)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tracer/annotation/clockid.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var clockIds = map[int]string{
6 | unix.CLOCK_REALTIME: "CLOCK_REALTIME",
7 | unix.CLOCK_MONOTONIC: "CLOCK_MONOTONIC",
8 | unix.CLOCK_PROCESS_CPUTIME_ID: "CLOCK_PROCESS_CPUTIME_ID",
9 | unix.CLOCK_THREAD_CPUTIME_ID: "CLOCK_THREAD_CPUTIME_ID",
10 | unix.CLOCK_MONOTONIC_RAW: "CLOCK_MONOTONIC_RAW",
11 | unix.CLOCK_REALTIME_COARSE: "CLOCK_REALTIME_COARSE",
12 | unix.CLOCK_MONOTONIC_COARSE: "CLOCK_MONOTONIC_COARSE",
13 | unix.CLOCK_BOOTTIME: "CLOCK_BOOTTIME",
14 | unix.CLOCK_REALTIME_ALARM: "CLOCK_REALTIME_ALARM",
15 | unix.CLOCK_BOOTTIME_ALARM: "CLOCK_BOOTTIME_ALARM",
16 | }
17 |
18 | func AnnotateClockID(arg Arg, pid int) {
19 | if str, ok := clockIds[int(arg.Raw())]; ok {
20 | arg.SetAnnotation(str, true)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tracer/annotation/clone.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var cloneFlags = map[int]string{
10 | unix.CLONE_CHILD_CLEARTID: "CLONE_CHILD_CLEARTID",
11 | unix.CLONE_CHILD_SETTID: "CLONE_CHILD_SETTID",
12 | unix.CLONE_FILES: "CLONE_FILES",
13 | unix.CLONE_FS: "CLONE_FS",
14 | unix.CLONE_IO: "CLONE_IO",
15 | unix.CLONE_NEWCGROUP: "CLONE_NEWCGROUP",
16 | unix.CLONE_NEWIPC: "CLONE_NEWIPC",
17 | unix.CLONE_NEWNET: "CLONE_NEWNET",
18 | unix.CLONE_NEWNS: "CLONE_NEWNS",
19 | unix.CLONE_NEWPID: "CLONE_NEWPID",
20 | unix.CLONE_NEWUSER: "CLONE_NEWUSER",
21 | unix.CLONE_NEWUTS: "CLONE_NEWUTS",
22 | unix.CLONE_PARENT: "CLONE_PARENT",
23 | unix.CLONE_PARENT_SETTID: "CLONE_PARENT_SETTID",
24 | unix.CLONE_PTRACE: "CLONE_PTRACE",
25 | unix.CLONE_SETTLS: "CLONE_SETTLS",
26 | unix.CLONE_SIGHAND: "CLONE_SIGHAND",
27 | unix.CLONE_SYSVSEM: "CLONE_SYSVSEM",
28 | unix.CLONE_THREAD: "CLONE_THREAD",
29 | unix.CLONE_UNTRACED: "CLONE_UNTRACED",
30 | unix.CLONE_VFORK: "CLONE_VFORK",
31 | unix.CLONE_VM: "CLONE_VM",
32 | }
33 |
34 | func AnnotateCloneFlags(arg Arg, _ int) {
35 | var joins []string
36 | for flag, name := range cloneFlags {
37 | if arg.Raw()&uintptr(flag) != 0 {
38 | joins = append(joins, name)
39 | }
40 | }
41 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
42 | }
43 |
--------------------------------------------------------------------------------
/tracer/annotation/closerange.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var closeRangeFlags = map[int]string{
10 | unix.CLOSE_RANGE_CLOEXEC: "CLOSE_RANGE_CLOEXEC",
11 | unix.CLOSE_RANGE_UNSHARE: "CLOSE_RANGE_UNSHARE",
12 | }
13 |
14 | func AnnotateCloseRangeFlags(arg Arg, _ int) {
15 | var joins []string
16 | for flag, str := range closeRangeFlags {
17 | if int(arg.Raw())&flag != 0 {
18 | joins = append(joins, str)
19 | }
20 | }
21 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
22 | }
23 |
--------------------------------------------------------------------------------
/tracer/annotation/control.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var socketLevels = map[int]string{
6 | unix.SOL_SOCKET: "SOL_SOCKET",
7 | unix.SOL_AAL: "SOL_AAL",
8 | unix.SOL_ALG: "SOL_ALG",
9 | unix.SOL_ATM: "SOL_ATM",
10 | unix.SOL_CAIF: "SOL_CAIF",
11 | unix.SOL_CAN_BASE: "SOL_CAN_BASE",
12 | unix.SOL_CAN_RAW: "SOL_CAN_RAW",
13 | unix.SOL_DCCP: "SOL_DCCP",
14 | unix.SOL_DECNET: "SOL_DECNET",
15 | unix.SOL_ICMPV6: "SOL_ICMPV6",
16 | unix.SOL_IP: "SOL_IP",
17 | unix.SOL_IPV6: "SOL_IPV6",
18 | unix.SOL_IRDA: "SOL_IRDA",
19 | unix.SOL_IUCV: "SOL_IUCV",
20 | unix.SOL_KCM: "SOL_KCM",
21 | unix.SOL_LLC: "SOL_LLC",
22 | unix.SOL_MCTP: "SOL_MCTP",
23 | unix.SOL_MPTCP: "SOL_MPTCP",
24 | unix.SOL_NETBEUI: "SOL_NETBEUI",
25 | unix.SOL_NETLINK: "SOL_NETLINK",
26 | unix.SOL_NFC: "SOL_NFC",
27 | unix.SOL_PACKET: "SOL_PACKET",
28 | unix.SOL_PNPIPE: "SOL_PNPIPE",
29 | unix.SOL_PPPOL2TP: "SOL_PPPOL2TP",
30 | unix.SOL_RAW: "SOL_RAW",
31 | unix.SOL_RDS: "SOL_RDS",
32 | unix.SOL_RXRPC: "SOL_RXRPC",
33 | unix.SOL_SMC: "SOL_SMC",
34 | unix.SOL_TCP: "SOL_TCP",
35 | unix.SOL_TIPC: "SOL_TIPC",
36 | unix.SOL_TLS: "SOL_TLS",
37 | unix.SOL_X25: "SOL_X25",
38 | unix.SOL_XDP: "SOL_XDP",
39 | }
40 |
41 | func AnnotateSocketLevel(arg Arg, _ int) {
42 | if str, ok := socketLevels[int(arg.Raw())]; ok {
43 | arg.SetAnnotation(str, true)
44 | }
45 | }
46 |
47 | var cmsgTypes = map[int]string{
48 | unix.SCM_RIGHTS: "SCM_RIGHTS",
49 | unix.SCM_CREDENTIALS: "SCM_CREDENTIALS",
50 | unix.SCM_TIMESTAMP: "SCM_TIMESTAMP",
51 | }
52 |
53 | func AnnotateControlMessageType(arg Arg, _ int) {
54 | if str, ok := cmsgTypes[int(arg.Raw())]; ok {
55 | arg.SetAnnotation(str, true)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tracer/annotation/device.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "fmt"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func AnnotateDevice(arg Arg, pid int) {
10 | arg.SetAnnotation(DeviceToString(uint64(arg.Raw())), true)
11 | }
12 |
13 | func DeviceToString(dev uint64) string {
14 | major := "0"
15 | if m := unix.Major(dev); m != 0 {
16 | major = fmt.Sprintf("0x%x", m)
17 | }
18 | minor := "0"
19 | if m := unix.Minor(dev); m != 0 {
20 | minor = fmt.Sprintf("0x%x", m)
21 | }
22 | return fmt.Sprintf("makedev(%s, %s)", major, minor)
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/dirent.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var dirEntTypes = map[int]string{
6 | unix.DT_BLK: "DT_BLK",
7 | unix.DT_CHR: "DT_CHR",
8 | unix.DT_DIR: "DT_DIR",
9 | unix.DT_FIFO: "DT_FIFO",
10 | unix.DT_LNK: "DT_LNK",
11 | unix.DT_REG: "DT_REG",
12 | unix.DT_SOCK: "DT_SOCK",
13 | unix.DT_WHT: "DT_WHT",
14 | unix.DT_UNKNOWN: "DT_UNKNOWN",
15 | }
16 |
17 | func AnnotateDirEntType(arg Arg, _ int) {
18 | if str, ok := dirEntTypes[int(arg.Raw())]; ok {
19 | arg.SetAnnotation(str, true)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tracer/annotation/epoll.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var epollCtlOps = map[int]string{
6 | unix.EPOLL_CTL_ADD: "EPOLL_CTL_ADD",
7 | unix.EPOLL_CTL_DEL: "EPOLL_CTL_DEL",
8 | unix.EPOLL_CTL_MOD: "EPOLL_CTL_MOD",
9 | }
10 |
11 | func AnnotateEpollCtlOp(arg Arg, _ int) {
12 | if str, ok := epollCtlOps[int(arg.Raw())]; ok {
13 | arg.SetAnnotation(str, true)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tracer/annotation/eventfd.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var eventFdFlags = map[int]string{
10 | unix.O_CLOEXEC: "EFD_CLOEXEC",
11 | unix.O_NONBLOCK: "EFD_NONBLOCK",
12 | unix.EFD_SEMAPHORE: "EFD_SEMAPHORE",
13 | }
14 |
15 | func AnnotateEventFdFlags(arg Arg, _ int) {
16 | var joins []string
17 | for flag, str := range eventFdFlags {
18 | if int(arg.Raw())&flag != 0 {
19 | joins = append(joins, str)
20 | }
21 | }
22 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/fadvice.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | */
6 | import "C"
7 |
8 | var fadviceFlags = map[int]string{
9 | C.POSIX_FADV_NORMAL: "POSIX_FADV_NORMAL",
10 | C.POSIX_FADV_RANDOM: "POSIX_FADV_RANDOM",
11 | C.POSIX_FADV_SEQUENTIAL: "POSIX_FADV_SEQUENTIAL",
12 | C.POSIX_FADV_WILLNEED: "POSIX_FADV_WILLNEED",
13 | C.POSIX_FADV_DONTNEED: "POSIX_FADV_DONTNEED",
14 | C.POSIX_FADV_NOREUSE: "POSIX_FADV_NOREUSE",
15 | }
16 |
17 | func AnnotateFAdvice(arg Arg, pid int) {
18 | if str, ok := fadviceFlags[int(arg.Raw())]; ok {
19 | arg.SetAnnotation(str, true)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tracer/annotation/fallocate.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var fallocateModes = map[int]string{
6 | unix.FALLOC_FL_KEEP_SIZE: "FALLOC_FL_KEEP_SIZE",
7 | unix.FALLOC_FL_PUNCH_HOLE: "FALLOC_FL_PUNCH_HOLE",
8 | unix.FALLOC_FL_COLLAPSE_RANGE: "FALLOC_FL_COLLAPSE_RANGE",
9 | unix.FALLOC_FL_ZERO_RANGE: "FALLOC_FL_ZERO_RANGE",
10 | unix.FALLOC_FL_INSERT_RANGE: "FALLOC_FL_INSERT_RANGE",
11 | unix.FALLOC_FL_UNSHARE_RANGE: "FALLOC_FL_UNSHARE_RANGE",
12 | }
13 |
14 | func AnnotateFallocateMode(arg Arg, _ int) {
15 | if str, ok := fallocateModes[int(arg.Raw())]; ok {
16 | arg.SetAnnotation(str, true)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/annotation/fanotify.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var fanotifyFlags = map[int]string{
10 | unix.FAN_CLASS_PRE_CONTENT: "FAN_CLASS_PRE_CONTENT",
11 | unix.FAN_CLASS_CONTENT: "FAN_CLASS_CONTENT",
12 | unix.FAN_CLASS_NOTIF: "FAN_CLASS_NOTIF",
13 | unix.FAN_REPORT_FID: "FAN_REPORT_FID",
14 | unix.FAN_REPORT_NAME: "FAN_REPORT_NAME",
15 | unix.FAN_REPORT_DIR_FID: "FAN_REPORT_DIR_FID",
16 | unix.FAN_REPORT_TID: "FAN_REPORT_TID",
17 | unix.FAN_NONBLOCK: "FAN_NONBLOCK",
18 | unix.FAN_UNLIMITED_QUEUE: "FAN_UNLIMITED_QUEUE",
19 | unix.FAN_UNLIMITED_MARKS: "FAN_UNLIMITED_MARKS",
20 | unix.FAN_ENABLE_AUDIT: "FAN_ENABLE_AUDIT",
21 | }
22 |
23 | var fanotifyMarkFlags = map[int]string{
24 | unix.FAN_MARK_ADD: "FAN_MARK_ADD",
25 | unix.FAN_MARK_REMOVE: "FAN_MARK_REMOVE",
26 | unix.FAN_MARK_DONT_FOLLOW: "FAN_MARK_DONT_FOLLOW",
27 | unix.FAN_MARK_ONLYDIR: "FAN_MARK_ONLYDIR",
28 | unix.FAN_MARK_MOUNT: "FAN_MARK_MOUNT",
29 | unix.FAN_MARK_IGNORED_MASK: "FAN_MARK_IGNORED_MASK",
30 | unix.FAN_MARK_IGNORED_SURV_MODIFY: "FAN_MARK_IGNORED_SURV_MODIFY",
31 | unix.FAN_MARK_FLUSH: "FAN_MARK_FLUSH",
32 | unix.FAN_MARK_FILESYSTEM: "FAN_MARK_FILESYSTEM",
33 | }
34 |
35 | func AnnotateFANotifyFlags(arg Arg, pid int) {
36 | var joins []string
37 | for flag, str := range fanotifyFlags {
38 | if int(arg.Raw())&flag != 0 {
39 | joins = append(joins, str)
40 | }
41 | }
42 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
43 | }
44 |
45 | func AnnotateFANotifyEventFlags(arg Arg, pid int) {
46 | AnnotateOpenFlags(arg, pid)
47 | }
48 |
49 | func AnnotateFANotifyMarkFlags(arg Arg, pid int) {
50 | var joins []string
51 | for flag, str := range fanotifyMarkFlags {
52 | if int(arg.Raw())&flag != 0 {
53 | joins = append(joins, str)
54 | }
55 | }
56 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
57 | }
58 |
--------------------------------------------------------------------------------
/tracer/annotation/fcntl.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var fcntlCmds = map[int]string{
10 | unix.F_DUPFD: "F_DUPFD",
11 | unix.F_DUPFD_CLOEXEC: "F_DUPFD_CLOEXEC",
12 | unix.F_GETFD: "F_GETFD",
13 | unix.F_SETFD: "F_SETFD",
14 | unix.F_GETFL: "F_GETFL",
15 | unix.F_SETFL: "F_SETFL",
16 | unix.F_GETLK: "F_GETLK",
17 | unix.F_SETLK: "F_SETLK",
18 | unix.F_SETLKW: "F_SETLKW",
19 | unix.F_SETOWN: "F_SETOWN",
20 | unix.F_GETOWN: "F_GETOWN",
21 | unix.F_GETOWN_EX: "F_GETOWN_EX",
22 | unix.F_SETOWN_EX: "F_SETOWN_EX",
23 | unix.F_GETSIG: "F_GETSIG",
24 | unix.F_SETSIG: "F_SETSIG",
25 | unix.F_GETLEASE: "F_GETLEASE",
26 | unix.F_SETLEASE: "F_SETLEASE",
27 | unix.F_NOTIFY: "F_NOTIFY",
28 | unix.F_GETPIPE_SZ: "F_GETPIPE_SZ",
29 | unix.F_SETPIPE_SZ: "F_SETPIPE_SZ",
30 | }
31 |
32 | func AnnotateFcntlCmd(arg Arg, pid int) {
33 | if str, ok := fcntlCmds[int(arg.Raw())]; ok {
34 | arg.SetAnnotation(str, true)
35 | }
36 | }
37 |
38 | var atFlags = map[int]string{
39 | unix.AT_SYMLINK_NOFOLLOW: "AT_SYMLINK_NOFOLLOW",
40 | unix.AT_REMOVEDIR: "AT_REMOVEDIR",
41 | unix.AT_SYMLINK_FOLLOW: "AT_SYMLINK_FOLLOW",
42 | unix.AT_EMPTY_PATH: "AT_EMPTY_PATH",
43 | unix.AT_NO_AUTOMOUNT: "AT_NO_AUTOMOUNT",
44 | }
45 |
46 | func AnnotateAtFlags(arg Arg, pid int) {
47 | var joins []string
48 | for flag, str := range atFlags {
49 | if int(arg.Raw())&flag != 0 {
50 | joins = append(joins, str)
51 | }
52 | }
53 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
54 | }
55 |
--------------------------------------------------------------------------------
/tracer/annotation/fd.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strconv"
7 | "strings"
8 | "syscall"
9 |
10 | "github.com/liamg/grace/tracer/netw"
11 |
12 | "golang.org/x/sys/unix"
13 | )
14 |
15 | func AnnotateFd(arg Arg, pid int) {
16 |
17 | if path, err := os.Readlink(fmt.Sprintf("/proc/%d/fd/%d", pid, arg.Raw())); err == nil {
18 |
19 | switch {
20 | case strings.HasPrefix(path, "socket:["):
21 | fd := strings.TrimPrefix(path, "socket:[")
22 | fd = strings.TrimSuffix(fd, "]")
23 | if inode, err := strconv.Atoi(fd); err == nil {
24 | if str := socketInoToString(inode); str != "" {
25 | arg.SetAnnotation(str, false)
26 | return
27 | }
28 | }
29 | }
30 | arg.SetAnnotation(path, false)
31 | }
32 |
33 | if int32(arg.Raw()) == unix.AT_FDCWD {
34 | arg.SetAnnotation("AT_FDCWD", true)
35 | return
36 | }
37 |
38 | switch int(arg.Raw()) {
39 | case syscall.Stdin:
40 | arg.SetAnnotation("STDIN", false)
41 | case syscall.Stdout:
42 | arg.SetAnnotation("STDOUT", false)
43 | case syscall.Stderr:
44 | arg.SetAnnotation("STDERR", false)
45 | }
46 | }
47 |
48 | func socketInoToString(inode int) string {
49 | if conns, err := netw.ListConnections(); err == nil {
50 | for _, conn := range conns {
51 | if conn.INode == inode {
52 | return fmt.Sprintf("%s %s:%d -> %s:%d", conn.Protocol, conn.LocalAddress, conn.LocalPort, conn.RemoteAddress, conn.RemotePort)
53 | }
54 | }
55 | }
56 | return ""
57 | }
58 |
--------------------------------------------------------------------------------
/tracer/annotation/flock.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var flockOps = map[int]string{
6 | unix.LOCK_SH: "LOCK_SH",
7 | unix.LOCK_EX: "LOCK_EX",
8 | unix.LOCK_NB: "LOCK_NB",
9 | unix.LOCK_UN: "LOCK_UN",
10 | }
11 |
12 | func AnnotateFlockOperation(arg Arg, _ int) {
13 | if str, ok := flockOps[int(arg.Raw())]; ok {
14 | arg.SetAnnotation(str, true)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tracer/annotation/futex.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | var futexOps = map[int]string{
4 | 0: "FUTEX_WAIT",
5 | 1: "FUTEX_WAKE",
6 | 2: "FUTEX_FD",
7 | 3: "FUTEX_REQUEUE",
8 | 4: "FUTEX_CMP_REQUEUE",
9 | 5: "FUTEX_WAKE_OP",
10 | 6: "FUTEX_LOCK_PI",
11 | 7: "FUTEX_UNLOCK_PI",
12 | 8: "FUTEX_TRYLOCK_PI",
13 | 9: "FUTEX_WAIT_BITSET",
14 | 10: "FUTEX_WAKE_BITSET",
15 | 11: "FUTEX_WAIT_REQUEUE_PI",
16 | 12: "FUTEX_CMP_REQUEUE_PI",
17 | 128 | 0: "FUTEX_PRIVATE_FLAG|FUTEX_WAIT",
18 | 128 | 1: "FUTEX_PRIVATE_FLAG|FUTEX_WAKE",
19 | 128 | 2: "FUTEX_PRIVATE_FLAG|FUTEX_FD",
20 | 128 | 3: "FUTEX_PRIVATE_FLAG|FUTEX_REQUEUE",
21 | 128 | 4: "FUTEX_PRIVATE_FLAG|FUTEX_CMP_REQUEUE",
22 | 128 | 5: "FUTEX_PRIVATE_FLAG|FUTEX_WAKE_OP",
23 | 128 | 6: "FUTEX_PRIVATE_FLAG|FUTEX_LOCK_PI",
24 | 128 | 7: "FUTEX_PRIVATE_FLAG|FUTEX_UNLOCK_PI",
25 | 128 | 8: "FUTEX_PRIVATE_FLAG|FUTEX_TRYLOCK_PI",
26 | 128 | 9: "FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET",
27 | 128 | 10: "FUTEX_PRIVATE_FLAG|FUTEX_WAKE_BITSET",
28 | 128 | 11: "FUTEX_PRIVATE_FLAG|FUTEX_WAIT_REQUEUE_PI",
29 | 128 | 12: "FUTEX_PRIVATE_FLAG|FUTEX_CMP_REQUEUE_PI",
30 | 256 | 0: "FUTEX_CLOCK_REALTIME|FUTEX_WAIT",
31 | 256 | 1: "FUTEX_CLOCK_REALTIME|FUTEX_WAKE",
32 | 256 | 2: "FUTEX_CLOCK_REALTIME|FUTEX_FD",
33 | 256 | 3: "FUTEX_CLOCK_REALTIME|FUTEX_REQUEUE",
34 | 256 | 4: "FUTEX_CLOCK_REALTIME|FUTEX_CMP_REQUEUE",
35 | 256 | 5: "FUTEX_CLOCK_REALTIME|FUTEX_WAKE_OP",
36 | 256 | 6: "FUTEX_CLOCK_REALTIME|FUTEX_LOCK_PI",
37 | 256 | 7: "FUTEX_CLOCK_REALTIME|FUTEX_UNLOCK_PI",
38 | 256 | 8: "FUTEX_CLOCK_REALTIME|FUTEX_TRYLOCK_PI",
39 | 256 | 9: "FUTEX_CLOCK_REALTIME|FUTEX_WAIT_BITSET",
40 | 256 | 10: "FUTEX_CLOCK_REALTIME|FUTEX_WAKE_BITSET",
41 | 256 | 11: "FUTEX_CLOCK_REALTIME|FUTEX_WAIT_REQUEUE_PI",
42 | 256 | 12: "FUTEX_CLOCK_REALTIME|FUTEX_CMP_REQUEUE_PI",
43 | 384 | 0: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_WAIT",
44 | 384 | 1: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_WAKE",
45 | 384 | 2: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_FD",
46 | 384 | 3: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_REQUEUE",
47 | 384 | 4: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_CMP_REQUEUE",
48 | 384 | 5: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_WAKE_OP",
49 | 384 | 6: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_LOCK_PI",
50 | 384 | 7: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_UNLOCK_PI",
51 | 384 | 8: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_TRYLOCK_PI",
52 | 384 | 9: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET",
53 | 384 | 10: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_WAKE_BITSET",
54 | 384 | 11: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_WAIT_REQUEUE_PI",
55 | 384 | 12: "FUTEX_CLOCK_REALTIME|FUTEX_PRIVATE_FLAG|FUTEX_CMP_REQUEUE_PI",
56 | }
57 |
58 | func AnnotateFutexOp(arg Arg, pid int) {
59 | if s, ok := futexOps[int(arg.Raw())]; ok {
60 | arg.SetAnnotation(s, true)
61 | } else {
62 | AnnotateHex(arg, pid)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tracer/annotation/hex.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "fmt"
4 |
5 | func AnnotateHex(arg Arg, _ int) {
6 | arg.SetAnnotation(fmt.Sprintf("0x%x", arg.Raw()), true)
7 | }
8 |
--------------------------------------------------------------------------------
/tracer/annotation/ioprio.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | var ioPrioWhiches = map[int]string{
4 | 1: "IOPRIO_WHO_PROCESS",
5 | 2: "IOPRIO_WHO_PGRP",
6 | 3: "IOPRIO_WHO_USER",
7 | }
8 |
9 | func AnnotateIoPrioWhich(arg Arg, _ int) {
10 | if which, ok := ioPrioWhiches[int(arg.Raw())]; ok {
11 | arg.SetAnnotation(which, true)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tracer/annotation/ioring.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "strings"
4 |
5 | var ioringEnterFlags = map[int]string{
6 | 1: "IORING_ENTER_GETEVENTS",
7 | 2: "IORING_ENTER_SQ_WAKEUP",
8 | 4: "IORING_ENTER_SQ_WAIT",
9 | 8: "IORING_ENTER_EXT_ARG",
10 | 16: "IORING_ENTER_REGISTERED_RING",
11 | }
12 |
13 | func AnnotateIoUringEnterFlags(arg Arg, pid int) {
14 | var joins []string
15 | for flag, name := range ioringEnterFlags {
16 | if int(arg.Raw())&flag != 0 {
17 | joins = append(joins, name)
18 | }
19 | }
20 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
21 | }
22 |
23 | var ioringOpCodes = []string{
24 | "IORING_REGISTER_BUFFERS",
25 | "IORING_UNREGISTER_BUFFERS",
26 | "IORING_REGISTER_FILES",
27 | "IORING_UNREGISTER_FILES",
28 | "IORING_REGISTER_EVENTFD",
29 | "IORING_UNREGISTER_EVENTFD",
30 | "IORING_REGISTER_FILES_UPDATE",
31 | "IORING_REGISTER_EVENTFD_ASYNC",
32 | "IORING_REGISTER_PROBE",
33 | "IORING_REGISTER_PERSONALITY",
34 | "IORING_UNREGISTER_PERSONALITY",
35 | "IORING_REGISTER_RESTRICTIONS",
36 | "IORING_REGISTER_ENABLE_RINGS",
37 | "IORING_REGISTER_FILES2",
38 | "IORING_REGISTER_FILES_UPDATE2",
39 | "IORING_REGISTER_BUFFERS2",
40 | "IORING_REGISTER_BUFFERS_UPDATE",
41 | "IORING_REGISTER_IOWQ_AFF",
42 | "IORING_UNREGISTER_IOWQ_AFF",
43 | "IORING_REGISTER_IOWQ_MAX_WORKERS",
44 | "IORING_REGISTER_RING_FDS",
45 | "IORING_UNREGISTER_RING_FDS",
46 | "IORING_REGISTER_PBUF_RING",
47 | "IORING_UNREGISTER_PBUF_RING",
48 | "IORING_REGISTER_SYNC_CANCEL",
49 | "IORING_REGISTER_FILE_ALLOC_RANGE",
50 | }
51 |
52 | func AnnotateIORingOpCode(arg Arg, _ int) {
53 | opcode := int(arg.Raw())
54 | if opcode >= 0 && opcode < len(ioringOpCodes) {
55 | arg.SetAnnotation(ioringOpCodes[opcode], true)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tracer/annotation/kcmp.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | var kcmpTypes = map[int]string{
4 | 0: "KCMP_FILE",
5 | 1: "KCMP_VM",
6 | 2: "KCMP_FILES",
7 | 3: "KCMP_FS",
8 | 4: "KCMP_SIGHAND",
9 | 5: "KCMP_IO",
10 | 6: "KCMP_SYSVSEM",
11 | 7: "KCMP_TYPES",
12 | 8: "KCMP_EPOLL_TFD",
13 | }
14 |
15 | func AnnotateKcmpType(arg Arg, pid int) {
16 | if str, ok := kcmpTypes[int(arg.Raw())]; ok {
17 | arg.SetAnnotation(str, true)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tracer/annotation/kexec.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var kexecLoadFlags = map[int]string{
10 | unix.KEXEC_FILE_UNLOAD: "KEXEC_FILE_UNLOAD",
11 | unix.KEXEC_FILE_ON_CRASH: "KEXEC_FILE_ON_CRASH",
12 | unix.KEXEC_FILE_NO_INITRAMFS: "KEXEC_FILE_NO_INITRAMFS",
13 | }
14 |
15 | func AnnotateKexecFlags(arg Arg, _ int) {
16 | var joins []string
17 | for flag, name := range kexecLoadFlags {
18 | if int(arg.Raw())&flag != 0 {
19 | joins = append(joins, name)
20 | }
21 | }
22 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/key.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var keyctlCmds = map[int]string{
6 | unix.KEYCTL_GET_KEYRING_ID: "KEYCTL_GET_KEYRING_ID",
7 | unix.KEYCTL_JOIN_SESSION_KEYRING: "KEYCTL_JOIN_SESSION_KEYRING",
8 | unix.KEYCTL_UPDATE: "KEYCTL_UPDATE",
9 | unix.KEYCTL_REVOKE: "KEYCTL_REVOKE",
10 | unix.KEYCTL_DESCRIBE: "KEYCTL_DESCRIBE",
11 | unix.KEYCTL_CLEAR: "KEYCTL_CLEAR",
12 | unix.KEYCTL_LINK: "KEYCTL_LINK",
13 | unix.KEYCTL_UNLINK: "KEYCTL_UNLINK",
14 | unix.KEYCTL_SEARCH: "KEYCTL_SEARCH",
15 | unix.KEYCTL_READ: "KEYCTL_READ",
16 | unix.KEYCTL_CHOWN: "KEYCTL_CHOWN",
17 | unix.KEYCTL_SETPERM: "KEYCTL_SETPERM",
18 | unix.KEYCTL_INSTANTIATE: "KEYCTL_INSTANTIATE",
19 | unix.KEYCTL_NEGATE: "KEYCTL_NEGATE",
20 | unix.KEYCTL_SET_REQKEY_KEYRING: "KEYCTL_SET_REQKEY_KEYRING",
21 | unix.KEYCTL_SET_TIMEOUT: "KEYCTL_SET_TIMEOUT",
22 | unix.KEYCTL_ASSUME_AUTHORITY: "KEYCTL_ASSUME_AUTHORITY",
23 | unix.KEYCTL_GET_SECURITY: "KEYCTL_GET_SECURITY",
24 | unix.KEYCTL_SESSION_TO_PARENT: "KEYCTL_SESSION_TO_PARENT",
25 | unix.KEYCTL_REJECT: "KEYCTL_REJECT",
26 | unix.KEYCTL_INSTANTIATE_IOV: "KEYCTL_INSTANTIATE_IOV",
27 | unix.KEYCTL_INVALIDATE: "KEYCTL_INVALIDATE",
28 | }
29 |
30 | func AnnotateKeyctlCommand(arg Arg, pid int) {
31 | if cmd, ok := keyctlCmds[int(arg.Raw())]; ok {
32 | arg.SetAnnotation(cmd, true)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tracer/annotation/keyring.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var keyringIDs = map[int]string{
6 | unix.KEY_SPEC_THREAD_KEYRING: "KEY_SPEC_THREAD_KEYRING",
7 | unix.KEY_SPEC_PROCESS_KEYRING: "KEY_SPEC_PROCESS_KEYRING",
8 | unix.KEY_SPEC_SESSION_KEYRING: "KEY_SPEC_SESSION_KEYRING",
9 | unix.KEY_SPEC_USER_KEYRING: "KEY_SPEC_USER_KEYRING",
10 | unix.KEY_SPEC_USER_SESSION_KEYRING: "KEY_SPEC_USER_SESSION_KEYRING",
11 | unix.KEY_SPEC_GROUP_KEYRING: "KEY_SPEC_GROUP_KEYRING",
12 | }
13 |
14 | func AnnotateKeyringID(arg Arg, _ int) {
15 | if id, ok := keyringIDs[int(arg.Raw())]; ok {
16 | arg.SetAnnotation(id, true)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/annotation/landlock.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var landlockFlags = map[int]string{
10 | unix.LANDLOCK_CREATE_RULESET_VERSION: "LANDLOCK_CREATE_RULESET_VERSION",
11 | }
12 |
13 | func AnnotateLandlockFlags(arg Arg, _ int) {
14 | var joins []string
15 | for flag, str := range landlockFlags {
16 | if int(arg.Raw())&flag != 0 {
17 | joins = append(joins, str)
18 | }
19 | }
20 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
21 | }
22 |
23 | var landlockRuleTypes = map[int]string{
24 | unix.LANDLOCK_RULE_PATH_BENEATH: "LANDLOCK_RULE_PATH_BENEATH",
25 | }
26 |
27 | func AnnotateLandlockRuleType(arg Arg, _ int) {
28 | var joins []string
29 | for flag, str := range landlockRuleTypes {
30 | if int(arg.Raw())&flag != 0 {
31 | joins = append(joins, str)
32 | }
33 | }
34 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
35 | }
36 |
--------------------------------------------------------------------------------
/tracer/annotation/madvise.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func AnnotateMAdviseAdvice(arg Arg, _ int) {
10 | flags := map[int]string{
11 | unix.MADV_NORMAL: "MADV_NORMAL",
12 | unix.MADV_RANDOM: "MADV_RANDOM",
13 | unix.MADV_SEQUENTIAL: "MADV_SEQUENTIAL",
14 | unix.MADV_WILLNEED: "MADV_WILLNEED",
15 | unix.MADV_DONTNEED: "MADV_DONTNEED",
16 | unix.MADV_REMOVE: "MADV_REMOVE",
17 | unix.MADV_DONTFORK: "MADV_DONTFORK",
18 | unix.MADV_DOFORK: "MADV_DOFORK",
19 | unix.MADV_MERGEABLE: "MADV_MERGEABLE",
20 | unix.MADV_UNMERGEABLE: "MADV_UNMERGEABLE",
21 | unix.MADV_HUGEPAGE: "MADV_HUGEPAGE",
22 | unix.MADV_NOHUGEPAGE: "MADV_NOHUGEPAGE",
23 | unix.MADV_DONTDUMP: "MADV_DONTDUMP",
24 | unix.MADV_DODUMP: "MADV_DODUMP",
25 | unix.MADV_HWPOISON: "MADV_HWPOISON",
26 | unix.MADV_COLD: "MADV_COLD",
27 | unix.MADV_PAGEOUT: "MADV_PAGEOUT",
28 | }
29 | var joins []string
30 | for flag, str := range flags {
31 | if int(arg.Raw())&flag != 0 {
32 | joins = append(joins, str)
33 | }
34 | }
35 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
36 | }
37 |
--------------------------------------------------------------------------------
/tracer/annotation/mbind.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "C"
4 |
5 | var numaModeFlags = map[int]string{
6 | 0: "MPOL_DEFAULT",
7 | 1: "MPOL_PREFERRED",
8 | 2: "MPOL_BIND",
9 | 3: "MPOL_INTERLEAVE",
10 | 4: "MPOL_LOCAL",
11 | 5: "MPOL_MAX",
12 | 6: "MPOL_F_STATIC_NODES",
13 | 7: "MPOL_F_RELATIVE_NODES",
14 | 8: "MPOL_MF_STRICT",
15 | 9: "MPOL_MF_MOVE",
16 | 10: "MPOL_MF_MOVE_ALL",
17 | }
18 |
19 | func AnnotateNumaModeFlag(arg Arg, pid int) {
20 | if str, ok := numaModeFlags[int(arg.Raw())]; ok {
21 | arg.SetAnnotation(str, true)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/membarrier.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "strings"
4 |
5 | /*
6 | #include
7 | */
8 | import "C"
9 |
10 | var membarrierCmds = map[int]string{
11 | C.MEMBARRIER_CMD_QUERY: "MEMBARRIER_CMD_QUERY",
12 | C.MEMBARRIER_CMD_GLOBAL: "MEMBARRIER_CMD_GLOBAL",
13 | C.MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED: "MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED",
14 | C.MEMBARRIER_CMD_PRIVATE_EXPEDITED: "MEMBARRIER_CMD_PRIVATE_EXPEDITED",
15 | C.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED: "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED",
16 | C.MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE: "MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE",
17 | C.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE: "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE",
18 | }
19 |
20 | var membarrierCmdFlags = map[int]string{
21 | 1: "MEMBARRIER_CMD_FLAG_CPU",
22 | }
23 |
24 | func AnnotateMembarrierCmd(arg Arg, _ int) {
25 | if name, ok := membarrierCmds[int(arg.Raw())]; ok {
26 | arg.SetAnnotation(name, true)
27 | }
28 | }
29 |
30 | func AnnotateMembarrierCmdFlags(arg Arg, _ int) {
31 | var joins []string
32 | for flag, name := range membarrierCmdFlags {
33 | if int(arg.Raw())&flag != 0 {
34 | joins = append(joins, name)
35 | }
36 | }
37 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
38 | }
39 |
--------------------------------------------------------------------------------
/tracer/annotation/memfd.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var memfdFlags = map[int]string{
10 | unix.MFD_CLOEXEC: "MFD_CLOEXEC",
11 | unix.MFD_ALLOW_SEALING: "MFD_ALLOW_SEALING",
12 | unix.MFD_HUGETLB: "MFD_HUGETLB",
13 | unix.MFD_HUGE_16GB: "MFD_HUGE_16GB",
14 | unix.MFD_HUGE_16MB: "MFD_HUGE_16MB",
15 | unix.MFD_HUGE_1GB: "MFD_HUGE_1GB",
16 | unix.MFD_HUGE_1MB: "MFD_HUGE_1MB",
17 | unix.MFD_HUGE_256MB: "MFD_HUGE_256MB",
18 | unix.MFD_HUGE_2GB: "MFD_HUGE_2GB",
19 | unix.MFD_HUGE_2MB: "MFD_HUGE_2MB",
20 | unix.MFD_HUGE_32MB: "MFD_HUGE_32MB",
21 | unix.MFD_HUGE_512KB: "MFD_HUGE_512KB",
22 | unix.MFD_HUGE_512MB: "MFD_HUGE_512MB",
23 | unix.MFD_HUGE_64KB: "MFD_HUGE_64KB",
24 | unix.MFD_HUGE_8MB: "MFD_HUGE_8MB",
25 | }
26 |
27 | func AnnotateMemfdFlags(arg Arg, pid int) {
28 | var joins []string
29 | for flag, name := range memfdFlags {
30 | if int(arg.Raw())&flag != 0 {
31 | joins = append(joins, name)
32 | }
33 | }
34 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
35 | }
36 |
--------------------------------------------------------------------------------
/tracer/annotation/mlock.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var mlockFlags = map[int]string{
10 | unix.MCL_CURRENT: "MCL_CURRENT",
11 | unix.MCL_FUTURE: "MCL_FUTURE",
12 | unix.MCL_ONFAULT: "MCL_ONFAULT",
13 | }
14 |
15 | func AnnotateMlockFlags(arg Arg, _ int) {
16 | var joins []string
17 | for flag, str := range mlockFlags {
18 | if int(arg.Raw())&flag != 0 {
19 | joins = append(joins, str)
20 | }
21 | }
22 | arg.SetAnnotation(strings.Join(joins, "|"), true)
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/mmap.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func AnnotateMMapFlags(arg Arg, _ int) {
10 | var joins []string
11 |
12 | switch arg.Raw() & 0x3 {
13 | case unix.MAP_SHARED:
14 | joins = append(joins, "MAP_SHARED")
15 | case unix.MAP_PRIVATE:
16 | joins = append(joins, "MAP_PRIVATE")
17 | case unix.MAP_SHARED_VALIDATE:
18 | joins = append(joins, "MAP_SHARED_VALIDATE")
19 | }
20 |
21 | mapConsts := map[int]string{
22 | unix.MAP_32BIT: "MAP_32BIT",
23 | unix.MAP_ANONYMOUS: "MAP_ANONYMOUS",
24 | unix.MAP_DENYWRITE: "MAP_DENYWRITE",
25 | unix.MAP_EXECUTABLE: "MAP_EXECUTABLE",
26 | unix.MAP_FILE: "MAP_FILE",
27 | unix.MAP_FIXED: "MAP_FIXED",
28 | unix.MAP_FIXED_NOREPLACE: "MAP_FIXED_NOREPLACE",
29 | unix.MAP_GROWSDOWN: "MAP_GROWSDOWN",
30 | unix.MAP_HUGETLB: "MAP_HUGETLB",
31 | 21 << unix.MAP_HUGE_SHIFT: "MAP_HUGE_2MB",
32 | 30 << unix.MAP_HUGE_SHIFT: "MAP_HUGE_1GB",
33 | unix.MAP_LOCKED: "MAP_LOCKED",
34 | unix.MAP_NONBLOCK: "MAP_NONBLOCK",
35 | unix.MAP_NORESERVE: "MAP_NORESERVE",
36 | unix.MAP_POPULATE: "MAP_POPULATE",
37 | unix.MAP_STACK: "MAP_STACK",
38 | unix.MAP_SYNC: "MAP_SYNC",
39 | }
40 |
41 | for flag, str := range mapConsts {
42 | if arg.Raw()&uintptr(flag) > 0 {
43 | joins = append(joins, str)
44 | }
45 | }
46 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
47 | }
48 |
--------------------------------------------------------------------------------
/tracer/annotation/module.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "C"
4 | import (
5 | "strings"
6 |
7 | "golang.org/x/sys/unix"
8 | )
9 |
10 | var deleteModuleFlags = map[int]string{
11 | unix.O_NONBLOCK: "O_NONBLOCK",
12 | unix.O_TRUNC: "O_TRUNC",
13 | }
14 |
15 | func AnnotateDeleteModuleFlags(arg Arg, _ int) {
16 | var joins []string
17 | for flag, name := range deleteModuleFlags {
18 | if int(arg.Raw())&flag != 0 {
19 | joins = append(joins, name)
20 | }
21 | }
22 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
23 | }
24 |
25 | var queryModuleWhiches = map[int]string{
26 | 1: "QM_MODULES",
27 | 2: "QM_DEPS",
28 | 3: "QM_REFS",
29 | 4: "QM_SYMBOLS",
30 | 5: "QM_INFO",
31 | 6: "QM_EXPORTS",
32 | }
33 |
34 | func AnnotateQueryModuleWhich(arg Arg, _ int) {
35 | if name, ok := queryModuleWhiches[int(arg.Raw())]; ok {
36 | arg.SetAnnotation(name, true)
37 | }
38 | }
39 |
40 | var moduleInitFlags = map[int]string{
41 | unix.MODULE_INIT_IGNORE_MODVERSIONS: "MODULE_INIT_IGNORE_MODVERSIONS",
42 | unix.MODULE_INIT_IGNORE_VERMAGIC: "MODULE_INIT_IGNORE_VERMAGIC",
43 | }
44 |
45 | func AnnotateModuleInitFlags(arg Arg, _ int) {
46 | var joins []string
47 | for flag, name := range moduleInitFlags {
48 | if int(arg.Raw())&flag != 0 {
49 | joins = append(joins, name)
50 | }
51 | }
52 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
53 | }
54 |
--------------------------------------------------------------------------------
/tracer/annotation/mount.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var mountFlags = map[int]string{
10 | unix.MS_BIND: "MS_BIND",
11 | unix.MS_DIRSYNC: "MS_DIRSYNC",
12 | unix.MS_MANDLOCK: "MS_MANDLOCK",
13 | unix.MS_MOVE: "MS_MOVE",
14 | unix.MS_NOATIME: "MS_NOATIME",
15 | unix.MS_NODEV: "MS_NODEV",
16 | unix.MS_NODIRATIME: "MS_NODIRATIME",
17 | unix.MS_NOEXEC: "MS_NOEXEC",
18 | unix.MS_NOSUID: "MS_NOSUID",
19 | unix.MS_RDONLY: "MS_RDONLY",
20 | unix.MS_REC: "MS_REC",
21 | unix.MS_RELATIME: "MS_RELATIME",
22 | unix.MS_REMOUNT: "MS_REMOUNT",
23 | unix.MS_SILENT: "MS_SILENT",
24 | unix.MS_STRICTATIME: "MS_STRICTATIME",
25 | unix.MS_SYNCHRONOUS: "MS_SYNCHRONOUS",
26 | }
27 |
28 | func AnnotateMountFlags(arg Arg, _ int) {
29 | var joins []string
30 | for flag, name := range mountFlags {
31 | if int(arg.Raw())&flag != 0 {
32 | joins = append(joins, name)
33 | }
34 | }
35 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
36 | }
37 |
38 | var umountFlags = map[int]string{
39 | unix.MNT_FORCE: "MNT_FORCE",
40 | unix.MNT_DETACH: "MNT_DETACH",
41 | unix.MNT_EXPIRE: "MNT_EXPIRE",
42 | unix.UMOUNT_NOFOLLOW: "UMOUNT_NOFOLLOW",
43 | }
44 |
45 | func AnnotateUmountFlags(arg Arg, _ int) {
46 | var joins []string
47 | for flag, name := range umountFlags {
48 | if int(arg.Raw())&flag != 0 {
49 | joins = append(joins, name)
50 | }
51 | }
52 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
53 | }
54 |
--------------------------------------------------------------------------------
/tracer/annotation/mremap.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "strings"
4 |
5 | // see https://github.com/torvalds/linux/blob/master/include/uapi/linux/mman.h
6 | func AnnotateMRemapFlags(arg Arg, _ int) {
7 | flags := map[int]string{
8 | 1: "MREMAP_MAYMOVE",
9 | 2: "MREMAP_FIXED",
10 | 4: "MREMAP_DONTUNMAP",
11 | }
12 | var joins []string
13 | for flag, str := range flags {
14 | if int(arg.Raw())&flag != 0 {
15 | joins = append(joins, str)
16 | }
17 | }
18 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
19 | }
20 |
--------------------------------------------------------------------------------
/tracer/annotation/msg.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var msgFlags = map[int]string{
10 | unix.MSG_OOB: "MSG_OOB",
11 | unix.MSG_PEEK: "MSG_PEEK",
12 | unix.MSG_DONTROUTE: "MSG_DONTROUTE",
13 | unix.MSG_CTRUNC: "MSG_CTRUNC",
14 | unix.MSG_PROXY: "MSG_PROXY",
15 | unix.MSG_TRUNC: "MSG_TRUNC",
16 | unix.MSG_DONTWAIT: "MSG_DONTWAIT",
17 | unix.MSG_EOR: "MSG_EOR",
18 | unix.MSG_WAITALL: "MSG_WAITALL",
19 | unix.MSG_FIN: "MSG_FIN",
20 | unix.MSG_SYN: "MSG_SYN",
21 | unix.MSG_CONFIRM: "MSG_CONFIRM",
22 | unix.MSG_RST: "MSG_RST",
23 | unix.MSG_ERRQUEUE: "MSG_ERRQUEUE",
24 | unix.MSG_NOSIGNAL: "MSG_NOSIGNAL",
25 | unix.MSG_MORE: "MSG_MORE",
26 | unix.MSG_WAITFORONE: "MSG_WAITFORONE",
27 | unix.MSG_FASTOPEN: "MSG_FASTOPEN",
28 | unix.MSG_CMSG_CLOEXEC: "MSG_CMSG_CLOEXEC",
29 | }
30 |
31 | func AnnotateMsgFlags(arg Arg, _ int) {
32 | var joins []string
33 | for flag, str := range msgFlags {
34 | if arg.Raw()&uintptr(flag) != 0 {
35 | joins = append(joins, str)
36 | }
37 | }
38 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
39 | }
40 |
41 | func AnnotateMsgType(arg Arg, pid int) {
42 | // TODO:
43 | }
44 |
--------------------------------------------------------------------------------
/tracer/annotation/msync.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var mSyncFlags = map[int]string{
10 | unix.MS_ASYNC: "MS_ASYNC",
11 | unix.MS_INVALIDATE: "MS_INVALIDATE",
12 | unix.MS_SYNC: "MS_SYNC",
13 | }
14 |
15 | func AnnotateMSyncFlags(arg Arg, _ int) {
16 | var joins []string
17 | for flag, str := range mSyncFlags {
18 | if int(arg.Raw())&flag != 0 {
19 | joins = append(joins, str)
20 | }
21 | }
22 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/null.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | func AnnotateNull(arg Arg, _ int) {
4 | if arg.Raw() == 0 {
5 | arg.SetAnnotation("NULL", true)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tracer/annotation/open.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var openFlags = map[int]string{
10 | unix.O_APPEND: "O_APPEND",
11 | unix.O_ASYNC: "O_ASYNC",
12 | unix.O_CLOEXEC: "O_CLOEXEC",
13 | unix.O_CREAT: "O_CREAT",
14 | unix.O_DIRECT: "O_DIRECT",
15 | unix.O_DIRECTORY: "O_DIRECTORY",
16 | unix.O_DSYNC: "O_DSYNC",
17 | unix.O_EXCL: "O_EXCL",
18 | unix.O_NOATIME: "O_NOATIME",
19 | unix.O_NOCTTY: "O_NOCTTY",
20 | unix.O_NOFOLLOW: "O_NOFOLLOW",
21 | unix.O_NONBLOCK: "O_NONBLOCK",
22 | unix.O_PATH: "O_PATH",
23 | unix.O_SYNC: "O_SYNC",
24 | unix.O_TMPFILE: "O_TMPFILE",
25 | unix.O_TRUNC: "O_TRUNC",
26 | unix.O_RDONLY: "O_RDONLY",
27 | unix.O_WRONLY: "O_WRONLY",
28 | unix.O_RDWR: "O_RDWR",
29 | }
30 |
31 | func AnnotateOpenFlags(arg Arg, _ int) {
32 | var joins []string
33 | for flag, name := range openFlags {
34 | if (int(arg.Raw())&flag != 0) || (int(arg.Raw()) == flag) {
35 | joins = append(joins, name)
36 | }
37 | }
38 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
39 | }
40 |
41 | var resolveFlags = map[int]string{
42 | unix.RESOLVE_BENEATH: "RESOLVE_BENEATH",
43 | unix.RESOLVE_IN_ROOT: "RESOLVE_IN_ROOT",
44 | unix.RESOLVE_NO_XDEV: "RESOLVE_NO_XDEV",
45 | unix.RESOLVE_NO_MAGICLINKS: "RESOLVE_NO_MAGICLINKS",
46 | unix.RESOLVE_NO_SYMLINKS: "RESOLVE_NO_SYMLINKS",
47 | // RESOLVE_CACHED is not available...
48 | }
49 |
50 | func AnnotateResolveFlags(arg Arg, _ int) {
51 | var joins []string
52 | for flag, name := range resolveFlags {
53 | if int(arg.Raw())&flag != 0 {
54 | joins = append(joins, name)
55 | }
56 | }
57 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
58 | }
59 |
--------------------------------------------------------------------------------
/tracer/annotation/p2.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var p2Flags = map[int]string{
10 | unix.RWF_APPEND: "RWF_APPEND",
11 | unix.RWF_DSYNC: "RWF_DSYNC",
12 | unix.RWF_HIPRI: "RWF_HIPRI",
13 | unix.RWF_NOWAIT: "RWF_NOWAIT",
14 | unix.RWF_SYNC: "RWF_SYNC",
15 | }
16 |
17 | func AnnotatePReadWrite2Flags(arg Arg, _ int) {
18 | var joins []string
19 | for flag, str := range p2Flags {
20 | if int(arg.Raw())&flag != 0 {
21 | joins = append(joins, str)
22 | }
23 | }
24 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
25 | }
26 |
--------------------------------------------------------------------------------
/tracer/annotation/perf.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var perfFlags = map[int]string{
10 | unix.PERF_FLAG_FD_CLOEXEC: "PERF_FLAG_FD_CLOEXEC",
11 | unix.PERF_FLAG_FD_OUTPUT: "PERF_FLAG_FD_OUTPUT",
12 | unix.PERF_FLAG_FD_NO_GROUP: "PERF_FLAG_FD_NO_GROUP",
13 | unix.PERF_FLAG_PID_CGROUP: "PERF_FLAG_PID_CGROUP",
14 | }
15 |
16 | func AnnotatePerfFlags(arg Arg, _ int) {
17 | var joins []string
18 | for flag, str := range perfFlags {
19 | if int(arg.Raw())&flag != 0 {
20 | joins = append(joins, str)
21 | }
22 | }
23 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
24 | }
25 |
--------------------------------------------------------------------------------
/tracer/annotation/pkey.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | var pkeyAccessRights = map[int]string{
4 | 1: "PKEY_DISABLE_ACCESS",
5 | 2: "PKEY_DISABLE_WRITE",
6 | }
7 |
8 | func AnnotatePkeyAccessRights(arg Arg, _ int) {
9 | if name, ok := pkeyAccessRights[int(arg.Raw())]; ok {
10 | arg.SetAnnotation(name, true)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/tracer/annotation/prctl.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var prctlOptions = map[int]string{
6 | unix.PR_CAP_AMBIENT: "PR_CAP_AMBIENT",
7 | unix.PR_CAP_AMBIENT_RAISE: "PR_CAP_AMBIENT_RAISE",
8 | unix.PR_CAP_AMBIENT_LOWER: "PR_CAP_AMBIENT_LOWER",
9 | unix.PR_CAP_AMBIENT_IS_SET: "PR_CAP_AMBIENT_IS_SET",
10 | unix.PR_CAP_AMBIENT_CLEAR_ALL: "PR_CAP_AMBIENT_CLEAR_ALL",
11 | unix.PR_CAPBSET_READ: "PR_CAPBSET_READ",
12 | unix.PR_CAPBSET_DROP: "PR_CAPBSET_DROP",
13 | unix.PR_SET_CHILD_SUBREAPER: "PR_SET_CHILD_SUBREAPER",
14 | unix.PR_GET_CHILD_SUBREAPER: "PR_GET_CHILD_SUBREAPER",
15 | unix.PR_SET_ENDIAN: "PR_SET_ENDIAN",
16 | unix.PR_GET_ENDIAN: "PR_GET_ENDIAN",
17 | unix.PR_SET_FPEMU: "PR_SET_FPEMU",
18 | unix.PR_GET_FPEMU: "PR_GET_FPEMU",
19 | unix.PR_SET_FPEXC: "PR_SET_FPEXC",
20 | unix.PR_GET_FPEXC: "PR_GET_FPEXC",
21 | unix.PR_SET_FP_MODE: "PR_SET_FP_MODE",
22 | unix.PR_GET_FP_MODE: "PR_GET_FP_MODE",
23 | unix.PR_MPX_ENABLE_MANAGEMENT: "PR_MPX_ENABLE_MANAGEMENT",
24 | unix.PR_MPX_DISABLE_MANAGEMENT: "PR_MPX_DISABLE_MANAGEMENT",
25 | unix.PR_SET_KEEPCAPS: "PR_SET_KEEPCAPS",
26 | unix.PR_GET_KEEPCAPS: "PR_GET_KEEPCAPS",
27 | unix.PR_MCE_KILL: "PR_MCE_KILL",
28 | unix.PR_MCE_KILL_GET: "PR_MCE_KILL_GET",
29 | unix.PR_SET_MM: "PR_SET_MM",
30 | unix.PR_SET_MM_START_STACK: "PR_SET_MM_START_STACK",
31 | unix.PR_SET_MM_START_BRK: "PR_SET_MM_START_BRK",
32 | unix.PR_SET_MM_EXE_FILE: "PR_SET_MM_EXE_FILE",
33 | unix.PR_SET_MM_MAP: "PR_SET_MM_MAP",
34 | unix.PR_SET_NAME: "PR_SET_NAME",
35 | unix.PR_GET_NAME: "PR_GET_NAME",
36 | unix.PR_SET_NO_NEW_PRIVS: "PR_SET_NO_NEW_PRIVS",
37 | unix.PR_GET_NO_NEW_PRIVS: "PR_GET_NO_NEW_PRIVS",
38 | unix.PR_SET_PTRACER: "PR_SET_PTRACER",
39 | unix.PR_SET_SECCOMP: "PR_SET_SECCOMP",
40 | unix.PR_GET_SECCOMP: "PR_GET_SECCOMP",
41 | unix.PR_SET_SECUREBITS: "PR_SET_SECUREBITS",
42 | unix.PR_GET_SECUREBITS: "PR_GET_SECUREBITS",
43 | unix.PR_SET_THP_DISABLE: "PR_SET_THP_DISABLE",
44 | unix.PR_TASK_PERF_EVENTS_DISABLE: "PR_TASK_PERF_EVENTS_DISABLE",
45 | unix.PR_TASK_PERF_EVENTS_ENABLE: "PR_TASK_PERF_EVENTS_ENABLE",
46 | unix.PR_GET_THP_DISABLE: "PR_GET_THP_DISABLE",
47 | unix.PR_GET_TID_ADDRESS: "PR_GET_TID_ADDRESS",
48 | unix.PR_SET_TIMERSLACK: "PR_SET_TIMERSLACK",
49 | unix.PR_GET_TIMERSLACK: "PR_GET_TIMERSLACK",
50 | unix.PR_SET_TSC: "PR_SET_TSC",
51 | unix.PR_GET_TSC: "PR_GET_TSC",
52 | unix.PR_MCE_KILL_CLEAR: "PR_MCE_KILL_CLEAR",
53 | unix.PR_SET_VMA: "PR_SET_VMA",
54 | }
55 |
56 | func AnnotatePrctlOption(arg Arg, _ int) {
57 | if s, ok := prctlOptions[int(arg.Raw())]; ok {
58 | arg.SetAnnotation(s, true)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tracer/annotation/priority.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var priorityWhiches = map[int]string{
6 | unix.PRIO_PROCESS: "PRIO_PROCESS",
7 | unix.PRIO_PGRP: "PRIO_PGRP",
8 | unix.PRIO_USER: "PRIO_USER",
9 | }
10 |
11 | func AnnotatePriorityWhich(arg Arg, _ int) {
12 | if s, ok := priorityWhiches[int(arg.Raw())]; ok {
13 | arg.SetAnnotation(s, true)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tracer/annotation/prot.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func AnnotateProt(arg Arg, _ int) {
10 | if arg.Raw() == unix.PROT_NONE {
11 | arg.SetAnnotation("PROT_NONE", true)
12 | return
13 | }
14 | var joins []string
15 | if arg.Raw()&unix.PROT_READ > 0 {
16 | joins = append(joins, "PROT_READ")
17 | }
18 | if arg.Raw()&unix.PROT_WRITE > 0 {
19 | joins = append(joins, "PROT_WRITE")
20 | }
21 | if arg.Raw()&unix.PROT_EXEC > 0 {
22 | joins = append(joins, "PROT_EXEC")
23 | }
24 | if arg.Raw()&unix.PROT_GROWSUP > 0 {
25 | joins = append(joins, "PROT_GROWSUP")
26 | }
27 | if arg.Raw()&unix.PROT_GROWSDOWN > 0 {
28 | joins = append(joins, "PROT_GROWSDOWN")
29 | }
30 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
31 | }
32 |
--------------------------------------------------------------------------------
/tracer/annotation/ptrace.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var ptraceRequests = map[int]string{
6 | unix.PTRACE_TRACEME: "PTRACE_TRACEME",
7 | unix.PTRACE_PEEKTEXT: "PTRACE_PEEKTEXT",
8 | unix.PTRACE_PEEKDATA: "PTRACE_PEEKDATA",
9 | unix.PTRACE_PEEKUSR: "PTRACE_PEEKUSR",
10 | unix.PTRACE_POKETEXT: "PTRACE_POKETEXT",
11 | unix.PTRACE_POKEDATA: "PTRACE_POKEDATA",
12 | unix.PTRACE_POKEUSR: "PTRACE_POKEUSR",
13 | unix.PTRACE_CONT: "PTRACE_CONT",
14 | unix.PTRACE_KILL: "PTRACE_KILL",
15 | unix.PTRACE_SINGLESTEP: "PTRACE_SINGLESTEP",
16 | unix.PTRACE_GETREGS: "PTRACE_GETREGS",
17 | unix.PTRACE_SETREGS: "PTRACE_SETREGS",
18 | unix.PTRACE_GETFPREGS: "PTRACE_GETFPREGS",
19 | unix.PTRACE_SETFPREGS: "PTRACE_SETFPREGS",
20 | unix.PTRACE_ATTACH: "PTRACE_ATTACH",
21 | unix.PTRACE_DETACH: "PTRACE_DETACH",
22 | unix.PTRACE_GETFPXREGS: "PTRACE_GETFPXREGS",
23 | unix.PTRACE_SETFPXREGS: "PTRACE_SETFPXREGS",
24 | unix.PTRACE_SYSCALL: "PTRACE_SYSCALL",
25 | unix.PTRACE_SETOPTIONS: "PTRACE_SETOPTIONS",
26 | unix.PTRACE_GETEVENTMSG: "PTRACE_GETEVENTMSG",
27 | unix.PTRACE_GETSIGINFO: "PTRACE_GETSIGINFO",
28 | unix.PTRACE_SETSIGINFO: "PTRACE_SETSIGINFO",
29 | unix.PTRACE_GETREGSET: "PTRACE_GETREGSET",
30 | unix.PTRACE_SETREGSET: "PTRACE_SETREGSET",
31 | unix.PTRACE_SEIZE: "PTRACE_SEIZE",
32 | unix.PTRACE_INTERRUPT: "PTRACE_INTERRUPT",
33 | unix.PTRACE_LISTEN: "PTRACE_LISTEN",
34 | unix.PTRACE_PEEKSIGINFO: "PTRACE_PEEKSIGINFO",
35 | unix.PTRACE_GETSIGMASK: "PTRACE_GETSIGMASK",
36 | unix.PTRACE_SETSIGMASK: "PTRACE_SETSIGMASK",
37 | }
38 |
39 | func AnnotatePtraceRequest(arg Arg, _ int) {
40 | if name, ok := ptraceRequests[int(arg.Raw())]; ok {
41 | arg.SetAnnotation(name, true)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tracer/annotation/quotactl.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | */
6 | import "C"
7 |
8 | var quotactlCmds = map[uintptr]string{
9 | C.Q_QUOTAON: "Q_QUOTAON",
10 | C.Q_QUOTAOFF: "Q_QUOTAOFF",
11 | }
12 |
13 | func AnnotateQuotactlCmd(arg Arg, _ int) {
14 | if cmd, ok := quotactlCmds[arg.Raw()]; ok {
15 | arg.SetAnnotation(cmd, true)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tracer/annotation/random.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var randomFlags = map[int]string{
10 | unix.GRND_RANDOM: "GRND_RANDOM",
11 | unix.GRND_NONBLOCK: "GRND_NONBLOCK",
12 | }
13 |
14 | func AnnotateRandomFlags(arg Arg, _ int) {
15 | var joins []string
16 | for flag, name := range randomFlags {
17 | if int(arg.Raw())&flag != 0 {
18 | joins = append(joins, name)
19 | }
20 | }
21 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
22 | }
23 |
--------------------------------------------------------------------------------
/tracer/annotation/reboot.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "C"
4 |
5 | // from reboot(2) manpages
6 | var rebootMagics = map[uintptr]string{
7 | 0xfee1dead: "LINUX_REBOOT_MAGIC1",
8 | 672274793: "LINUX_REBOOT_MAGIC2",
9 | 85072278: "LINUX_REBOOT_MAGIC2A",
10 | 369367448: "LINUX_REBOOT_MAGIC2B",
11 | 537993216: "LINUX_REBOOT_MAGIC2C",
12 | }
13 |
14 | func AnnotateRebootMagic(arg Arg, _ int) {
15 | if magic, ok := rebootMagics[arg.Raw()]; ok {
16 | arg.SetAnnotation(magic, true)
17 | }
18 | }
19 |
20 | var rebootCmds = map[uintptr]string{
21 | 0x00000000: "LINUX_REBOOT_CMD_CAD_OFF",
22 | 0x89ABCDEF: "LINUX_REBOOT_CMD_CAD_ON",
23 | 0xCDEF0123: "LINUX_REBOOT_CMD_HALT",
24 | 0x45584543: "LINUX_REBOOT_CMD_KEXEC",
25 | 0x4321FEDC: "LINUX_REBOOT_CMD_POWER_OFF",
26 | 0x01234567: "LINUX_REBOOT_CMD_RESTART",
27 | 0xA1B2C3D4: "LINUX_REBOOT_CMD_RESTART2",
28 | 0xD000FCE2: "LINUX_REBOOT_CMD_SW_SUSPEND",
29 | }
30 |
31 | func AnnotateRebootCmd(arg Arg, _ int) {
32 | if cmd, ok := rebootCmds[arg.Raw()]; ok {
33 | arg.SetAnnotation(cmd, true)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tracer/annotation/rlimit.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "golang.org/x/sys/unix"
5 | )
6 |
7 | var rlimitFlags = map[int]string{
8 | unix.RLIMIT_AS: "RLIMIT_AS",
9 | unix.RLIMIT_CORE: "RLIMIT_CORE",
10 | unix.RLIMIT_CPU: "RLIMIT_CPU",
11 | unix.RLIMIT_DATA: "RLIMIT_DATA",
12 | unix.RLIMIT_FSIZE: "RLIMIT_FSIZE",
13 | unix.RLIMIT_LOCKS: "RLIMIT_LOCKS",
14 | unix.RLIMIT_MEMLOCK: "RLIMIT_MEMLOCK",
15 | unix.RLIMIT_MSGQUEUE: "RLIMIT_MSGQUEUE",
16 | unix.RLIMIT_NICE: "RLIMIT_NICE",
17 | unix.RLIMIT_NOFILE: "RLIMIT_NOFILE",
18 | unix.RLIMIT_NPROC: "RLIMIT_NPROC",
19 | unix.RLIMIT_RSS: "RLIMIT_RSS",
20 | unix.RLIMIT_RTPRIO: "RLIMIT_RTPRIO",
21 | unix.RLIMIT_RTTIME: "RLIMIT_RTTIME",
22 | unix.RLIMIT_SIGPENDING: "RLIMIT_SIGPENDING",
23 | unix.RLIMIT_STACK: "RLIMIT_STACK",
24 | }
25 |
26 | func AnnotateRLimitResourceFlags(arg Arg, pid int) {
27 | if str, ok := rlimitFlags[int(arg.Raw())]; ok {
28 | arg.SetAnnotation(str, true)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tracer/annotation/rusage.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var rusageWho = map[int]string{
6 | unix.RUSAGE_CHILDREN: "RUSAGE_CHILDREN",
7 | unix.RUSAGE_SELF: "RUSAGE_SELF",
8 | unix.RUSAGE_THREAD: "RUSAGE_THREAD",
9 | }
10 |
11 | func AnnotateRUsageWho(arg Arg, _ int) {
12 | if name, ok := rusageWho[int(arg.Raw())]; ok {
13 | arg.SetAnnotation(name, true)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tracer/annotation/sched.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | */
6 | import "C"
7 |
8 | var schedPolicies = map[int]string{
9 | C.SCHED_NORMAL: "SCHED_NORMAL",
10 | C.SCHED_FIFO: "SCHED_FIFO",
11 | C.SCHED_RR: "SCHED_RR",
12 | C.SCHED_BATCH: "SCHED_BATCH",
13 | C.SCHED_IDLE: "SCHED_IDLE",
14 | }
15 |
16 | func AnnotateSchedPolicy(arg Arg, pid int) {
17 | if s, ok := schedPolicies[int(arg.Raw())]; ok {
18 | arg.SetAnnotation(s, true)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tracer/annotation/seccomp.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | */
6 | import "C"
7 |
8 | var seccompOps = map[int]string{
9 | C.SECCOMP_SET_MODE_STRICT: "SECCOMP_SET_MODE_STRICT",
10 | C.SECCOMP_SET_MODE_FILTER: "SECCOMP_SET_MODE_FILTER",
11 | C.SECCOMP_GET_ACTION_AVAIL: "SECCOMP_GET_ACTION_AVAIL",
12 | }
13 |
14 | func AnnotateSeccompOp(arg Arg, pid int) {
15 | if s, ok := seccompOps[int(arg.Raw())]; ok {
16 | arg.SetAnnotation(s, true)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/annotation/sem.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | #include
6 | */
7 | import "C"
8 |
9 | import (
10 | "strings"
11 |
12 | "golang.org/x/sys/unix"
13 | )
14 |
15 | var semFlags = map[int]string{
16 | unix.IPC_CREAT: "IPC_CREAT",
17 | unix.IPC_EXCL: "IPC_EXCL",
18 | unix.IPC_NOWAIT: "IPC_NOWAIT",
19 | unix.S_IRUSR: "S_IRUSR",
20 | unix.S_IWUSR: "S_IWUSR",
21 | unix.S_IXUSR: "S_IXUSR",
22 | unix.S_IRGRP: "S_IRGRP",
23 | unix.S_IWGRP: "S_IWGRP",
24 | unix.S_IXGRP: "S_IXGRP",
25 | unix.S_IROTH: "S_IROTH",
26 | unix.S_IWOTH: "S_IWOTH",
27 | unix.S_IXOTH: "S_IXOTH",
28 | }
29 |
30 | func AnnotateSemFlags(arg Arg, pid int) {
31 | var joins []string
32 | for flag, name := range semFlags {
33 | if arg.Raw()&uintptr(flag) != 0 {
34 | joins = append(joins, name)
35 | }
36 | }
37 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
38 | }
39 |
40 | var semCmds = map[int]string{
41 | unix.IPC_STAT: "IPC_STAT",
42 | unix.IPC_SET: "IPC_SET",
43 | unix.IPC_RMID: "IPC_RMID",
44 | C.IPC_INFO: "IPC_INFO",
45 | C.SEM_INFO: "SEM_INFO",
46 | C.SEM_STAT: "SEM_STAT",
47 | C.SEM_STAT_ANY: "SEM_STAT_ANY",
48 | C.GETALL: "GETALL",
49 | C.GETNCNT: "GETNCNT",
50 | C.GETPID: "GETPID",
51 | C.GETVAL: "GETVAL",
52 | C.GETZCNT: "GETZCNT",
53 | C.SETALL: "SETALL",
54 | C.SETVAL: "SETVAL",
55 | }
56 |
57 | func AnnotateSemCmd(arg Arg, _ int) {
58 | if name, ok := semCmds[int(arg.Raw())]; ok {
59 | arg.SetAnnotation(name, true)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tracer/annotation/shm.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | */
6 | import "C"
7 | import (
8 | "strings"
9 |
10 | "golang.org/x/sys/unix"
11 | )
12 |
13 | var shmCommands = map[int]string{
14 | unix.IPC_STAT: "IPC_STAT",
15 | unix.IPC_SET: "IPC_SET",
16 | unix.IPC_RMID: "IPC_RMID",
17 | }
18 |
19 | func AnnotateSHMCTLCommand(arg Arg, _ int) {
20 | str, ok := shmCommands[int(arg.Raw())]
21 | arg.SetAnnotation(str, ok)
22 | }
23 |
24 | var shmAtFlags = map[int]string{
25 | unix.SHM_RDONLY: "SHM_RDONLY",
26 | C.SHM_REMAP: "SHM_REMAP",
27 | }
28 |
29 | func AnnotateSHMAtFlags(arg Arg, _ int) {
30 | var joins []string
31 | for flag, str := range shmAtFlags {
32 | if int(arg.Raw())&flag != 0 {
33 | joins = append(joins, str)
34 | }
35 | }
36 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
37 | }
38 |
39 | var shmGetFlags = map[int]string{
40 | unix.IPC_CREAT: "IPC_CREAT",
41 | unix.IPC_EXCL: "IPC_EXCL",
42 | C.SHM_HUGETLB: "SHM_HUGETLB",
43 | C.SHM_HUGE_1GB: "SHM_HUGE_1GB",
44 | C.SHM_HUGE_2MB: "SHM_HUGE_2MB",
45 | C.SHM_NORESERVE: "SHM_NO_RESERVE",
46 | }
47 |
48 | func AnnotateSHMGetFlags(arg Arg, _ int) {
49 | var joins []string
50 | for flag, name := range shmGetFlags {
51 | if arg.Raw()&uintptr(flag) != 0 {
52 | joins = append(joins, name)
53 | }
54 | }
55 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
56 | }
57 |
--------------------------------------------------------------------------------
/tracer/annotation/shutdown.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var shutdownHow = map[int]string{
6 | unix.SHUT_RD: "SHUT_RD",
7 | unix.SHUT_WR: "SHUT_WR",
8 | unix.SHUT_RDWR: "SHUT_RDWR",
9 | }
10 |
11 | func AnnotateShutdownHow(arg Arg, _ int) {
12 | str, ok := shutdownHow[int(arg.Raw())]
13 | arg.SetAnnotation(str, ok)
14 | }
15 |
--------------------------------------------------------------------------------
/tracer/annotation/signal.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | #include
6 |
7 | */
8 | import "C"
9 | import (
10 | "fmt"
11 | "strings"
12 | "syscall"
13 |
14 | "golang.org/x/sys/unix"
15 | )
16 |
17 | func AnnotateSigProcMaskFlags(arg Arg, _ int) {
18 | var joins []string
19 | if arg.Raw()&C.SIG_BLOCK != 0 {
20 | joins = append(joins, "SIG_BLOCK")
21 | }
22 | if arg.Raw()&C.SIG_UNBLOCK != 0 {
23 | joins = append(joins, "SIG_UNBLOCK")
24 | }
25 | if arg.Raw()&C.SIG_SETMASK != 0 {
26 | joins = append(joins, "SIG_SETMASK")
27 | }
28 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
29 | }
30 |
31 | var signals = map[int]string{
32 | C.SIGHUP: "SIGHUP",
33 | C.SIGINT: "SIGINT",
34 | C.SIGQUIT: "SIGQUIT",
35 | C.SIGILL: "SIGILL",
36 | C.SIGTRAP: "SIGTRAP",
37 | C.SIGABRT: "SIGABRT",
38 | C.SIGBUS: "SIGBUS",
39 | C.SIGFPE: "SIGFPE",
40 | C.SIGKILL: "SIGKILL",
41 | C.SIGUSR1: "SIGUSR1",
42 | C.SIGSEGV: "SIGSEGV",
43 | C.SIGUSR2: "SIGUSR2",
44 | C.SIGPIPE: "SIGPIPE",
45 | C.SIGALRM: "SIGALRM",
46 | C.SIGTERM: "SIGTERM",
47 | C.SIGSTKFLT: "SIGSTKFLT",
48 | C.SIGCHLD: "SIGCHLD",
49 | C.SIGCONT: "SIGCONT",
50 | C.SIGSTOP: "SIGSTOP",
51 | C.SIGTSTP: "SIGTSTP",
52 | C.SIGTTIN: "SIGTTIN",
53 | C.SIGTTOU: "SIGTTOU",
54 | C.SIGURG: "SIGURG",
55 | C.SIGXCPU: "SIGXCPU",
56 | C.SIGXFSZ: "SIGXFSZ",
57 | C.SIGVTALRM: "SIGVTALRM",
58 | C.SIGPROF: "SIGPROF",
59 | C.SIGWINCH: "SIGWINCH",
60 | C.SIGIO: "SIGIO",
61 | C.SIGPWR: "SIGPWR",
62 | C.SIGSYS: "SIGSYS",
63 | }
64 |
65 | func AnnotateSignal(arg Arg, _ int) {
66 | arg.SetAnnotation(SignalToString(int(arg.Raw())), true)
67 | }
68 |
69 | func SignalToString(signal int) string {
70 | var extra string
71 | if signal&0x80 != 0 {
72 | extra = "|0x80"
73 | signal &= ^0x80
74 | }
75 | if name, ok := signals[signal]; ok {
76 | return name + extra
77 | }
78 | return fmt.Sprintf("0x%x%s", signal, extra)
79 | }
80 |
81 | var signalCodes = map[syscall.Signal]map[int]string{
82 | 0: {
83 | C.SI_USER: "SI_USER",
84 | C.SI_KERNEL: "SI_KERNEL",
85 | C.SI_QUEUE: "SI_QUEUE",
86 | C.SI_TIMER: "SI_TIMER",
87 | C.SI_MESGQ: "SI_MESGQ",
88 | C.SI_ASYNCIO: "SI_ASYNCIO",
89 | C.SI_SIGIO: "SI_SIGIO",
90 | C.SI_TKILL: "SI_TKILL",
91 | },
92 | syscall.SIGILL: {
93 | C.ILL_ILLOPC: "ILL_ILLOPC",
94 | C.ILL_ILLOPN: "ILL_ILLOPN",
95 | C.ILL_ILLADR: "ILL_ILLADR",
96 | C.ILL_ILLTRP: "ILL_ILLTRP",
97 | C.ILL_PRVOPC: "ILL_PRVOPC",
98 | C.ILL_PRVREG: "ILL_PRVREG",
99 | C.ILL_COPROC: "ILL_COPROC",
100 | C.ILL_BADSTK: "ILL_BADSTK",
101 | },
102 | syscall.SIGFPE: {
103 | C.FPE_INTDIV: "FPE_INTDIV",
104 | C.FPE_INTOVF: "FPE_INTOVF",
105 | C.FPE_FLTDIV: "FPE_FLTDIV",
106 | C.FPE_FLTOVF: "FPE_FLTOVF",
107 | C.FPE_FLTUND: "FPE_FLTUND",
108 | C.FPE_FLTRES: "FPE_FLTRES",
109 | C.FPE_FLTINV: "FPE_FLTINV",
110 | C.FPE_FLTSUB: "FPE_FLTSUB",
111 | },
112 | syscall.SIGSEGV: {
113 | C.SEGV_MAPERR: "SEGV_MAPERR",
114 | C.SEGV_ACCERR: "SEGV_ACCERR",
115 | C.SEGV_BNDERR: "SEGV_BNDERR",
116 | C.SEGV_PKUERR: "SEGV_PKUERR",
117 | },
118 | syscall.SIGBUS: {
119 | C.BUS_ADRALN: "BUS_ADRALN",
120 | C.BUS_ADRERR: "BUS_ADRERR",
121 | C.BUS_OBJERR: "BUS_OBJERR",
122 | C.BUS_MCEERR_AR: "BUS_MCEERR_AR",
123 | C.BUS_MCEERR_AO: "BUS_MCEERR_AO",
124 | },
125 | syscall.SIGTRAP: {
126 | C.TRAP_BRKPT: "TRAP_BRKPT",
127 | C.TRAP_TRACE: "TRAP_TRACE",
128 | C.TRAP_BRANCH: "TRAP_BRANCH",
129 | C.TRAP_HWBKPT: "TRAP_HWBKPT",
130 | },
131 | syscall.SIGCHLD: {
132 | C.CLD_EXITED: "CLD_EXITED",
133 | C.CLD_KILLED: "CLD_KILLED",
134 | C.CLD_DUMPED: "CLD_DUMPED",
135 | C.CLD_TRAPPED: "CLD_TRAPPED",
136 | C.CLD_STOPPED: "CLD_STOPPED",
137 | C.CLD_CONTINUED: "CLD_CONTINUED",
138 | },
139 | syscall.SIGPOLL: {
140 | C.POLL_IN: "POLL_IN",
141 | C.POLL_OUT: "POLL_OUT",
142 | C.POLL_MSG: "POLL_MSG",
143 | C.POLL_ERR: "POLL_ERR",
144 | C.POLL_PRI: "POLL_PRI",
145 | C.POLL_HUP: "POLL_HUP",
146 | },
147 | syscall.SIGSYS: {
148 | C.SYS_SECCOMP: "SYS_SECCOMP",
149 | },
150 | }
151 |
152 | func SignalCodeToString(signal syscall.Signal, code int32) string {
153 | if codes, ok := signalCodes[signal]; ok {
154 | if str, ok := codes[int(code)]; ok {
155 | return str
156 | }
157 | }
158 | if str, ok := signalCodes[0][int(code)]; ok {
159 | return str
160 | }
161 | return fmt.Sprintf("%d", code)
162 | }
163 |
164 | var signalFDFlags = map[int]string{
165 | unix.SFD_NONBLOCK: "SFD_NONBLOCK",
166 | unix.SFD_CLOEXEC: "SFD_CLOEXEC",
167 | }
168 |
169 | func AnnotateSignalFdFlags(arg Arg, _ int) {
170 | if str, ok := signalFDFlags[int(arg.Raw())]; ok {
171 | arg.SetAnnotation(str, true)
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/tracer/annotation/sigstack.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | */
6 | import "C"
7 |
8 | var sigStackFlags = map[int]string{
9 | C.SS_AUTODISARM: "SS_AUTODISARM",
10 | }
11 |
12 | func AnnotateSigStackFlags(arg Arg, _ int) {
13 | for flag, name := range sigStackFlags {
14 | if int(arg.Raw())&flag != 0 {
15 | arg.SetAnnotation(name, true)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/annotation/splice.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var spliceFlags = map[int]string{
10 | unix.SPLICE_F_MOVE: "SPLICE_F_MOVE",
11 | unix.SPLICE_F_NONBLOCK: "SPLICE_F_NONBLOCK",
12 | unix.SPLICE_F_MORE: "SPLICE_F_MORE",
13 | unix.SPLICE_F_GIFT: "SPLICE_F_GIFT",
14 | }
15 |
16 | func AnnotateSpliceFlags(arg Arg, _ int) {
17 | var joins []string
18 | for flag, name := range spliceFlags {
19 | if (int(arg.Raw())&flag != 0) || (int(arg.Raw()) == flag) {
20 | joins = append(joins, name)
21 | }
22 | }
23 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
24 | }
25 |
--------------------------------------------------------------------------------
/tracer/annotation/statx.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var statxFlags = map[int]string{
10 | unix.STATX_TYPE: "STATX_TYPE",
11 | unix.STATX_MODE: "STATX_MODE",
12 | unix.STATX_NLINK: "STATX_NLINK",
13 | unix.STATX_UID: "STATX_UID",
14 | unix.STATX_GID: "STATX_GID",
15 | unix.STATX_ATIME: "STATX_ATIME",
16 | unix.STATX_MTIME: "STATX_MTIME",
17 | unix.STATX_CTIME: "STATX_CTIME",
18 | unix.STATX_INO: "STATX_INO",
19 | unix.STATX_SIZE: "STATX_SIZE",
20 | unix.STATX_BLOCKS: "STATX_BLOCKS",
21 | unix.STATX_BASIC_STATS: "STATX_BASIC_STATS",
22 | unix.STATX_BTIME: "STATX_BTIME",
23 | unix.STATX_MNT_ID: "STATX_MNT_ID",
24 | unix.STATX_ALL: "STATX_ALL",
25 | }
26 |
27 | func AnnotateStatxMask(arg Arg, _ int) {
28 | var joins []string
29 | for flag, str := range statxFlags {
30 | if int(arg.Raw())&flag != 0 {
31 | joins = append(joins, str)
32 | }
33 | }
34 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
35 | }
36 |
--------------------------------------------------------------------------------
/tracer/annotation/syncfilerange.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var syncFileRangeFlags = map[int]string{
10 | unix.SYNC_FILE_RANGE_WAIT_BEFORE: "SYNC_FILE_RANGE_WAIT_BEFORE",
11 | unix.SYNC_FILE_RANGE_WRITE: "SYNC_FILE_RANGE_WRITE",
12 | unix.SYNC_FILE_RANGE_WAIT_AFTER: "SYNC_FILE_RANGE_WAIT_AFTER",
13 | }
14 |
15 | func AnnotateSyncFileRangeFlags(arg Arg, _ int) {
16 | var joins []string
17 | for flag, name := range syncFileRangeFlags {
18 | if (int(arg.Raw())&flag != 0) || (int(arg.Raw()) == flag) {
19 | joins = append(joins, name)
20 | }
21 | }
22 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
23 | }
24 |
--------------------------------------------------------------------------------
/tracer/annotation/syslog.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var syslogTypes = map[int]string{
6 | unix.SYSLOG_ACTION_READ: "SYSLOG_ACTION_READ",
7 | unix.SYSLOG_ACTION_READ_ALL: "SYSLOG_ACTION_READ_ALL",
8 | unix.SYSLOG_ACTION_READ_CLEAR: "SYSLOG_ACTION_READ_CLEAR",
9 | unix.SYSLOG_ACTION_CLEAR: "SYSLOG_ACTION_CLEAR",
10 | unix.SYSLOG_ACTION_CONSOLE_OFF: "SYSLOG_ACTION_CONSOLE_OFF",
11 | unix.SYSLOG_ACTION_CONSOLE_ON: "SYSLOG_ACTION_CONSOLE_ON",
12 | unix.SYSLOG_ACTION_CONSOLE_LEVEL: "SYSLOG_ACTION_CONSOLE_LEVEL",
13 | unix.SYSLOG_ACTION_SIZE_UNREAD: "SYSLOG_ACTION_SIZE_UNREAD",
14 | unix.SYSLOG_ACTION_SIZE_BUFFER: "SYSLOG_ACTION_SIZE_BUFFER",
15 | }
16 |
17 | func AnnotateSyslogType(arg Arg, _ int) {
18 | if name, ok := syslogTypes[int(arg.Raw())]; ok {
19 | arg.SetAnnotation(name, true)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tracer/annotation/time.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | var clockStates = map[int]string{
6 | unix.TIME_OK: "TIME_OK",
7 | unix.TIME_INS: "TIME_INS",
8 | unix.TIME_DEL: "TIME_DEL",
9 | unix.TIME_OOP: "TIME_OOP",
10 | unix.TIME_WAIT: "TIME_WAIT",
11 | unix.TIME_ERROR: "TIME_ERROR",
12 | }
13 |
14 | func AnnotateClockState(arg Arg, _ int) {
15 | if s, ok := clockStates[int(arg.Raw())]; ok {
16 | arg.SetAnnotation(s, true)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/annotation/timer.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func AnnotateWhichTimer(arg Arg, _ int) {
10 | switch arg.Raw() {
11 | case unix.ITIMER_REAL:
12 | arg.SetAnnotation("ITIMER_REAL", true)
13 | case unix.ITIMER_VIRTUAL:
14 | arg.SetAnnotation("ITIMER_VIRTUAL", true)
15 | case unix.ITIMER_PROF:
16 | arg.SetAnnotation("ITIMER_PROF", true)
17 | }
18 | }
19 |
20 | var timerFlags = map[int]string{
21 | unix.TIMER_ABSTIME: "TIMER_ABSTIME",
22 | }
23 |
24 | func AnnotateTimerFlags(arg Arg, _ int) {
25 | if str, ok := timerFlags[int(arg.Raw())]; ok {
26 | arg.SetAnnotation(str, true)
27 | }
28 | }
29 |
30 | var timerFdFlags = map[int]string{
31 | unix.O_CLOEXEC: "TFD_CLOEXEC",
32 | unix.O_NONBLOCK: "TFD_NONBLOCK",
33 | unix.TFD_TIMER_ABSTIME: "TFD_TIMER_ABSTIME",
34 | unix.TFD_TIMER_CANCEL_ON_SET: "TFD_TIMER_CANCEL_ON_SET",
35 | }
36 |
37 | func AnnotateTimerFdFlags(arg Arg, _ int) {
38 | var joins []string
39 | for flag, str := range timerFdFlags {
40 | if int(arg.Raw())&flag != 0 {
41 | joins = append(joins, str)
42 | }
43 | }
44 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
45 | }
46 |
--------------------------------------------------------------------------------
/tracer/annotation/wait.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | /*
4 | #include
5 | #include
6 | #include
7 |
8 | int fWIFEXITED(int status) {
9 | return WIFEXITED(status);
10 | }
11 | int fWEXITSTATUS(int status) {
12 | return WEXITSTATUS(status);
13 | }
14 | int fWIFSIGNALED(int status) {
15 | return WIFSIGNALED(status);
16 | }
17 | int fWTERMSIG(int status) {
18 | return WTERMSIG(status);
19 | }
20 | int fWIFSTOPPED(int status) {
21 | return WIFSTOPPED(status);
22 | }
23 | int fWSTOPSIG(int status) {
24 | return WSTOPSIG(status);
25 | }
26 | */
27 | import "C"
28 |
29 | import (
30 | "fmt"
31 | "strings"
32 | "syscall"
33 |
34 | "golang.org/x/sys/unix"
35 | )
36 |
37 | var waitOptions = map[int]string{
38 | unix.WNOHANG: "WNOHANG",
39 | unix.WUNTRACED: "WUNTRACED",
40 | unix.WCONTINUED: "WCONTINUED",
41 | unix.WEXITED: "WEXITED",
42 | unix.WNOWAIT: "WNOWAIT",
43 | unix.WALL: "__WALL",
44 | unix.WNOTHREAD: "__WNOTHREAD",
45 | unix.WCLONE: "__WCLONE",
46 | }
47 |
48 | func AnnotateWaitOptions(arg Arg, _ int) {
49 | var joins []string
50 | for flag, name := range waitOptions {
51 | if arg.Raw()&uintptr(flag) != 0 {
52 | joins = append(joins, name)
53 | }
54 | }
55 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
56 | }
57 |
58 | func AnnotateWaitStatus(arg Arg, _ int) {
59 | status := syscall.WaitStatus(arg.Raw())
60 |
61 | var joins []string
62 |
63 | if C.fWIFEXITED(C.int(status)) != 0 {
64 | joins = append(joins, "WIFEXITED(s)")
65 | result := C.fWEXITSTATUS(C.int(status))
66 | joins = append(joins, fmt.Sprintf("WEXITSTATUS(s) == %d", result))
67 | }
68 |
69 | if C.fWIFSIGNALED(C.int(status)) != 0 {
70 | joins = append(joins, "WIFSIGNALED(s)")
71 | result := int(C.fWTERMSIG(C.int(status)))
72 | joins = append(joins, fmt.Sprintf("WTERMSIG(s) == %s", SignalToString(result)))
73 | }
74 |
75 | if C.fWIFSTOPPED(C.int(status)) != 0 {
76 | joins = append(joins, "WIFSTOPPED(s)")
77 | result := int(C.fWSTOPSIG(C.int(status)))
78 | joins = append(joins, fmt.Sprintf("WSTOPSIG(s) == %s", SignalToString(result)))
79 | }
80 |
81 | arg.SetAnnotation(strings.Join(joins, " && "), len(joins) > 0)
82 | }
83 |
84 | var waitIDs = map[int]string{
85 | unix.P_PID: "P_PID",
86 | unix.P_PGID: "P_PGID",
87 | unix.P_ALL: "P_ALL",
88 | }
89 |
90 | func AnnotateIDType(arg Arg, _ int) {
91 | if str, ok := waitIDs[int(arg.Raw())]; ok {
92 | arg.SetAnnotation(str, true)
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/tracer/annotation/whence.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import "golang.org/x/sys/unix"
4 |
5 | func AnnotateWhence(arg Arg, _ int) {
6 | switch int(arg.Raw()) {
7 | case unix.SEEK_SET:
8 | arg.SetAnnotation("SEEK_SET", true)
9 | case unix.SEEK_CUR:
10 | arg.SetAnnotation("SEEK_CUR", true)
11 | case unix.SEEK_END:
12 | arg.SetAnnotation("SEEK_END", true)
13 | case unix.SEEK_DATA:
14 | arg.SetAnnotation("SEEK_DATA", true)
15 | case unix.SEEK_HOLE:
16 | arg.SetAnnotation("SEEK_HOLE", true)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/annotation/x.go:
--------------------------------------------------------------------------------
1 | package annotation
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | var xFlags = map[int]string{
10 | unix.XATTR_CREATE: "XATTR_CREATE",
11 | unix.XATTR_REPLACE: "XATTR_REPLACE",
12 | }
13 |
14 | func AnnotateXFlags(arg Arg, _ int) {
15 | var joins []string
16 | for flag, name := range xFlags {
17 | if int(arg.Raw())&flag != 0 {
18 | joins = append(joins, name)
19 | }
20 | }
21 | arg.SetAnnotation(strings.Join(joins, "|"), len(joins) > 0)
22 | }
23 |
--------------------------------------------------------------------------------
/tracer/args.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "github.com/liamg/grace/tracer/annotation"
7 | )
8 |
9 | type ArgMetadata struct {
10 | Name string
11 | Type ArgType
12 | Annotator func(arg annotation.Arg, pid int)
13 | LenSource LenSource
14 | Optional bool
15 | Destination bool
16 | FixedCount int
17 | }
18 |
19 | type LenSource uint8
20 |
21 | const (
22 | LenSourceNone LenSource = iota
23 | LenSourcePrev
24 | LenSourceNext
25 | LenSourceNextPointer
26 | LenSourceReturnValue
27 | LenSourceFixed
28 | )
29 |
30 | type ReturnMetadata ArgMetadata
31 |
32 | type Arg struct {
33 | name string
34 | t ArgType
35 | raw uintptr
36 | data []byte
37 | annotation string
38 | replace bool // replace value output with annotation
39 | bitSize int
40 | obj *Object
41 | array []Arg
42 | known bool
43 | }
44 |
45 | type Object struct {
46 | Name string
47 | Properties []Arg
48 | }
49 |
50 | func (s Arg) Known() bool {
51 | return s.known
52 | }
53 |
54 | func (s Arg) Name() string {
55 | return s.name
56 | }
57 |
58 | func (s Arg) Type() ArgType {
59 | return s.t
60 | }
61 |
62 | func (s Arg) Raw() uintptr {
63 | return s.raw
64 | }
65 |
66 | func (s Arg) Int() int {
67 | switch s.t {
68 | case ArgTypeLong:
69 | switch s.bitSize {
70 | case 32:
71 | return int(int32(s.raw))
72 | case 64:
73 | return int(int64(s.raw))
74 | }
75 | case ArgTypeInt, ArgTypeUnknown:
76 | // an int is 32-bit on both 32-bit and 64-bit linux
77 | return int(int32(s.raw))
78 | }
79 | return int(s.raw)
80 | }
81 |
82 | func (s Arg) Data() []byte {
83 | return s.data
84 | }
85 |
86 | func (s Arg) Annotation() string {
87 | return s.annotation
88 | }
89 |
90 | func (s Arg) ReplaceValueWithAnnotation() bool {
91 | return s.replace
92 | }
93 |
94 | func (s Arg) Object() *Object {
95 | return s.obj
96 | }
97 |
98 | func (s Arg) Array() []Arg {
99 | return s.array
100 | }
101 |
102 | func (s *Arg) SetAnnotation(annotation string, replace bool) {
103 | s.annotation = annotation
104 | s.replace = replace
105 | }
106 |
107 | func processArgument(raw uintptr, next, prev uintptr, ret uintptr, metadata ArgMetadata, pid int, exit bool) (*Arg, error) {
108 | arg := &Arg{
109 | name: metadata.Name,
110 | t: metadata.Type,
111 | raw: raw,
112 | bitSize: bitSize,
113 | known: true,
114 | }
115 |
116 | // if we're on the syscall enter and the argument is a pointer for a destination, we don't know the value yet
117 | if !exit && metadata.Destination {
118 | arg.known = false
119 | return arg, nil
120 | }
121 |
122 | // resolve next to int from next pointer
123 | if metadata.LenSource == LenSourceNextPointer && (exit || !metadata.Destination) && next > 0 {
124 | var realNext uint32
125 | buf, err := readSize(pid, next, unsafe.Sizeof(realNext))
126 | if err != nil {
127 | return nil, err
128 | }
129 | next = uintptr(decodeInt(buf))
130 | }
131 |
132 | // process the argument data into something meaningful
133 | if err := handleType(arg, metadata, raw, next, prev, ret, pid); err != nil {
134 | return nil, err
135 | }
136 |
137 | // always apply annotations
138 | if metadata.Annotator != nil {
139 | metadata.Annotator(arg, pid)
140 | }
141 |
142 | return arg, nil
143 | }
144 |
--------------------------------------------------------------------------------
/tracer/decode.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "reflect"
7 | )
8 |
9 | func decodeStruct(memory []byte, target interface{}) error {
10 |
11 | sType := reflect.TypeOf(target)
12 | if sType.Kind() != reflect.Ptr {
13 | return errors.New("target must be a pointer")
14 | }
15 |
16 | var index uintptr
17 |
18 | sPtrValue := reflect.ValueOf(target)
19 | sValue := sPtrValue.Elem()
20 |
21 | switch sValue.Kind() {
22 | case reflect.Struct:
23 | for i := 0; i < sValue.Type().NumField(); i++ {
24 | size := sValue.Type().Field(i).Type.Size()
25 | if sValue.Type().Field(i).Name == "_" {
26 | index += size
27 | continue
28 | }
29 | raw := memory[index : index+size]
30 | if err := decodeAnonymous(sValue.Field(i), raw); err != nil {
31 | return err
32 | }
33 | index += size
34 | }
35 | default:
36 | return errors.New("target must be a pointer to a struct")
37 | }
38 |
39 | return nil
40 | }
41 |
42 | func decodeAnonymous(target reflect.Value, raw []byte) error {
43 |
44 | if target.Kind() == reflect.Ptr {
45 | target.Set(reflect.New(target.Type().Elem()))
46 | target = target.Elem()
47 | }
48 |
49 | if !target.CanSet() {
50 | return fmt.Errorf("cannot set %s", target.Type())
51 | }
52 |
53 | switch target.Kind() {
54 | case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint, reflect.Uintptr:
55 | target.SetUint(decodeUint(raw))
56 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
57 | target.SetInt(decodeInt(raw))
58 | case reflect.String:
59 | target.SetString(string(raw))
60 | case reflect.Struct:
61 | if err := decodeStruct(raw, target.Addr().Interface()); err != nil {
62 | return err
63 | }
64 | case reflect.Array, reflect.Slice:
65 | var index uintptr
66 | for i := 0; i < target.Len(); i++ {
67 | memory := raw[index : index+target.Type().Elem().Size()]
68 | if err := decodeAnonymous(target.Index(i), memory); err != nil {
69 | return err
70 | }
71 | index += target.Type().Elem().Size()
72 | }
73 | default:
74 | return fmt.Errorf("unsupported kind for field '%s': %s", target.String(), target.Kind().String())
75 | }
76 | return nil
77 | }
78 |
79 | func decodeUint(raw []byte) uint64 {
80 | var output uint64
81 | for i := 0; i < len(raw); i++ {
82 | output |= uint64(raw[i]) << uint(i*8)
83 | }
84 | return output
85 | }
86 | func decodeInt(raw []byte) int64 {
87 | var output int64
88 | for i := 0; i < len(raw); i++ {
89 | output |= int64(raw[i]) << uint(i*8)
90 | }
91 | return output
92 | }
93 |
--------------------------------------------------------------------------------
/tracer/decode_uint_test.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import "testing"
4 |
5 | func Test_DecodeUint(t *testing.T) {
6 |
7 | tests := []struct {
8 | name string
9 | data []byte
10 | want uint64
11 | }{
12 | {
13 | name: "zero length",
14 | data: []byte{},
15 | want: 0,
16 | },
17 | {
18 | name: "filled byte",
19 | data: []byte{
20 | 0xff,
21 | },
22 | want: 0xff,
23 | },
24 | {
25 | name: "byte order",
26 | data: []byte{
27 | 0x11,
28 | 0xff,
29 | 0x00,
30 | },
31 | want: 0xff11,
32 | },
33 | {
34 | name: "byte max value",
35 | data: []byte{
36 | 0xff,
37 | 0xff,
38 | 0xff,
39 | 0xff,
40 | 0xff,
41 | 0xff,
42 | 0xff,
43 | 0xff,
44 | },
45 | want: 0xffffffffffffffff,
46 | },
47 | {
48 | name: "overflow ignored",
49 | data: []byte{
50 | 0xff,
51 | 0xff,
52 | 0xff,
53 | 0xff,
54 | 0xff,
55 | 0xff,
56 | 0xff,
57 | 0xff,
58 | 0x1,
59 | },
60 | want: 0xffffffffffffffff,
61 | },
62 | }
63 |
64 | for _, test := range tests {
65 | t.Run(test.name, func(t *testing.T) {
66 | if got := decodeUint(test.data); got != test.want {
67 | t.Errorf("decodeUint() = %v, want %v", got, test.want)
68 | }
69 | })
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/tracer/netw/netw.go:
--------------------------------------------------------------------------------
1 | package netw
2 |
3 | func ListConnections() ([]Connection, error) {
4 | tcpConnections, err := ListTCPConnections()
5 | if err != nil {
6 | return nil, err
7 | }
8 | udpConnections, err := ListUDPConnections()
9 | if err != nil {
10 | return nil, err
11 | }
12 | icmpConnections, err := ListICMPConnections()
13 | if err != nil {
14 | return nil, err
15 | }
16 | return append(append(tcpConnections, udpConnections...), icmpConnections...), nil
17 | }
18 |
--------------------------------------------------------------------------------
/tracer/netw/proc.go:
--------------------------------------------------------------------------------
1 | package netw
2 |
3 | import (
4 | "fmt"
5 | "net"
6 | "os"
7 | "strconv"
8 | "strings"
9 | )
10 |
11 | type Connection struct {
12 | Protocol string
13 | LocalAddress net.IP
14 | LocalPort int
15 | RemoteAddress net.IP
16 | RemotePort int
17 | INode int
18 | State int // TCP_ESTABLISHED etc. see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp_states.h
19 | }
20 |
21 | const netPath = "/proc/net/"
22 |
23 | func ListTCPConnections() ([]Connection, error) {
24 | return parseBaseProtocol("tcp")
25 | }
26 |
27 | func ListUDPConnections() ([]Connection, error) {
28 | return parseBaseProtocol("udp")
29 | }
30 |
31 | func ListICMPConnections() ([]Connection, error) {
32 | return parseBaseProtocol("icmp")
33 | }
34 |
35 | func parseBaseProtocol(protocol string) ([]Connection, error) {
36 | v4, err := parseFile(protocol)
37 | if err != nil {
38 | return nil, err
39 | }
40 |
41 | v6, err := parseFile(protocol + "6")
42 | if err != nil {
43 | return nil, err
44 | }
45 |
46 | return append(v4, v6...), nil
47 | }
48 |
49 | func parseFile(protocol string) ([]Connection, error) {
50 |
51 | file := netPath + protocol
52 | data, err := os.ReadFile(file)
53 | if err != nil {
54 | return nil, err
55 | }
56 | var connections []Connection
57 | lines := strings.Split(string(data), "\n")
58 | for _, line := range lines {
59 | line = strings.TrimSpace(line)
60 | if line == "" {
61 | continue
62 | }
63 | if strings.HasPrefix(line, "sl") { // skip headings
64 | continue
65 | }
66 | connection, err := parseLine(line)
67 | if err != nil {
68 | return nil, err
69 | }
70 | connection.Protocol = protocol
71 | connections = append(connections, *connection)
72 | }
73 | return connections, nil
74 | }
75 |
76 | func parseLine(line string) (*Connection, error) {
77 |
78 | line = strings.TrimSpace(line)
79 | fields := strings.Fields(line)
80 |
81 | if len(fields) < 10 {
82 | return nil, fmt.Errorf("invalid tcp connection: %s", line)
83 | }
84 |
85 | inode, err := strconv.Atoi(fields[9])
86 | if err != nil {
87 | return nil, fmt.Errorf("invalid inode '%s': %w", fields[9], err)
88 | }
89 |
90 | localip, localport, err := parseIPAndPortFromHex(fields[1])
91 | if err != nil {
92 | return nil, fmt.Errorf("invalid local ip '%s': %w", fields[1], err)
93 | }
94 |
95 | remoteip, remoteport, err := parseIPAndPortFromHex(fields[2])
96 | if err != nil {
97 | return nil, fmt.Errorf("invalid remote ip '%s': %w", fields[2], err)
98 | }
99 |
100 | return &Connection{
101 | INode: inode,
102 | LocalAddress: localip,
103 | LocalPort: localport,
104 | RemoteAddress: remoteip,
105 | RemotePort: remoteport,
106 | State: int(hexToByte(fields[3])),
107 | }, nil
108 | }
109 |
110 | func parseIPAndPortFromHex(hex string) (net.IP, int, error) {
111 |
112 | rawip, rawport, found := strings.Cut(hex, ":")
113 | if !found {
114 | return nil, 0, fmt.Errorf("invalid hex '%s'", hex)
115 | }
116 |
117 | var ip net.IP
118 |
119 | switch len(rawip) {
120 | case 8:
121 | ip = net.IPv4(
122 | hexToByte(rawip[6:8]),
123 | hexToByte(rawip[4:6]),
124 | hexToByte(rawip[2:4]),
125 | hexToByte(rawip[0:2]),
126 | )
127 | case 32:
128 | ip = []byte{
129 | hexToByte(rawip[30:32]),
130 | hexToByte(rawip[28:30]),
131 | hexToByte(rawip[26:28]),
132 | hexToByte(rawip[24:26]),
133 | hexToByte(rawip[22:24]),
134 | hexToByte(rawip[20:22]),
135 | hexToByte(rawip[18:20]),
136 | hexToByte(rawip[16:18]),
137 | hexToByte(rawip[14:16]),
138 | hexToByte(rawip[12:14]),
139 | hexToByte(rawip[10:12]),
140 | hexToByte(rawip[8:10]),
141 | hexToByte(rawip[6:8]),
142 | hexToByte(rawip[4:6]),
143 | hexToByte(rawip[2:4]),
144 | hexToByte(rawip[0:2]),
145 | }
146 | default:
147 | return nil, 0, fmt.Errorf("invalid ipv4 hex '%s'", hex)
148 | }
149 |
150 | port, err := strconv.ParseInt(rawport, 16, 32)
151 | if err != nil {
152 | return nil, 0, fmt.Errorf("invalid port '%s': %w", rawport, err)
153 | }
154 |
155 | return ip, int(port), nil
156 | }
157 |
158 | func hexToByte(hex string) byte {
159 | b, err := strconv.ParseUint(hex, 16, 8)
160 | if err != nil {
161 | return 0
162 | }
163 | return byte(b)
164 | }
165 |
--------------------------------------------------------------------------------
/tracer/signal.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "syscall"
6 | "unsafe"
7 |
8 | "golang.org/x/sys/unix"
9 | )
10 |
11 | type SigInfo struct {
12 | Signo int32
13 | Errno int32
14 | Code int32
15 | TrapNo int32
16 | Pid int32
17 | Uid int32
18 | }
19 |
20 | func getSignalInfo(pid int) (*SigInfo, error) {
21 | var info SigInfo
22 | _, _, e1 := syscall.Syscall6(syscall.SYS_PTRACE, uintptr(unix.PTRACE_GETSIGINFO), uintptr(pid), 0, uintptr(unsafe.Pointer(&info)), 0, 0)
23 | if e1 != 0 {
24 | return nil, fmt.Errorf("ptrace get signal info failed: %v", e1)
25 | }
26 | return &info, nil
27 | }
28 |
--------------------------------------------------------------------------------
/tracer/sys.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 | )
8 |
9 | type Syscall struct {
10 | pid int
11 | number int
12 | rawArgs [6]uintptr
13 | args []Arg
14 | rawRet uintptr
15 | ret Arg
16 | unknown bool
17 | paths []string
18 | complete bool
19 | }
20 |
21 | type SyscallMetadata struct {
22 | Name string
23 | Args []ArgMetadata
24 | ReturnValue ReturnMetadata
25 | Modifier func(call *Syscall)
26 | }
27 |
28 | func (s *Syscall) Number() int {
29 | return s.number
30 | }
31 |
32 | func (s *Syscall) Paths() []string {
33 | return s.paths
34 | }
35 |
36 | func (s *Syscall) Name() string {
37 | meta, ok := sysMap[s.number]
38 | if !ok {
39 | return fmt.Sprintf("unknown_syscall_%d", s.number)
40 | }
41 | return meta.Name
42 | }
43 |
44 | func (s *Syscall) Args() []Arg {
45 | return s.args
46 | }
47 |
48 | func (s *Syscall) Return() Arg {
49 | return s.ret
50 | }
51 |
52 | func (s *Syscall) Unknown() bool {
53 | return s.unknown
54 | }
55 |
56 | func (s *Syscall) Complete() bool {
57 | return s.complete
58 | }
59 |
60 | func (s *Syscall) populate(exit bool) error {
61 | meta, ok := sysMap[s.number]
62 | if !ok {
63 | s.unknown = true
64 | }
65 |
66 | if exit {
67 | ret, err := processArgument(s.rawRet, 0, 0, 0, ArgMetadata(meta.ReturnValue), s.pid, exit)
68 | if err != nil {
69 | return fmt.Errorf("failed to set return value of syscall %s (%d): %w", meta.Name, s.number, err)
70 | }
71 | s.ret = *ret
72 | }
73 | for i, argMeta := range meta.Args {
74 | if exit && !argMeta.Destination && i < len(s.args) {
75 | continue
76 | }
77 |
78 | var next uintptr
79 | if i < len(meta.Args)-1 {
80 | next = s.rawArgs[i+1]
81 | }
82 | var prev uintptr
83 | if i > 0 {
84 | prev = s.rawArgs[i-1]
85 | }
86 |
87 | arg, err := processArgument(s.rawArgs[i], next, prev, s.rawRet, argMeta, s.pid, exit)
88 | if err != nil {
89 | return fmt.Errorf("failed to set argument %d (%s) of syscall %s (%d): %w", i, argMeta.Name, meta.Name, s.number, err)
90 | }
91 | if !arg.known {
92 | break
93 | }
94 | if i >= len(s.args) {
95 | s.args = append(s.args, *arg)
96 | } else {
97 | s.args[i] = *arg
98 | }
99 |
100 | // best attempt to set path information
101 | if argMeta.Type == argTypeString && (strings.Contains(argMeta.Name, "path") || strings.Contains(argMeta.Name, "file")) {
102 | s.paths = append(s.paths, string(arg.Data()))
103 | } else if argMeta.Type == ArgTypeInt && strings.Contains(argMeta.Name, "fd") {
104 | if path, err := os.Readlink(fmt.Sprintf("/proc/%d/fd/%d", s.pid, arg.Raw())); err == nil {
105 | s.paths = append(s.paths, path)
106 | }
107 | }
108 | }
109 | s.complete = len(s.args) == len(meta.Args)
110 | for _, arg := range s.args {
111 | if !arg.known {
112 | s.complete = false
113 | break
114 | }
115 | }
116 |
117 | // strip off trailing optional args if they have no value
118 | var lastIndex int
119 | for i, arg := range s.args {
120 | meta := meta.Args[i]
121 | if !meta.Optional || arg.Raw() > 0 {
122 | lastIndex = i
123 | }
124 | }
125 | if lastIndex < len(s.args)-1 {
126 | s.args = s.args[:lastIndex+1]
127 | }
128 |
129 | if exit && meta.Modifier != nil {
130 | meta.Modifier(s)
131 | }
132 |
133 | return nil
134 | }
135 |
--------------------------------------------------------------------------------
/tracer/sys_arm64.go:
--------------------------------------------------------------------------------
1 | //go:build arm64
2 |
3 | package tracer
4 |
5 | import (
6 | "syscall"
7 | )
8 |
9 | const bitSize = 64
10 |
11 | // useful info: https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
12 |
13 | func parseSyscall(regs *syscall.PtraceRegs) *Syscall {
14 | return &Syscall{
15 | number: int(regs.Regs[8]),
16 | rawArgs: [6]uintptr{
17 | uintptr(regs.Regs[0]),
18 | uintptr(regs.Regs[1]),
19 | uintptr(regs.Regs[2]),
20 | uintptr(regs.Regs[3]),
21 | uintptr(regs.Regs[4]),
22 | uintptr(regs.Regs[5]),
23 | },
24 | rawRet: uintptr(regs.Regs[0]),
25 | }
26 | }
27 |
28 | // TODO: add syscall table for arm64
29 | var sysMap = map[int]SyscallMetadata{}
30 |
--------------------------------------------------------------------------------
/tracer/sys_test.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_SyscallSupport(t *testing.T) {
12 |
13 | for number, meta := range sysMap {
14 | t.Run(fmt.Sprintf("syscall %d: %s", number, meta.Name), func(t *testing.T) {
15 | checkSyscall(t, number, meta)
16 | })
17 | }
18 | }
19 |
20 | func checkSyscall(t *testing.T, number int, meta SyscallMetadata) {
21 | require.NotNil(t, meta)
22 | assert.NotEmpty(t, meta.Name)
23 | assert.NotEqualf(t, ArgTypeUnknown, meta.ReturnValue.Type, "syscall %d (%s) has unspecified return value type", number, meta.Name)
24 | for i, arg := range meta.Args {
25 | assert.NotEqualf(t, ArgTypeUnknown, arg.Type, "syscall %d (%s) has unspecified argument type", number, meta.Name)
26 | switch arg.Type {
27 | case ArgTypeData:
28 | assert.NotEqual(t, LenSourceNone, arg.LenSource)
29 | }
30 | switch arg.LenSource {
31 | case LenSourceFixed:
32 | assert.NotZero(t, arg.FixedCount)
33 | case LenSourceNextPointer, LenSourceNext:
34 | assert.Less(t, i, len(meta.Args)-1)
35 | case LenSourcePrev:
36 | assert.Greater(t, i, 0)
37 | case LenSourceReturnValue:
38 | assert.NotEqual(t, ArgTypeErrorCode, meta.ReturnValue.Type)
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tracer/type.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | type ArgType int
9 |
10 | const (
11 | // public
12 | ArgTypeUnknown ArgType = iota
13 | ArgTypeData
14 | ArgTypeInt
15 | ArgTypeLong
16 | ArgTypeAddress
17 | ArgTypeUnsignedInt
18 | ArgTypeUnsignedLong
19 | ArgTypeObject
20 | ArgTypeErrorCode
21 | ArgTypeArray
22 |
23 | argStartInternal // TODO: use this to test all type converters are registered
24 |
25 | // internal
26 | argTypeString
27 | argTypeSockaddr
28 | argTypeIntOrErrorCode
29 | argTypeStat
30 | argTypePollFdArray
31 | argTypeSigAction
32 | argTypeIovecArray
33 | argTypeIntArray
34 | argTypeStringArray
35 | argTypeFdSet
36 | argTypeTimeval
37 | argTypeTimevalArray
38 | argTypeTimezone
39 | argTypeSHMIDDS
40 | argTypeTimespec
41 | argTypeTimespecArray
42 | argTypeItimerval
43 | argTypeMsghdr
44 | argTypeUnsignedIntPtr
45 | argTypeUnsignedInt64Ptr
46 | argTypeSockoptval
47 | argTypeWaitStatus
48 | argTypeRUsage
49 | argTypeRLimit
50 | argTypeUname
51 | argTypeSembuf
52 | argTypeSysinfo
53 | argTypeTms
54 | argTypeCapUserHeader
55 | argTypeCapUserData
56 | argTypeSigInfo
57 | argTypeStack
58 | argTypeUtimbuf
59 | argTypeUstat
60 | argTypeStatfs
61 | argTypeSchedParam
62 | argTypeUserDesc
63 | argTypeTimex
64 | argTypeIoEvent
65 | argTypeIoEvents
66 | argTypeIoCB
67 | argTypeItimerspec
68 | argTypeEpollEvent
69 | argTypeMqAttr
70 | argTypeMMsgHdrArray
71 | argTypeSchedAttr
72 | argTypeStatX
73 | argTypeIoUringParams
74 | argTypeCloneArgs
75 | argTypeOpenHow
76 | argTypeMountAttr
77 | argTypeLandlockRulesetAttr
78 |
79 | argEndInternal
80 | )
81 |
82 | type typeHandler func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error
83 |
84 | var typesRegistry = map[ArgType]typeHandler{}
85 | var typesRegistryMutex = sync.RWMutex{}
86 |
87 | func registerTypeHandler(t ArgType, h typeHandler) {
88 | typesRegistryMutex.Lock()
89 | defer typesRegistryMutex.Unlock()
90 | if _, ok := typesRegistry[t]; ok {
91 | panic(fmt.Sprintf("type handler for %d already registered", t))
92 | }
93 | typesRegistry[t] = h
94 | }
95 |
96 | func getHandler(t ArgType) typeHandler {
97 | typesRegistryMutex.RLock()
98 | defer typesRegistryMutex.RUnlock()
99 | return typesRegistry[t]
100 | }
101 |
102 | func handleType(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) (err error) {
103 | typesRegistryMutex.RLock()
104 | defer typesRegistryMutex.RUnlock()
105 | defer func() {
106 | if r := recover(); r != nil {
107 | err = fmt.Errorf("error handling type %s with value 0x%x: %v", metadata.Name, raw, r)
108 | }
109 | }()
110 | if h, ok := typesRegistry[metadata.Type]; ok {
111 | return h(arg, metadata, raw, next, prev, ret, pid)
112 | }
113 | return nil
114 | }
115 |
--------------------------------------------------------------------------------
/tracer/type_test.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestTypeConversions(t *testing.T) {
9 | for i := argStartInternal + 1; i < argEndInternal; i++ {
10 | t.Run(fmt.Sprintf("ArgType %d", i), func(t *testing.T) {
11 | if getHandler(i) == nil {
12 | t.Errorf("No handler for type %d", i)
13 | }
14 | })
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tracer/types_cap.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type capHeader struct {
8 | Version uint32
9 | Pid int32
10 | }
11 |
12 | type capData struct {
13 | Effective uint32
14 | Permitted uint32
15 | Inheritable uint32
16 | }
17 |
18 | func init() {
19 | registerTypeHandler(argTypeCapUserHeader, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
20 | if raw > 0 {
21 | mem, err := readSize(pid, raw, unsafe.Sizeof(capHeader{}))
22 | if err != nil {
23 | return err
24 | }
25 | var cap capHeader
26 | if err := decodeStruct(mem, &cap); err != nil {
27 | return err
28 | }
29 | arg.obj = convertCapHeader(&cap)
30 | arg.t = ArgTypeObject
31 | } else {
32 | arg.t = ArgTypeAddress
33 | arg.annotation = "NULL"
34 | arg.replace = true
35 | }
36 | return nil
37 | })
38 | registerTypeHandler(argTypeCapUserData, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
39 | if raw > 0 {
40 | mem, err := readSize(pid, raw, unsafe.Sizeof(capData{}))
41 | if err != nil {
42 | return err
43 | }
44 | var cap capData
45 | if err := decodeStruct(mem, &cap); err != nil {
46 | return err
47 | }
48 | arg.obj = convertCapData(&cap)
49 | arg.t = ArgTypeObject
50 | } else {
51 | arg.t = ArgTypeAddress
52 | arg.annotation = "NULL"
53 | arg.replace = true
54 | }
55 | return nil
56 | })
57 | }
58 |
59 | func convertCapHeader(cap *capHeader) *Object {
60 | return &Object{
61 | Name: "hdr",
62 | Properties: []Arg{
63 | {
64 | name: "version",
65 | t: ArgTypeInt,
66 | raw: uintptr(cap.Version),
67 | },
68 | {
69 | name: "pid",
70 | t: ArgTypeInt,
71 | raw: uintptr(cap.Pid),
72 | },
73 | },
74 | }
75 | }
76 |
77 | func convertCapData(cap *capData) *Object {
78 | return &Object{
79 | Name: "data",
80 | Properties: []Arg{
81 | {
82 | name: "effective",
83 | t: ArgTypeInt,
84 | raw: uintptr(cap.Effective),
85 | },
86 | {
87 | name: "permitted",
88 | t: ArgTypeInt,
89 | raw: uintptr(cap.Permitted),
90 | },
91 | {
92 | name: "inheritable",
93 | t: ArgTypeInt,
94 | raw: uintptr(cap.Inheritable),
95 | },
96 | },
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/tracer/types_cloneargs.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | // used by clone3 syscall
8 | type cloneArgs struct {
9 | Flags uint64
10 | PidFd uint64
11 | ChildTid uint64
12 | ParentTid uint64
13 | ExitSignal uint64
14 | Stack uint64
15 | StackSize uint64
16 | SetTLS uint64
17 | SetTid uint64
18 | SetTidSize uint64
19 | Cgroup uint64
20 | }
21 |
22 | func init() {
23 | registerTypeHandler(argTypeCloneArgs, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
24 |
25 | if raw > 0 {
26 | // read the raw C struct from the process memory
27 | mem, err := readSize(pid, raw, unsafe.Sizeof(cloneArgs{}))
28 | if err != nil {
29 | return err
30 | }
31 |
32 | var args cloneArgs
33 | if err := decodeStruct(mem, &args); err != nil {
34 | return err
35 | }
36 |
37 | arg.obj = convertCloneArgs(args)
38 | arg.t = ArgTypeObject
39 | } else {
40 | arg.annotation = "NULL"
41 | arg.replace = true
42 | }
43 | return nil
44 | })
45 | }
46 |
47 | func convertCloneArgs(args cloneArgs) *Object {
48 | return &Object{
49 | Name: "clone_args",
50 | Properties: []Arg{
51 | {
52 | name: "flags",
53 | t: ArgTypeUnsignedLong,
54 | raw: uintptr(args.Flags),
55 | },
56 | {
57 | name: "pid_fd",
58 | t: ArgTypeUnsignedLong,
59 | raw: uintptr(args.PidFd),
60 | },
61 | {
62 | name: "child_tid",
63 | t: ArgTypeUnsignedLong,
64 | raw: uintptr(args.ChildTid),
65 | },
66 | {
67 | name: "parent_tid",
68 | t: ArgTypeUnsignedLong,
69 | raw: uintptr(args.ParentTid),
70 | },
71 | {
72 | name: "exit_signal",
73 | t: ArgTypeUnsignedLong,
74 | raw: uintptr(args.ExitSignal),
75 | },
76 | {
77 | name: "stack",
78 | t: ArgTypeUnsignedLong,
79 | raw: uintptr(args.Stack),
80 | },
81 | {
82 | name: "stack_size",
83 | t: ArgTypeUnsignedLong,
84 | raw: uintptr(args.StackSize),
85 | },
86 | {
87 | name: "set_tls",
88 | t: ArgTypeUnsignedLong,
89 | raw: uintptr(args.SetTLS),
90 | },
91 | {
92 | name: "set_tid",
93 | t: ArgTypeUnsignedLong,
94 | raw: uintptr(args.SetTid),
95 | },
96 | {
97 | name: "set_tid_size",
98 | t: ArgTypeUnsignedLong,
99 | raw: uintptr(args.SetTidSize),
100 | },
101 | {
102 | name: "cgroup",
103 | t: ArgTypeUnsignedLong,
104 | raw: uintptr(args.Cgroup),
105 | },
106 | },
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/tracer/types_data.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "syscall"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(ArgTypeData, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | switch metadata.LenSource {
11 | case LenSourceNextPointer:
12 | if next == 0 {
13 | return nil
14 | }
15 | if buf, err := readSize(pid, next, 4); err == nil {
16 | size := uintptr(decodeInt(buf))
17 | data, err := readSize(pid, raw, size)
18 | if err != nil {
19 | return err
20 | }
21 | arg.data = data
22 | }
23 | case LenSourcePrev:
24 | data, err := readSize(pid, raw, prev)
25 | if err != nil {
26 | return err
27 | }
28 | arg.data = data
29 | case LenSourceNext:
30 | data, err := readSize(pid, raw, next)
31 | if err != nil {
32 | return err
33 | }
34 | arg.data = data
35 | case LenSourceReturnValue:
36 | data, err := readSize(pid, raw, ret)
37 | if err != nil {
38 | return err
39 | }
40 | arg.data = data
41 | default:
42 | return fmt.Errorf("syscall %s has no supported count location", metadata.Name)
43 | }
44 | return nil
45 | })
46 | }
47 |
48 | func readSize(pid int, addr uintptr, size uintptr) ([]byte, error) {
49 |
50 | if size == 0 || size>>(bitSize-1) == 1 { // if negative for this arch
51 | return nil, nil
52 | }
53 | data := make([]byte, size)
54 | count, err := syscall.PtracePeekData(pid, addr, data)
55 | if err != nil {
56 | return nil, fmt.Errorf("read of 0x%x (%d) failed: %w", addr, size, err)
57 | }
58 | return data[:count], nil
59 | }
60 |
--------------------------------------------------------------------------------
/tracer/types_epollevent.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeEpollEvent, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | // read the raw C struct from the process memory
14 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(unix.EpollEvent{}))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | var event unix.EpollEvent
20 | if err := decodeStruct(rawTimeVal, &event); err != nil {
21 | return err
22 | }
23 |
24 | arg.obj = convertEpollEvent(&event)
25 | arg.t = ArgTypeObject
26 | } else {
27 | arg.annotation = "NULL"
28 | arg.replace = true
29 | }
30 | return nil
31 | })
32 | }
33 |
34 | func convertEpollEvent(ev *unix.EpollEvent) *Object {
35 | if ev == nil {
36 | return nil
37 | }
38 | return &Object{
39 | Name: "epoll_event",
40 | Properties: []Arg{
41 | {
42 | name: "events",
43 | t: ArgTypeUnsignedLong,
44 | raw: uintptr(ev.Events),
45 | },
46 | {
47 | name: "fd",
48 | t: ArgTypeAddress,
49 | raw: uintptr(ev.Fd),
50 | },
51 | },
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tracer/types_error.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | func init() {
4 | registerTypeHandler(argTypeIntOrErrorCode, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
5 | if arg.Int() < 0 {
6 | arg.t = ArgTypeErrorCode
7 | } else {
8 | arg.t = ArgTypeInt
9 | }
10 | return nil
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/tracer/types_fdset.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "github.com/liamg/grace/tracer/annotation"
7 |
8 | "golang.org/x/sys/unix"
9 | )
10 |
11 | func init() {
12 | registerTypeHandler(argTypeFdSet, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
13 | if raw > 0 {
14 | // read the raw C struct from the process memory
15 | rawFdset, err := readSize(pid, raw, unsafe.Sizeof(unix.FdSet{}))
16 | if err != nil {
17 | return err
18 | }
19 |
20 | // safely squish it into a struct in our own memory space
21 | var fdset unix.FdSet
22 | if err := decodeStruct(rawFdset, &fdset); err != nil {
23 | return err
24 | }
25 |
26 | // convert into a nice array for output
27 | arg.array = convertFdset(&fdset, pid)
28 | }
29 | arg.t = ArgTypeArray
30 | return nil
31 | })
32 | }
33 |
34 | func convertFdset(fdset *unix.FdSet, pid int) []Arg {
35 | var fds []Arg
36 | for _, fd := range fdset.Bits {
37 | if fd == 0 {
38 | break
39 | }
40 | item := Arg{
41 | name: "fd",
42 | t: ArgTypeInt,
43 | raw: uintptr(fd),
44 | }
45 | annotation.AnnotateFd(&item, pid)
46 | fds = append(fds, item)
47 | }
48 | return fds
49 | }
50 |
--------------------------------------------------------------------------------
/tracer/types_int.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(argTypeIntArray, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | var count int
11 | switch metadata.LenSource {
12 | case LenSourcePrev:
13 | count = int(prev)
14 | case LenSourceNext:
15 | count = int(next)
16 | case LenSourceReturnValue:
17 | count = int(ret)
18 | case LenSourceFixed:
19 | count = metadata.FixedCount
20 | default:
21 | return fmt.Errorf("syscall %s has no supported count location", metadata.Name)
22 | }
23 |
24 | mem, err := readSize(pid, raw, 4*uintptr(count))
25 | if err != nil {
26 | return err
27 | }
28 |
29 | target := make([]int32, count)
30 | if err := decodeAnonymous(reflect.ValueOf(&target).Elem(), mem); err != nil {
31 | return err
32 | }
33 |
34 | arg.array = nil
35 | for i := 0; i < count; i++ {
36 | arg.array = append(arg.array, Arg{
37 | t: ArgTypeInt,
38 | raw: uintptr(target[i]),
39 | })
40 | }
41 | arg.t = ArgTypeArray
42 |
43 | return nil
44 | })
45 | }
46 |
--------------------------------------------------------------------------------
/tracer/types_int_ptr.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | func init() {
8 | registerTypeHandler(argTypeUnsignedIntPtr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
9 | var underlying uint32
10 | if buf, err := readSize(pid, next, unsafe.Sizeof(underlying)); err == nil {
11 | arg.raw = uintptr(decodeInt(buf))
12 | arg.t = ArgTypeUnsignedInt
13 | } else {
14 | arg.t = ArgTypeAddress
15 | if raw == 0 {
16 | arg.annotation = "NULL"
17 | arg.replace = true
18 | }
19 | }
20 | return nil
21 | })
22 | registerTypeHandler(argTypeUnsignedInt64Ptr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
23 | var underlying uint64
24 | if buf, err := readSize(pid, next, unsafe.Sizeof(underlying)); err == nil {
25 | arg.raw = uintptr(decodeInt(buf))
26 | arg.t = ArgTypeUnsignedInt
27 | } else {
28 | arg.t = ArgTypeAddress
29 | if raw == 0 {
30 | arg.annotation = "NULL"
31 | arg.replace = true
32 | }
33 | }
34 | return nil
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/tracer/types_iocb.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type iocb struct {
8 | Data uint64
9 | Key uint32
10 | Opcode uint16
11 | Priority uint16
12 | Flags uint32
13 | Fd uint32
14 | Offset uint64
15 | Addr uint64
16 | Len uint32
17 | Pos uint64
18 | Reserved2 uint32
19 | Reserved3 uint64
20 | }
21 |
22 | func init() {
23 | registerTypeHandler(argTypeIoCB, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
24 |
25 | if raw > 0 {
26 |
27 | // read the raw C struct from the process memory
28 | mem, err := readSize(pid, raw, unsafe.Sizeof(ioevent{}))
29 | if err != nil {
30 | return err
31 | }
32 |
33 | var rawIoCB iocb
34 | if err := decodeStruct(mem, &rawIoCB); err != nil {
35 | return err
36 | }
37 |
38 | arg.t = ArgTypeObject
39 | arg.obj = convertIoCB(rawIoCB)
40 | } else {
41 | arg.annotation = "NULL"
42 | arg.replace = true
43 | }
44 | return nil
45 | })
46 | }
47 |
48 | func convertIoCB(cb iocb) *Object {
49 | return &Object{
50 | Name: "iocb",
51 | Properties: []Arg{
52 | {
53 | name: "data",
54 | t: ArgTypeUnsignedLong,
55 | raw: uintptr(cb.Data),
56 | },
57 | {
58 | name: "key",
59 | t: ArgTypeUnsignedInt,
60 | raw: uintptr(cb.Key),
61 | },
62 | {
63 | name: "opcode",
64 | t: ArgTypeUnsignedInt,
65 | raw: uintptr(cb.Opcode),
66 | },
67 | {
68 | name: "priority",
69 | t: ArgTypeUnsignedInt,
70 | raw: uintptr(cb.Priority),
71 | },
72 | {
73 | name: "flags",
74 | t: ArgTypeUnsignedInt,
75 | raw: uintptr(cb.Flags),
76 | },
77 | {
78 | name: "fd",
79 | t: ArgTypeUnsignedInt,
80 | raw: uintptr(cb.Fd),
81 | },
82 | {
83 | name: "offset",
84 | t: ArgTypeUnsignedLong,
85 | raw: uintptr(cb.Offset),
86 | },
87 | {
88 | name: "addr",
89 | t: ArgTypeUnsignedLong,
90 | raw: uintptr(cb.Addr),
91 | },
92 | {
93 | name: "len",
94 | t: ArgTypeUnsignedInt,
95 | raw: uintptr(cb.Len),
96 | },
97 | {
98 | name: "pos",
99 | t: ArgTypeUnsignedLong,
100 | raw: uintptr(cb.Pos),
101 | },
102 | {
103 | name: "reserved2",
104 | t: ArgTypeUnsignedInt,
105 | raw: uintptr(cb.Reserved2),
106 | },
107 | {
108 | name: "reserved3",
109 | t: ArgTypeUnsignedLong,
110 | raw: uintptr(cb.Reserved3),
111 | },
112 | },
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/tracer/types_ioevents.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "reflect"
5 | "unsafe"
6 | )
7 |
8 | type ioevent struct {
9 | Data uint64
10 | Obj uint64
11 | Res int64
12 | Res2 int64
13 | }
14 |
15 | func init() {
16 | registerTypeHandler(argTypeIoEvents, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
17 |
18 | if raw > 0 {
19 |
20 | var events []Arg
21 |
22 | // ret contains number of events read
23 | if ret > 0 {
24 |
25 | // read the raw C struct from the process memory
26 | mem, err := readSize(pid, raw, unsafe.Sizeof(ioevent{})*ret)
27 | if err != nil {
28 | return err
29 | }
30 |
31 | var rawEvents []ioevent
32 | if err := decodeAnonymous(reflect.ValueOf(&rawEvents).Elem(), mem); err != nil {
33 | return err
34 | }
35 |
36 | events = convertIoEvents(rawEvents)
37 | }
38 |
39 | arg.t = ArgTypeArray
40 | arg.array = events
41 | } else {
42 | arg.annotation = "NULL"
43 | arg.replace = true
44 | }
45 | return nil
46 | })
47 | registerTypeHandler(argTypeIoEvent, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
48 |
49 | if raw > 0 {
50 |
51 | // read the raw C struct from the process memory
52 | mem, err := readSize(pid, raw, unsafe.Sizeof(ioevent{}))
53 | if err != nil {
54 | return err
55 | }
56 |
57 | var rawEvent ioevent
58 | if err := decodeStruct(mem, &rawEvent); err != nil {
59 | return err
60 | }
61 |
62 | arg.t = ArgTypeObject
63 | arg.obj = convertIoEvent(rawEvent)
64 | } else {
65 | arg.annotation = "NULL"
66 | arg.replace = true
67 | }
68 | return nil
69 | })
70 | }
71 |
72 | func convertIoEvents(events []ioevent) []Arg {
73 | var output []Arg
74 | for _, event := range events {
75 | output = append(output, Arg{
76 | t: ArgTypeObject,
77 | obj: convertIoEvent(event),
78 | })
79 | }
80 | return output
81 | }
82 |
83 | func convertIoEvent(event ioevent) *Object {
84 | return &Object{
85 | Name: "io_event",
86 | Properties: []Arg{
87 | {
88 | name: "data",
89 | t: ArgTypeUnsignedLong,
90 | raw: uintptr(event.Data),
91 | },
92 | {
93 | name: "obj",
94 | t: ArgTypeUnsignedLong,
95 | raw: uintptr(event.Obj),
96 | },
97 | {
98 | name: "res",
99 | t: ArgTypeLong,
100 | raw: uintptr(event.Res),
101 | },
102 | {
103 | name: "res2",
104 | t: ArgTypeLong,
105 | raw: uintptr(event.Res2),
106 | },
107 | },
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/tracer/types_iouring.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type iouringParams struct {
8 | SqEntries uint32
9 | CqEntries uint32
10 | Flags uint32
11 | SqThreadCpu uint32
12 | SqThreadIdle uint32
13 | Features uint32
14 | WqFd uint32
15 | }
16 |
17 | func init() {
18 | registerTypeHandler(argTypeIoUringParams, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
19 |
20 | if raw > 0 {
21 | // read the raw C struct from the process memory
22 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(iouringParams{}))
23 | if err != nil {
24 | return err
25 | }
26 |
27 | var params iouringParams
28 | if err := decodeStruct(rawTimeVal, ¶ms); err != nil {
29 | return err
30 | }
31 |
32 | arg.obj = convertIoUringParams(params)
33 | arg.t = ArgTypeObject
34 | } else {
35 | arg.annotation = "NULL"
36 | arg.replace = true
37 | }
38 | return nil
39 | })
40 | }
41 |
42 | func convertIoUringParams(u iouringParams) *Object {
43 | return &Object{
44 | Name: "io_uring_params",
45 | Properties: []Arg{
46 | {
47 | name: "sq_entries",
48 | t: ArgTypeUnsignedLong,
49 | raw: uintptr(u.SqEntries),
50 | },
51 | {
52 | name: "cq_entries",
53 | t: ArgTypeUnsignedLong,
54 | raw: uintptr(u.CqEntries),
55 | },
56 | {
57 | name: "flags",
58 | t: ArgTypeUnsignedLong,
59 | raw: uintptr(u.Flags),
60 | },
61 | {
62 | name: "sq_thread_cpu",
63 | t: ArgTypeUnsignedLong,
64 | raw: uintptr(u.SqThreadCpu),
65 | },
66 | {
67 | name: "sq_thread_idle",
68 | t: ArgTypeUnsignedLong,
69 | raw: uintptr(u.SqThreadIdle),
70 | },
71 | {
72 | name: "features",
73 | t: ArgTypeUnsignedLong,
74 | raw: uintptr(u.Features),
75 | },
76 | {
77 | name: "wq_fd",
78 | t: ArgTypeUnsignedLong,
79 | raw: uintptr(u.WqFd),
80 | },
81 | },
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/tracer/types_iovec.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "reflect"
5 | "unsafe"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(argTypeIovecArray, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | // read the raw C struct from the process memory
11 | mem, err := readSize(pid, raw, next*unsafe.Sizeof(iovec{}))
12 | if err != nil {
13 | return err
14 | }
15 |
16 | iovecs := make([]iovec, next)
17 | if err := decodeAnonymous(reflect.ValueOf(&iovecs).Elem(), mem); err != nil {
18 | return err
19 | }
20 |
21 | arg.array, err = convertIovecs(iovecs, pid)
22 | if err != nil {
23 | return err
24 | }
25 | arg.t = ArgTypeArray
26 | return nil
27 | })
28 | }
29 |
30 | type iovec struct {
31 | Base uintptr /* Starting address */
32 | Len uintptr /* Number of bytes to transfer */
33 | }
34 |
35 | func convertIovecs(vecs []iovec, pid int) ([]Arg, error) {
36 | var output []Arg
37 | for _, fd := range vecs {
38 | vec, err := convertIovec(fd, pid)
39 | if err != nil {
40 | return nil, err
41 | }
42 | output = append(output, *vec)
43 | }
44 | return output, nil
45 | }
46 |
47 | func convertIovec(vec iovec, pid int) (*Arg, error) {
48 |
49 | base, err := readSize(pid, vec.Base, uintptr(vec.Len))
50 | if err != nil {
51 | return nil, err
52 | }
53 |
54 | return &Arg{
55 | t: ArgTypeObject,
56 | obj: &Object{
57 | Name: "iovec",
58 | Properties: []Arg{
59 | {
60 | name: "base",
61 | t: ArgTypeData,
62 | data: base,
63 | raw: vec.Base,
64 | },
65 | {
66 | name: "len",
67 | t: ArgTypeUnsignedInt,
68 | raw: vec.Len,
69 | },
70 | },
71 | },
72 | known: true,
73 | }, nil
74 | }
75 |
--------------------------------------------------------------------------------
/tracer/types_itimerspec.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeItimerspec, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | // read the raw C struct from the process memory
14 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(unix.ItimerSpec{}))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | var timeVal unix.ItimerSpec
20 | if err := decodeStruct(rawTimeVal, &timeVal); err != nil {
21 | return err
22 | }
23 |
24 | arg.obj = convertITimerSpec(&timeVal)
25 | arg.t = ArgTypeObject
26 | } else {
27 | arg.annotation = "NULL"
28 | arg.replace = true
29 | }
30 | return nil
31 | })
32 | }
33 |
34 | func convertITimerSpec(u *unix.ItimerSpec) *Object {
35 | if u == nil {
36 | return nil
37 | }
38 | return &Object{
39 | Name: "itimerspec",
40 | Properties: []Arg{
41 | {
42 | name: "interval",
43 | t: ArgTypeObject,
44 | obj: convertTimeSpec(&u.Interval),
45 | },
46 | {
47 | name: "value",
48 | t: ArgTypeObject,
49 | obj: convertTimeSpec(&u.Value),
50 | },
51 | },
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tracer/types_itimerval.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeItimerval, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | // read the raw C struct from the process memory
14 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Itimerval{}))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | var timeVal unix.Itimerval
20 | if err := decodeStruct(rawTimeVal, &timeVal); err != nil {
21 | return err
22 | }
23 |
24 | arg.obj = convertITimerVal(&timeVal)
25 | arg.t = ArgTypeObject
26 | } else {
27 | arg.annotation = "NULL"
28 | arg.replace = true
29 | }
30 | return nil
31 | })
32 | }
33 |
34 | func convertITimerVal(u *unix.Itimerval) *Object {
35 | return &Object{
36 | Name: "itimerval",
37 | Properties: []Arg{
38 | {
39 | name: "interval",
40 | t: ArgTypeObject,
41 | obj: convertTimeVal(&u.Interval),
42 | },
43 | {
44 | name: "value",
45 | t: ArgTypeObject,
46 | obj: convertTimeVal(&u.Value),
47 | },
48 | },
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tracer/types_landlock.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | // used by clone3 syscall
8 | type landlockRulesetAttr struct {
9 | HandledAccessFS uint64
10 | }
11 |
12 | func init() {
13 | registerTypeHandler(argTypeLandlockRulesetAttr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
14 |
15 | if raw > 0 {
16 | // read the raw C struct from the process memory
17 | mem, err := readSize(pid, raw, unsafe.Sizeof(landlockRulesetAttr{}))
18 | if err != nil {
19 | return err
20 | }
21 |
22 | var attr landlockRulesetAttr
23 | if err := decodeStruct(mem, &attr); err != nil {
24 | return err
25 | }
26 |
27 | arg.obj = convertLandlockRulesetAttr(attr)
28 | arg.t = ArgTypeObject
29 | } else {
30 | arg.annotation = "NULL"
31 | arg.replace = true
32 | }
33 | return nil
34 | })
35 | }
36 |
37 | func convertLandlockRulesetAttr(attr landlockRulesetAttr) *Object {
38 | return &Object{
39 | Name: "landlock_ruleset_attr",
40 | Properties: []Arg{
41 | {
42 | name: "handled_access_fs",
43 | t: ArgTypeUnsignedLong,
44 | raw: uintptr(attr.HandledAccessFS),
45 | },
46 | },
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tracer/types_mountattr.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | // used by clone3 syscall
8 | type mountAttr struct {
9 | Set uint64
10 | Clear uint64
11 | Propagation uint64
12 | UserNamespaceFd uint64
13 | }
14 |
15 | func init() {
16 | registerTypeHandler(argTypeMountAttr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
17 |
18 | if raw > 0 {
19 | // read the raw C struct from the process memory
20 | mem, err := readSize(pid, raw, unsafe.Sizeof(mountAttr{}))
21 | if err != nil {
22 | return err
23 | }
24 |
25 | var attr mountAttr
26 | if err := decodeStruct(mem, &attr); err != nil {
27 | return err
28 | }
29 |
30 | arg.obj = convertMountAttr(attr)
31 | arg.t = ArgTypeObject
32 | } else {
33 | arg.annotation = "NULL"
34 | arg.replace = true
35 | }
36 | return nil
37 | })
38 | }
39 |
40 | func convertMountAttr(attr mountAttr) *Object {
41 | return &Object{
42 | Name: "mount_attr",
43 | Properties: []Arg{
44 | {
45 | name: "set",
46 | t: ArgTypeUnsignedLong,
47 | raw: uintptr(attr.Set),
48 | },
49 | {
50 | name: "clear",
51 | t: ArgTypeUnsignedLong,
52 | raw: uintptr(attr.Clear),
53 | },
54 | {
55 | name: "propagation",
56 | t: ArgTypeUnsignedLong,
57 | raw: uintptr(attr.Propagation),
58 | },
59 | {
60 | name: "user_namespace_fd",
61 | t: ArgTypeUnsignedLong,
62 | raw: uintptr(attr.UserNamespaceFd),
63 | },
64 | },
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tracer/types_mqattr.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type mqattr struct {
8 | Flags int32
9 | Maxmsg int32
10 | Msgsize int32
11 | Curmsgs int32
12 | }
13 |
14 | func init() {
15 | registerTypeHandler(argTypeMqAttr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
16 |
17 | if raw > 0 {
18 | // read the raw C struct from the process memory
19 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(mqattr{}))
20 | if err != nil {
21 | return err
22 | }
23 |
24 | var attr mqattr
25 | if err := decodeStruct(rawTimeVal, &attr); err != nil {
26 | return err
27 | }
28 |
29 | arg.obj = convertMqAttr(attr)
30 | arg.t = ArgTypeObject
31 | } else {
32 | arg.annotation = "NULL"
33 | arg.replace = true
34 | }
35 | return nil
36 | })
37 | }
38 |
39 | func convertMqAttr(a mqattr) *Object {
40 | return &Object{
41 | Name: "mq_attr",
42 | Properties: []Arg{
43 | {
44 | name: "flags",
45 | t: ArgTypeUnsignedLong,
46 | raw: uintptr(a.Flags),
47 | },
48 | {
49 | name: "maxmsg",
50 | t: ArgTypeUnsignedLong,
51 | raw: uintptr(a.Maxmsg),
52 | },
53 | {
54 | name: "msgsize",
55 | t: ArgTypeUnsignedLong,
56 | raw: uintptr(a.Msgsize),
57 | },
58 | {
59 | name: "curmsgs",
60 | t: ArgTypeUnsignedLong,
61 | raw: uintptr(a.Curmsgs),
62 | },
63 | },
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tracer/types_openhow.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "github.com/liamg/grace/tracer/annotation"
7 | )
8 |
9 | // used by clone3 syscall
10 | type openHow struct {
11 | Flags uint64
12 | Mode uint64
13 | Resolve uint64
14 | }
15 |
16 | func init() {
17 | registerTypeHandler(argTypeOpenHow, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
18 |
19 | if raw > 0 {
20 | // read the raw C struct from the process memory
21 | mem, err := readSize(pid, raw, unsafe.Sizeof(openHow{}))
22 | if err != nil {
23 | return err
24 | }
25 |
26 | var how openHow
27 | if err := decodeStruct(mem, &how); err != nil {
28 | return err
29 | }
30 |
31 | arg.obj = convertOpenHow(how)
32 | arg.t = ArgTypeObject
33 | } else {
34 | arg.annotation = "NULL"
35 | arg.replace = true
36 | }
37 | return nil
38 | })
39 | }
40 |
41 | func convertOpenHow(how openHow) *Object {
42 |
43 | flags := Arg{
44 | name: "flags",
45 | t: ArgTypeUnsignedLong,
46 | raw: uintptr(how.Flags),
47 | }
48 | annotation.AnnotateOpenFlags(&flags, 0)
49 |
50 | mode := Arg{
51 | name: "flags",
52 | t: ArgTypeUnsignedLong,
53 | raw: uintptr(how.Mode),
54 | }
55 | annotation.AnnotateAccMode(&mode, 0)
56 |
57 | resolve := Arg{
58 | name: "resolve",
59 | t: ArgTypeUnsignedLong,
60 | raw: uintptr(how.Resolve),
61 | }
62 | annotation.AnnotateResolveFlags(&mode, 0)
63 |
64 | return &Object{
65 | Name: "open_how",
66 | Properties: []Arg{
67 | flags,
68 | mode,
69 | resolve,
70 | },
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/tracer/types_pollfd.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "reflect"
5 | "unsafe"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(argTypePollFdArray, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | if raw > 0 {
11 | // read the raw C struct from the process memory
12 | rawPollFds, err := readSize(pid, raw, next*unsafe.Sizeof(pollfd{}))
13 | if err != nil {
14 | return err
15 | }
16 |
17 | pollFds := make([]pollfd, next)
18 | if err := decodeAnonymous(reflect.ValueOf(&pollFds).Elem(), rawPollFds); err != nil {
19 | return err
20 | }
21 |
22 | arg.array = convertPollFds(pollFds)
23 | }
24 | arg.t = ArgTypeArray
25 | return nil
26 | })
27 | }
28 |
29 | type pollfd struct {
30 | Fd int /* file descriptor */
31 | Events uint16 /* events requested for polling */
32 | REvents uint32 /* events that occurred during polling */
33 | }
34 |
35 | func convertPollFds(fds []pollfd) []Arg {
36 | var output []Arg
37 | for _, fd := range fds {
38 | output = append(output, convertPollFd(fd))
39 | }
40 | return output
41 | }
42 |
43 | func convertPollFd(fd pollfd) Arg {
44 | return Arg{
45 | t: ArgTypeObject,
46 | obj: &Object{
47 | Name: "pollfd",
48 | Properties: []Arg{
49 | {
50 | name: "fd",
51 | t: ArgTypeInt,
52 | raw: uintptr(fd.Fd),
53 | },
54 | {
55 | name: "events",
56 | t: ArgTypeInt,
57 | raw: uintptr(fd.Events),
58 | },
59 | {
60 | name: "revents",
61 | t: ArgTypeInt,
62 | raw: uintptr(fd.REvents),
63 | },
64 | },
65 | },
66 | known: true,
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tracer/types_rlimit.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "syscall"
5 | "unsafe"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(argTypeRLimit, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | if raw > 0 {
11 | data, err := readSize(pid, raw, unsafe.Sizeof(syscall.Rlimit{}))
12 | if err != nil {
13 | return err
14 | }
15 |
16 | var rlimit syscall.Rlimit
17 | if err := decodeStruct(data, &rlimit); err != nil {
18 | return err
19 | }
20 |
21 | arg.obj = convertRLimit(&rlimit)
22 | arg.t = ArgTypeObject
23 | } else {
24 | arg.t = ArgTypeAddress
25 | arg.annotation = "NULL"
26 | arg.replace = true
27 | }
28 | return nil
29 | })
30 | }
31 |
32 | func convertRLimit(rlimit *syscall.Rlimit) *Object {
33 | return &Object{
34 | Name: "rlimit",
35 | Properties: []Arg{
36 | {
37 | name: "cur",
38 | t: ArgTypeUnsignedLong,
39 | raw: uintptr(rlimit.Cur),
40 | },
41 | {
42 | name: "max",
43 | t: ArgTypeUnsignedLong,
44 | raw: uintptr(rlimit.Max),
45 | },
46 | },
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tracer/types_rusage.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "syscall"
5 | "unsafe"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(argTypeRUsage, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | if raw > 0 {
11 | data, err := readSize(pid, raw, unsafe.Sizeof(syscall.Rusage{}))
12 | if err != nil {
13 | return err
14 | }
15 |
16 | var rusage syscall.Rusage
17 | if err := decodeStruct(data, &rusage); err != nil {
18 | return err
19 | }
20 |
21 | arg.obj = convertRUsage(&rusage)
22 | arg.t = ArgTypeObject
23 | } else {
24 | arg.t = ArgTypeAddress
25 | arg.annotation = "NULL"
26 | arg.replace = true
27 | }
28 | return nil
29 | })
30 | }
31 |
32 | func convertRUsage(rusage *syscall.Rusage) *Object {
33 | return &Object{
34 | Name: "rusage",
35 | Properties: []Arg{
36 | {
37 | name: "utime",
38 | t: ArgTypeObject,
39 | obj: &Object{
40 | Name: "timeval",
41 | Properties: []Arg{
42 | {
43 | name: "tv_sec",
44 | t: ArgTypeLong,
45 | raw: uintptr(rusage.Utime.Sec),
46 | },
47 | {
48 | name: "tv_usec",
49 | t: ArgTypeLong,
50 | raw: uintptr(rusage.Utime.Usec),
51 | },
52 | },
53 | },
54 | },
55 | {
56 | name: "stime",
57 | t: ArgTypeObject,
58 | obj: &Object{
59 | Name: "timeval",
60 | Properties: []Arg{
61 | {
62 | name: "tv_sec",
63 | t: ArgTypeLong,
64 | raw: uintptr(rusage.Stime.Sec),
65 | },
66 | {
67 | name: "tv_usec",
68 | t: ArgTypeLong,
69 | raw: uintptr(rusage.Stime.Usec),
70 | },
71 | },
72 | },
73 | },
74 | {
75 | name: "maxrss",
76 | t: ArgTypeLong,
77 | raw: uintptr(rusage.Maxrss),
78 | },
79 | {
80 | name: "ixrss",
81 | t: ArgTypeLong,
82 | raw: uintptr(rusage.Ixrss),
83 | },
84 | {
85 | name: "idrss",
86 | t: ArgTypeLong,
87 | raw: uintptr(rusage.Idrss),
88 | },
89 | {
90 | name: "isrss",
91 | t: ArgTypeLong,
92 | raw: uintptr(rusage.Isrss),
93 | },
94 | {
95 | name: "minflt",
96 | t: ArgTypeLong,
97 | raw: uintptr(rusage.Minflt),
98 | },
99 | {
100 | name: "majflt",
101 | t: ArgTypeLong,
102 | raw: uintptr(rusage.Majflt),
103 | },
104 | {
105 | name: "nswap",
106 | t: ArgTypeLong,
107 | raw: uintptr(rusage.Nswap),
108 | },
109 | {
110 | name: "inblock",
111 | t: ArgTypeLong,
112 | raw: uintptr(rusage.Inblock),
113 | },
114 | {
115 | name: "oublock",
116 | t: ArgTypeLong,
117 | raw: uintptr(rusage.Oublock),
118 | },
119 | {
120 | name: "msgsnd",
121 | t: ArgTypeLong,
122 | raw: uintptr(rusage.Msgsnd),
123 | },
124 | {
125 | name: "msgrcv",
126 | t: ArgTypeLong,
127 | raw: uintptr(rusage.Msgrcv),
128 | },
129 | {
130 | name: "nsignals",
131 | t: ArgTypeLong,
132 | raw: uintptr(rusage.Nsignals),
133 | },
134 | {
135 | name: "nvcsw",
136 | t: ArgTypeLong,
137 | raw: uintptr(rusage.Nvcsw),
138 | },
139 | {
140 | name: "nivcsw",
141 | t: ArgTypeLong,
142 | raw: uintptr(rusage.Nivcsw),
143 | },
144 | },
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/tracer/types_schedattr.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type schedAttr struct {
8 | Size uint32
9 | SchedPolicy uint32
10 | SchedFlags uint64
11 | SchedNice int32
12 | SchedPriority uint32
13 | SchedRuntime uint64
14 | SchedDeadline uint64
15 | SchedPeriod uint64
16 | }
17 |
18 | func init() {
19 | registerTypeHandler(argTypeSchedAttr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
20 |
21 | if raw > 0 {
22 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(schedAttr{}))
23 | if err != nil {
24 | return err
25 | }
26 |
27 | var attr schedAttr
28 | if err := decodeStruct(rawVal, &attr); err != nil {
29 | return err
30 | }
31 |
32 | arg.obj = convertSchedAttr(attr)
33 | if err != nil {
34 | return err
35 | }
36 | arg.t = ArgTypeObject
37 | } else {
38 | arg.annotation = "NULL"
39 | arg.replace = true
40 | }
41 | return nil
42 | })
43 | }
44 |
45 | func convertSchedAttr(param schedAttr) *Object {
46 | return &Object{
47 | Name: "sched_attr",
48 | Properties: []Arg{
49 | {
50 | name: "size",
51 | t: ArgTypeInt,
52 | raw: uintptr(param.Size),
53 | },
54 | {
55 | name: "sched_policy",
56 | t: ArgTypeInt,
57 | raw: uintptr(param.SchedPolicy),
58 | },
59 | {
60 | name: "sched_flags",
61 | t: ArgTypeInt,
62 | raw: uintptr(param.SchedFlags),
63 | },
64 | {
65 | name: "sched_nice",
66 | t: ArgTypeInt,
67 | raw: uintptr(param.SchedNice),
68 | },
69 | {
70 | name: "sched_priority",
71 | t: ArgTypeInt,
72 | raw: uintptr(param.SchedPriority),
73 | },
74 | {
75 | name: "sched_runtime",
76 | t: ArgTypeInt,
77 | raw: uintptr(param.SchedRuntime),
78 | },
79 | {
80 | name: "sched_deadline",
81 | t: ArgTypeInt,
82 | raw: uintptr(param.SchedDeadline),
83 | },
84 | {
85 | name: "sched_period",
86 | t: ArgTypeInt,
87 | raw: uintptr(param.SchedPeriod),
88 | },
89 | },
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/tracer/types_schedparam.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type schedParam struct {
8 | Priority int32
9 | }
10 |
11 | func init() {
12 | registerTypeHandler(argTypeSchedParam, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
13 |
14 | if raw > 0 {
15 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(schedParam{}))
16 | if err != nil {
17 | return err
18 | }
19 |
20 | var param schedParam
21 | if err := decodeStruct(rawVal, ¶m); err != nil {
22 | return err
23 | }
24 |
25 | arg.obj = convertSchedParam(param)
26 | if err != nil {
27 | return err
28 | }
29 | arg.t = ArgTypeObject
30 | } else {
31 | arg.annotation = "NULL"
32 | arg.replace = true
33 | }
34 | return nil
35 | })
36 | }
37 |
38 | func convertSchedParam(param schedParam) *Object {
39 | return &Object{
40 | Name: "sched_param",
41 | Properties: []Arg{
42 | {
43 | name: "priority",
44 | t: ArgTypeInt,
45 | raw: uintptr(param.Priority),
46 | },
47 | },
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tracer/types_sembuf.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "reflect"
5 | "unsafe"
6 |
7 | "github.com/liamg/grace/tracer/annotation"
8 | )
9 |
10 | type sembuf struct {
11 | Num uint16 /* semaphore index in array */
12 | Op int16 /* semaphore operation */
13 | Flg int16 /* flags for operation */
14 | }
15 |
16 | func init() {
17 | registerTypeHandler(argTypeSembuf, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
18 | // read the raw C struct from the process memory
19 | mem, err := readSize(pid, raw, next*unsafe.Sizeof(sembuf{})*next)
20 | if err != nil {
21 | return err
22 | }
23 |
24 | sembufs := make([]sembuf, next)
25 | if err := decodeAnonymous(reflect.ValueOf(&sembufs).Elem(), mem); err != nil {
26 | return err
27 | }
28 |
29 | arg.array, err = convertSembufs(sembufs, pid)
30 | if err != nil {
31 | return err
32 | }
33 | arg.t = ArgTypeArray
34 | return nil
35 | })
36 | }
37 |
38 | func convertSembufs(bufs []sembuf, pid int) ([]Arg, error) {
39 | var items []Arg
40 | for _, buf := range bufs {
41 | obj := convertSembuf(buf, pid)
42 | items = append(items, obj)
43 | }
44 | return items, nil
45 | }
46 |
47 | func convertSembuf(buf sembuf, pid int) Arg {
48 |
49 | flagsArg := Arg{
50 | name: "flags",
51 | t: ArgTypeInt,
52 | raw: uintptr(buf.Flg),
53 | }
54 | annotation.AnnotateSemFlags(&flagsArg, pid)
55 |
56 | return Arg{
57 | name: "sops",
58 | t: ArgTypeObject,
59 | obj: &Object{
60 | Name: "sembuf",
61 | Properties: []Arg{
62 | {
63 | name: "sem_num",
64 | t: ArgTypeInt,
65 | raw: uintptr(buf.Num),
66 | },
67 | {
68 | name: "sem_op",
69 | t: ArgTypeInt,
70 | raw: uintptr(buf.Op),
71 | },
72 | flagsArg,
73 | },
74 | },
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/tracer/types_shmidds.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type shmidds struct {
8 | IPCPerm struct {
9 | Key uint32 /* Key provided to shmget */
10 | Uid uint32 /* Effective UID of owner */
11 | Gid uint32 /* Effective GID of owner */
12 | Cuid uint32 /* Effective UID of creator */
13 | Cgid uint32 /* Effective GID of creator */
14 | Mode uint32 /* Permissions and SHM_DEST + SHM_LOCKED flags */
15 | Pad1 uint16
16 | Seq uint16 /* Sequence */
17 | Pad2 uint16
18 | Unused1 uint
19 | Unused2 uint
20 | } /* Ownership and permissions */
21 | Segsz uint32 /* Size of shared segment (bytes) */
22 | Atime uint64 /* Last attach time */
23 | Dtime uint64 /* Last detach time */
24 | Ctime uint64 /* Last change time */
25 | Cpid uint32 /* PID of shared segment creator */
26 | Lpid uint32 /* PID of last shmat(2)/shmdt(2) syscall */
27 | Nattch uint16 /* Number of current attaches */
28 | Unused uint16
29 | Unused2 uintptr
30 | Unused3 uintptr
31 | }
32 |
33 | func init() {
34 | registerTypeHandler(argTypeSHMIDDS, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
35 |
36 | if raw > 0 {
37 |
38 | // read the raw C struct from the process memory
39 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(shmidds{}))
40 | if err != nil {
41 | return err
42 | }
43 |
44 | var ds shmidds
45 | if err := decodeStruct(rawTimeVal, &ds); err != nil {
46 | return err
47 | }
48 |
49 | arg.obj = convertSHMIDDS(&ds)
50 | arg.t = ArgTypeObject
51 | } else {
52 | arg.annotation = "NULL"
53 | arg.replace = true
54 | }
55 | return nil
56 | })
57 | }
58 |
59 | func convertSHMIDDS(ds *shmidds) *Object {
60 |
61 | var permProps []Arg
62 |
63 | permProps = append(permProps, Arg{
64 | name: "key",
65 | t: ArgTypeUnsignedInt,
66 | raw: uintptr(ds.IPCPerm.Key),
67 | })
68 | permProps = append(permProps, Arg{
69 | name: "uid",
70 | t: ArgTypeUnsignedInt,
71 | raw: uintptr(ds.IPCPerm.Uid),
72 | })
73 | permProps = append(permProps, Arg{
74 | name: "gid",
75 | t: ArgTypeUnsignedInt,
76 | raw: uintptr(ds.IPCPerm.Gid),
77 | })
78 | permProps = append(permProps, Arg{
79 | name: "cuid",
80 | t: ArgTypeUnsignedInt,
81 | raw: uintptr(ds.IPCPerm.Cuid),
82 | })
83 | permProps = append(permProps, Arg{
84 | name: "cgid",
85 | t: ArgTypeUnsignedInt,
86 | raw: uintptr(ds.IPCPerm.Cgid),
87 | })
88 | permProps = append(permProps, Arg{
89 | name: "mode",
90 | t: ArgTypeUnsignedInt,
91 | raw: uintptr(ds.IPCPerm.Mode),
92 | })
93 | permProps = append(permProps, Arg{
94 | name: "seq",
95 | t: ArgTypeUnsignedInt,
96 | raw: uintptr(ds.IPCPerm.Seq),
97 | })
98 |
99 | var props []Arg
100 |
101 | props = append(props, Arg{
102 | name: "perm",
103 | t: ArgTypeObject,
104 | obj: &Object{
105 | Name: "ipc_perm",
106 | },
107 | })
108 | props = append(props, Arg{
109 | name: "segsize",
110 | t: ArgTypeUnsignedInt,
111 | raw: uintptr(ds.Segsz),
112 | })
113 |
114 | // TODO: read time structs from process memory instead of storing raw addresses
115 |
116 | props = append(props, Arg{
117 | name: "atime",
118 | t: ArgTypeAddress,
119 | raw: uintptr(ds.Atime),
120 | })
121 | props = append(props, Arg{
122 | name: "dtime",
123 | t: ArgTypeAddress,
124 | raw: uintptr(ds.Dtime),
125 | })
126 | props = append(props, Arg{
127 | name: "ctime",
128 | t: ArgTypeAddress,
129 | raw: uintptr(ds.Ctime),
130 | })
131 |
132 | props = append(props, Arg{
133 | name: "cpid",
134 | t: ArgTypeUnsignedInt,
135 | raw: uintptr(ds.Cpid),
136 | })
137 | props = append(props, Arg{
138 | name: "lpid",
139 | t: ArgTypeUnsignedInt,
140 | raw: uintptr(ds.Lpid),
141 | })
142 | props = append(props, Arg{
143 | name: "nattch",
144 | t: ArgTypeUnsignedInt,
145 | raw: uintptr(ds.Nattch),
146 | })
147 |
148 | return &Object{
149 | Name: "shmid_ds",
150 | Properties: props,
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/tracer/types_sigaction.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "strings"
5 | "unsafe"
6 | )
7 |
8 | /*
9 | #include
10 |
11 | const void* sig_dfl = SIG_DFL;
12 | const void* sig_ign = SIG_IGN;
13 | */
14 | import "C"
15 |
16 | type sigAction struct {
17 | Handler uintptr
18 | Sigaction uintptr
19 | Mask int
20 | Flags int
21 | Restorer uintptr
22 | }
23 |
24 | func init() {
25 | registerTypeHandler(argTypeSigAction, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
26 | if raw > 0 {
27 |
28 | raw, err := readSize(pid, raw, unsafe.Sizeof(sigAction{}))
29 | if err != nil {
30 | return err
31 | }
32 |
33 | var action sigAction
34 | if err := decodeStruct(raw, &action); err != nil {
35 | return err
36 | }
37 |
38 | arg.obj = convertSigAction(&action)
39 | arg.t = ArgTypeObject
40 | } else {
41 | arg.annotation = "NULL"
42 | arg.replace = true
43 | }
44 | return nil
45 | })
46 | }
47 |
48 | func convertSigAction(action *sigAction) *Object {
49 | obj := Object{
50 | Name: "sigaction",
51 | }
52 |
53 | var handlerStr string
54 | switch action.Handler {
55 | case uintptr(C.sig_dfl):
56 | handlerStr = "SIG_DFL"
57 | case uintptr(C.sig_ign):
58 | handlerStr = "SIG_IGN"
59 | }
60 | obj.Properties = append(obj.Properties, Arg{
61 | name: "handler",
62 | t: ArgTypeAddress,
63 | raw: action.Handler,
64 | annotation: handlerStr,
65 | replace: handlerStr != "",
66 | })
67 |
68 | obj.Properties = append(obj.Properties, Arg{
69 | name: "sigaction",
70 | t: ArgTypeAddress,
71 | raw: action.Sigaction,
72 | })
73 | obj.Properties = append(obj.Properties, Arg{
74 | name: "mask",
75 | t: ArgTypeInt,
76 | raw: uintptr(action.Mask),
77 | })
78 |
79 | var signActionFlags []string
80 | if action.Flags&C.SA_NOCLDSTOP != 0 {
81 | signActionFlags = append(signActionFlags, "SA_NOCLDSTOP")
82 | }
83 | if action.Flags&C.SA_NOCLDWAIT != 0 {
84 | signActionFlags = append(signActionFlags, "SA_NOCLDWAIT")
85 | }
86 | if action.Flags&C.SA_NODEFER != 0 {
87 | signActionFlags = append(signActionFlags, "SA_NODEFER")
88 | }
89 | if action.Flags&C.SA_ONSTACK != 0 {
90 | signActionFlags = append(signActionFlags, "SA_ONSTACK")
91 | }
92 | if action.Flags&C.SA_RESETHAND != 0 {
93 | signActionFlags = append(signActionFlags, "SA_RESETHAND")
94 | }
95 | if action.Flags&C.SA_RESTART != 0 {
96 | signActionFlags = append(signActionFlags, "SA_RESTART")
97 | }
98 | if action.Flags&C.SA_RESTORER != 0 {
99 | signActionFlags = append(signActionFlags, "SA_RESTORER")
100 | }
101 | if action.Flags&C.SA_SIGINFO != 0 {
102 | signActionFlags = append(signActionFlags, "SA_SIGINFO")
103 | }
104 | if action.Flags&C.SA_UNSUPPORTED != 0 {
105 | signActionFlags = append(signActionFlags, "SA_UNSUPPORTED")
106 | }
107 | if action.Flags&C.SA_EXPOSE_TAGBITS != 0 {
108 | signActionFlags = append(signActionFlags, "SA_EXPOSE_TAGBITS")
109 | }
110 | flagStr := strings.Join(signActionFlags, "|")
111 |
112 | obj.Properties = append(obj.Properties, Arg{
113 | name: "flags",
114 | t: ArgTypeInt,
115 | raw: uintptr(action.Flags),
116 | annotation: flagStr,
117 | replace: flagStr != "",
118 | })
119 | obj.Properties = append(obj.Properties, Arg{
120 | name: "restorer",
121 | t: ArgTypeAddress,
122 | raw: action.Restorer,
123 | })
124 |
125 | return &obj
126 | }
127 |
--------------------------------------------------------------------------------
/tracer/types_siginfo.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "syscall"
5 | "unsafe"
6 |
7 | "github.com/liamg/grace/tracer/annotation"
8 |
9 | "golang.org/x/sys/unix"
10 | )
11 |
12 | /*
13 | #include
14 | */
15 | import "C"
16 |
17 | func init() {
18 | registerTypeHandler(argTypeSigInfo, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
19 | if raw > 0 {
20 |
21 | raw, err := readSize(pid, raw, unsafe.Sizeof(unix.Siginfo{}))
22 | if err != nil {
23 | return err
24 | }
25 |
26 | var info unix.Siginfo
27 | if err := decodeStruct(raw, &info); err != nil {
28 | return err
29 | }
30 |
31 | arg.obj = convertSigInfo(&info, pid)
32 | arg.t = ArgTypeObject
33 | } else {
34 | arg.annotation = "NULL"
35 | arg.replace = true
36 | }
37 | return nil
38 | })
39 | }
40 |
41 | func convertSigInfo(u *unix.Siginfo, pid int) *Object {
42 |
43 | signo := Arg{
44 | name: "signo",
45 | t: ArgTypeInt,
46 | raw: uintptr(u.Signo),
47 | }
48 | annotation.AnnotateSignal(&signo, pid)
49 |
50 | errStr := annotation.ErrNoToString(int(u.Errno))
51 | errno := Arg{
52 | name: "errno",
53 | t: ArgTypeInt,
54 | raw: uintptr(u.Errno),
55 | annotation: errStr,
56 | replace: errStr != "",
57 | }
58 |
59 | codeStr := annotation.SignalCodeToString(syscall.Signal(u.Signo), u.Code)
60 |
61 | code := Arg{
62 | name: "code",
63 | t: ArgTypeInt,
64 | raw: uintptr(u.Code),
65 | annotation: codeStr,
66 | replace: codeStr != "",
67 | }
68 |
69 | return &Object{
70 | Name: "siginfo",
71 | Properties: []Arg{
72 | signo,
73 | errno,
74 | code,
75 | },
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tracer/types_sockaddr.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "syscall"
6 | "unsafe"
7 |
8 | "github.com/liamg/grace/tracer/annotation"
9 | )
10 |
11 | func init() {
12 | registerTypeHandler(argTypeSockaddr, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
13 | if raw > 0 {
14 | rawFamily, err := readSize(pid, raw, unsafe.Sizeof(syscall.RawSockaddrInet4{}.Family))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | family := decodeInt(rawFamily)
20 |
21 | rawSockAddr, err := readSize(pid, raw, next)
22 | if err != nil {
23 | return err
24 | }
25 |
26 | arg.obj, err = convertSockAddr(family, rawSockAddr)
27 | if err != nil {
28 | return err
29 | }
30 | arg.t = ArgTypeObject
31 | } else {
32 | arg.t = ArgTypeAddress
33 | arg.annotation = "NULL"
34 | arg.replace = true
35 | }
36 | return nil
37 | })
38 | }
39 |
40 | func htons(port uint16) uint16 {
41 | return port>>8 | port<<8
42 | }
43 |
44 | func convertSockAddr(family int64, raw []byte) (*Object, error) {
45 | switch family {
46 | case syscall.AF_INET:
47 | var target syscall.RawSockaddrInet4
48 | if err := decodeStruct(raw, &target); err != nil {
49 | return nil, err
50 | }
51 | return &Object{
52 | Name: "sockaddr",
53 | Properties: []Arg{
54 | {
55 | name: "family",
56 | annotation: "AF_INET",
57 | replace: true,
58 | },
59 | {
60 | name: "port",
61 | t: ArgTypeInt,
62 | raw: uintptr(htons(target.Port)),
63 | },
64 | {
65 | name: "addr",
66 | t: ArgTypeData,
67 | data: []byte(fmt.Sprintf("%d.%d.%d.%d", target.Addr[0], target.Addr[1], target.Addr[2], target.Addr[3])),
68 | },
69 | },
70 | }, nil
71 | case syscall.AF_INET6:
72 | var target syscall.RawSockaddrInet6
73 | if err := decodeStruct(raw, &target); err != nil {
74 | return nil, err
75 | }
76 | return &Object{
77 | Name: "sockaddr",
78 | Properties: []Arg{
79 | {
80 | name: "family",
81 | annotation: "AF_INET6",
82 | replace: true,
83 | },
84 | {
85 | name: "port",
86 | t: ArgTypeInt,
87 | raw: uintptr(htons(target.Port)),
88 | },
89 | {
90 | name: "addr",
91 | t: ArgTypeData,
92 | data: []byte(fmt.Sprintf("%x:%x:%x:%x:%x:%x:%x:%x", target.Addr[0], target.Addr[1], target.Addr[2], target.Addr[3], target.Addr[4], target.Addr[5], target.Addr[6], target.Addr[7])),
93 | },
94 | {
95 | name: "flowinfo",
96 | t: ArgTypeInt,
97 | raw: uintptr(target.Flowinfo),
98 | },
99 | {
100 | name: "scope_id",
101 | t: ArgTypeInt,
102 | raw: uintptr(target.Scope_id),
103 | },
104 | },
105 | }, nil
106 | case syscall.AF_UNIX:
107 | var target syscall.RawSockaddrUnix
108 |
109 | if len(raw) < int(unsafe.Sizeof(target)) {
110 | raw = append(raw, make([]byte, int(unsafe.Sizeof(target))-len(raw))...)
111 | }
112 |
113 | if err := decodeStruct(raw, &target); err != nil {
114 | return nil, err
115 | }
116 | var path string
117 | for _, b := range target.Path {
118 | if b == 0 {
119 | break
120 | }
121 | path += string(byte(b))
122 | }
123 | return &Object{
124 | Name: "sockaddr",
125 | Properties: []Arg{
126 | {
127 | name: "family",
128 | annotation: "AF_UNIX",
129 | replace: true,
130 | },
131 | {
132 | name: "path",
133 | t: ArgTypeData,
134 | data: []byte(path),
135 | },
136 | },
137 | }, nil
138 | case syscall.AF_NETLINK:
139 | var target syscall.RawSockaddrNetlink
140 | if err := decodeStruct(raw, &target); err != nil {
141 | return nil, err
142 | }
143 | return &Object{
144 | Name: "sockaddr",
145 | Properties: []Arg{
146 | {
147 | name: "family",
148 | annotation: "AF_NETLINK",
149 | replace: true,
150 | },
151 | {
152 | name: "pid",
153 | t: ArgTypeInt,
154 | raw: uintptr(target.Pid),
155 | },
156 | {
157 | name: "groups",
158 | t: ArgTypeInt,
159 | raw: uintptr(target.Groups),
160 | },
161 | },
162 | }, nil
163 | default:
164 | var target syscall.RawSockaddr
165 | if err := decodeStruct(raw, &target); err != nil {
166 | return nil, err
167 | }
168 | data := make([]byte, len(target.Data))
169 | for i, b := range target.Data {
170 | data[i] = byte(b)
171 | }
172 | familyStr := annotation.SocketFamily(int(target.Family))
173 | return &Object{
174 | Name: "sockaddr",
175 | Properties: []Arg{
176 | {
177 | name: "family",
178 | annotation: familyStr,
179 | replace: familyStr != "",
180 | },
181 | {
182 | name: "data",
183 | t: ArgTypeData,
184 | data: data,
185 | },
186 | },
187 | }, nil
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/tracer/types_sockoptval.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | func init() {
4 | registerTypeHandler(argTypeSockoptval, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
5 | if raw > 0 {
6 | rawSockOptVal, err := readSize(pid, raw, next)
7 | if err != nil {
8 | return err
9 | }
10 |
11 | switch prev {
12 | // TODO: expect specific types for specific options?
13 | default:
14 | if next == 4 { // if it's exactly 4 bytes, it's probably an int
15 | arg.raw = uintptr(decodeInt(rawSockOptVal))
16 | arg.t = ArgTypeInt
17 | } else { // otherwise it's a big pile of misc data
18 | arg.data = rawSockOptVal
19 | arg.t = ArgTypeData
20 | }
21 | }
22 | } else {
23 | arg.t = ArgTypeAddress
24 | arg.annotation = "NULL"
25 | arg.replace = true
26 | }
27 | return nil
28 | })
29 | }
30 |
--------------------------------------------------------------------------------
/tracer/types_stack.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "github.com/liamg/grace/tracer/annotation"
7 | )
8 |
9 | type stack struct {
10 | Sp uintptr
11 | Flags uint32
12 | Size uint32
13 | }
14 |
15 | func init() {
16 | registerTypeHandler(argTypeStack, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
17 |
18 | if raw > 0 {
19 | // read the raw C struct from the process memory
20 | mem, err := readSize(pid, raw, unsafe.Sizeof(stack{}))
21 | if err != nil {
22 | return err
23 | }
24 |
25 | var stack stack
26 | if err := decodeStruct(mem, &stack); err != nil {
27 | return err
28 | }
29 |
30 | arg.obj = convertStack(&stack)
31 | arg.t = ArgTypeObject
32 | } else {
33 | arg.annotation = "NULL"
34 | arg.replace = true
35 | }
36 | return nil
37 | })
38 | }
39 |
40 | func convertStack(st *stack) *Object {
41 |
42 | flagsArg := Arg{
43 | name: "flags",
44 | t: ArgTypeUnsignedInt,
45 | raw: uintptr(st.Flags),
46 | }
47 | annotation.AnnotateSigStackFlags(&flagsArg, 0)
48 |
49 | return &Object{
50 | Name: "stack",
51 | Properties: []Arg{
52 | {
53 | name: "sp",
54 | t: ArgTypeAddress,
55 | raw: st.Sp,
56 | },
57 | flagsArg,
58 | {
59 | name: "size",
60 | t: ArgTypeUnsignedInt,
61 | raw: uintptr(st.Size),
62 | },
63 | },
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tracer/types_stat.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | "syscall"
7 | "unsafe"
8 |
9 | "github.com/liamg/grace/tracer/annotation"
10 |
11 | "golang.org/x/sys/unix"
12 | )
13 |
14 | func init() {
15 | registerTypeHandler(argTypeStat, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
16 | if raw > 0 {
17 | // read the raw C struct from the process memory
18 | rawStat, err := readSize(pid, raw, unsafe.Sizeof(syscall.Stat_t{}))
19 | if err != nil {
20 | return err
21 | }
22 |
23 | var stat syscall.Stat_t
24 | if err := decodeStruct(rawStat, &stat); err != nil {
25 | return err
26 | }
27 |
28 | arg.obj = convertStat(&stat)
29 | arg.t = ArgTypeObject
30 | } else {
31 | arg.annotation = "NULL"
32 | arg.replace = true
33 | }
34 | return nil
35 | })
36 | }
37 |
38 | func convertStat(stat *syscall.Stat_t) *Object {
39 | obj := Object{
40 | Name: "stat",
41 | }
42 |
43 | obj.Properties = append(obj.Properties, Arg{
44 | name: "mode",
45 | t: ArgTypeUnsignedInt,
46 | raw: uintptr(stat.Mode),
47 | annotation: permModeToString(stat.Mode),
48 | replace: true,
49 | })
50 |
51 | obj.Properties = append(obj.Properties, Arg{
52 | name: "dev",
53 | t: ArgTypeUnsignedInt,
54 | raw: uintptr(stat.Dev),
55 | annotation: annotation.DeviceToString(stat.Dev),
56 | replace: true,
57 | })
58 |
59 | obj.Properties = append(obj.Properties, Arg{
60 | name: "ino",
61 | t: ArgTypeUnsignedInt,
62 | raw: uintptr(stat.Ino),
63 | })
64 |
65 | obj.Properties = append(obj.Properties, Arg{
66 | name: "nlink",
67 | t: ArgTypeUnsignedInt,
68 | raw: uintptr(stat.Nlink),
69 | })
70 |
71 | obj.Properties = append(obj.Properties, Arg{
72 | name: "uid",
73 | t: ArgTypeUnsignedInt,
74 | raw: uintptr(stat.Uid),
75 | })
76 |
77 | obj.Properties = append(obj.Properties, Arg{
78 | name: "gid",
79 | t: ArgTypeUnsignedInt,
80 | raw: uintptr(stat.Gid),
81 | })
82 |
83 | obj.Properties = append(obj.Properties, Arg{
84 | name: "blksize",
85 | t: ArgTypeInt,
86 | raw: uintptr(stat.Blksize),
87 | })
88 |
89 | obj.Properties = append(obj.Properties, Arg{
90 | name: "blocks",
91 | t: ArgTypeInt,
92 | raw: uintptr(stat.Blocks),
93 | })
94 |
95 | obj.Properties = append(obj.Properties, Arg{
96 | name: "size",
97 | t: ArgTypeInt,
98 | raw: uintptr(stat.Size),
99 | })
100 |
101 | obj.Properties = append(obj.Properties, Arg{
102 | name: "nlink",
103 | t: ArgTypeUnsignedInt,
104 | raw: uintptr(stat.Nlink),
105 | })
106 |
107 | obj.Properties = append(obj.Properties, Arg{
108 | name: "rdev",
109 | t: ArgTypeUnsignedInt,
110 | raw: uintptr(stat.Rdev),
111 | annotation: annotation.DeviceToString(stat.Rdev),
112 | replace: true,
113 | })
114 |
115 | return &obj
116 | }
117 |
118 | func permModeToString(mode uint32) string {
119 |
120 | flags := map[uint32]string{
121 | unix.S_IFBLK: "S_IFBLK",
122 | unix.S_IFCHR: "S_IFCHR",
123 | unix.S_IFIFO: "S_IFIFO",
124 | unix.S_IFLNK: "S_IFLNK",
125 | unix.S_IFREG: "S_IFREG",
126 | unix.S_IFDIR: "S_IFDIR",
127 | unix.S_IFSOCK: "S_IFSOCK",
128 | unix.S_ISUID: "S_ISUID",
129 | unix.S_ISGID: "S_ISGID",
130 | unix.S_ISVTX: "S_ISVTX",
131 | }
132 |
133 | var joins []string
134 | for flag, name := range flags {
135 | if mode&syscall.S_IFMT == flag {
136 | joins = append(joins, name)
137 | }
138 | }
139 |
140 | perm := fmt.Sprintf("%04o", int(mode)&0777)
141 |
142 | joins = append(joins, perm)
143 |
144 | return strings.Join(joins, "|")
145 | }
146 |
--------------------------------------------------------------------------------
/tracer/types_statfs.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeStatfs, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Statfs_t{}))
14 | if err != nil {
15 | return err
16 | }
17 |
18 | var stat unix.Statfs_t
19 | if err := decodeStruct(rawVal, &stat); err != nil {
20 | return err
21 | }
22 |
23 | arg.obj, err = convertStatfs(&stat, pid)
24 | if err != nil {
25 | return err
26 | }
27 | arg.t = ArgTypeObject
28 | } else {
29 | arg.annotation = "NULL"
30 | arg.replace = true
31 | }
32 | return nil
33 | })
34 | }
35 |
36 | func convertStatfs(stat *unix.Statfs_t, _ int) (*Object, error) {
37 | return &Object{
38 | Name: "statfs",
39 | Properties: []Arg{
40 | {
41 | name: "type",
42 | t: ArgTypeUnsignedLong,
43 | raw: uintptr(stat.Type),
44 | },
45 | {
46 | name: "bsize",
47 | t: ArgTypeUnsignedLong,
48 | raw: uintptr(stat.Bsize),
49 | },
50 |
51 | {
52 | name: "blocks",
53 | t: ArgTypeUnsignedLong,
54 | raw: uintptr(stat.Blocks),
55 | },
56 | {
57 | name: "bfree",
58 | t: ArgTypeUnsignedLong,
59 | raw: uintptr(stat.Bfree),
60 | },
61 | {
62 | name: "bavail",
63 | t: ArgTypeUnsignedLong,
64 | raw: uintptr(stat.Bavail),
65 | },
66 | {
67 | name: "files",
68 | t: ArgTypeUnsignedLong,
69 | raw: uintptr(stat.Files),
70 | },
71 | {
72 | name: "ffree",
73 | t: ArgTypeUnsignedLong,
74 | raw: uintptr(stat.Ffree),
75 | },
76 | {
77 | name: "namelen",
78 | t: ArgTypeUnsignedLong,
79 | raw: uintptr(stat.Namelen),
80 | },
81 | {
82 | name: "frsize",
83 | t: ArgTypeUnsignedLong,
84 | raw: uintptr(stat.Frsize),
85 | },
86 | {
87 | name: "flags",
88 | t: ArgTypeUnsignedLong,
89 | raw: uintptr(stat.Flags),
90 | },
91 | },
92 | }, nil
93 | }
94 |
--------------------------------------------------------------------------------
/tracer/types_statx.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeStatX, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 | if raw > 0 {
12 | // read the raw C struct from the process memory
13 | rawStat, err := readSize(pid, raw, unsafe.Sizeof(unix.Statx_t{}))
14 | if err != nil {
15 | return err
16 | }
17 |
18 | var stat unix.Statx_t
19 | if err := decodeStruct(rawStat, &stat); err != nil {
20 | return err
21 | }
22 |
23 | arg.obj = convertStatx(&stat)
24 | arg.t = ArgTypeObject
25 | } else {
26 | arg.annotation = "NULL"
27 | arg.replace = true
28 | }
29 | return nil
30 | })
31 | }
32 |
33 | func convertStatx(stat *unix.Statx_t) *Object {
34 | obj := Object{
35 | Name: "statx",
36 | }
37 |
38 | obj.Properties = append(obj.Properties, Arg{
39 | name: "mask",
40 | t: ArgTypeUnsignedInt,
41 | raw: uintptr(stat.Mask),
42 | })
43 |
44 | obj.Properties = append(obj.Properties, Arg{
45 | name: "blksize",
46 | t: ArgTypeUnsignedInt,
47 | raw: uintptr(stat.Blksize),
48 | })
49 |
50 | obj.Properties = append(obj.Properties, Arg{
51 | name: "attributes",
52 | t: ArgTypeUnsignedInt,
53 | raw: uintptr(stat.Attributes),
54 | })
55 |
56 | obj.Properties = append(obj.Properties, Arg{
57 | name: "nlink",
58 | t: ArgTypeUnsignedInt,
59 | raw: uintptr(stat.Nlink),
60 | })
61 |
62 | obj.Properties = append(obj.Properties, Arg{
63 | name: "uid",
64 | t: ArgTypeUnsignedInt,
65 | raw: uintptr(stat.Uid),
66 | })
67 |
68 | obj.Properties = append(obj.Properties, Arg{
69 | name: "gid",
70 | t: ArgTypeUnsignedInt,
71 | raw: uintptr(stat.Gid),
72 | })
73 |
74 | obj.Properties = append(obj.Properties, Arg{
75 | name: "mode",
76 | t: ArgTypeUnsignedInt,
77 | raw: uintptr(stat.Mode),
78 | annotation: permModeToString(uint32(stat.Mode)),
79 | replace: true,
80 | })
81 |
82 | obj.Properties = append(obj.Properties, Arg{
83 | name: "ino",
84 | t: ArgTypeUnsignedInt,
85 | raw: uintptr(stat.Ino),
86 | })
87 |
88 | obj.Properties = append(obj.Properties, Arg{
89 | name: "size",
90 | t: ArgTypeInt,
91 | raw: uintptr(stat.Size),
92 | })
93 |
94 | obj.Properties = append(obj.Properties, Arg{
95 | name: "blocks",
96 | t: ArgTypeInt,
97 | raw: uintptr(stat.Blocks),
98 | })
99 |
100 | obj.Properties = append(obj.Properties, Arg{
101 | name: "attributes_mask",
102 | t: ArgTypeUnsignedInt,
103 | raw: uintptr(stat.Attributes_mask),
104 | })
105 |
106 | // -
107 |
108 | obj.Properties = append(obj.Properties, Arg{
109 | name: "atime",
110 | t: ArgTypeObject,
111 | obj: convertStatXTimestamp(stat.Atime),
112 | })
113 | obj.Properties = append(obj.Properties, Arg{
114 | name: "btime",
115 | t: ArgTypeObject,
116 | obj: convertStatXTimestamp(stat.Btime),
117 | })
118 |
119 | obj.Properties = append(obj.Properties, Arg{
120 | name: "ctime",
121 | t: ArgTypeObject,
122 | obj: convertStatXTimestamp(stat.Ctime),
123 | })
124 |
125 | obj.Properties = append(obj.Properties, Arg{
126 | name: "mtime",
127 | t: ArgTypeObject,
128 | obj: convertStatXTimestamp(stat.Mtime),
129 | })
130 |
131 | obj.Properties = append(obj.Properties, Arg{
132 | name: "rdev_major",
133 | t: ArgTypeUnsignedInt,
134 | raw: uintptr(stat.Rdev_major),
135 | })
136 |
137 | obj.Properties = append(obj.Properties, Arg{
138 | name: "rdev_minor",
139 | t: ArgTypeUnsignedInt,
140 | raw: uintptr(stat.Rdev_minor),
141 | })
142 | obj.Properties = append(obj.Properties, Arg{
143 | name: "dev_major",
144 | t: ArgTypeUnsignedInt,
145 | raw: uintptr(stat.Dev_major),
146 | })
147 | obj.Properties = append(obj.Properties, Arg{
148 | name: "dev_minor",
149 | t: ArgTypeUnsignedInt,
150 | raw: uintptr(stat.Dev_minor),
151 | })
152 | obj.Properties = append(obj.Properties, Arg{
153 | name: "mnt_id",
154 | t: ArgTypeUnsignedInt,
155 | raw: uintptr(stat.Mnt_id),
156 | })
157 |
158 | return &obj
159 | }
160 |
161 | func convertStatXTimestamp(t unix.StatxTimestamp) *Object {
162 | return &Object{
163 | Name: "statx_timestamp",
164 | Properties: []Arg{
165 | {
166 | name: "sec",
167 | t: ArgTypeUnsignedInt,
168 | raw: uintptr(t.Sec),
169 | },
170 | {
171 | name: "nsec",
172 | t: ArgTypeUnsignedInt,
173 | raw: uintptr(t.Nsec),
174 | },
175 | },
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/tracer/types_string.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "syscall"
6 | "unsafe"
7 | )
8 |
9 | /*
10 | NOTE: an array of strings in C (at least a char *argv[]) is an array of pointers to strings, terminated by a NULL pointer.
11 | */
12 |
13 | func init() {
14 | registerTypeHandler(argTypeStringArray, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
15 |
16 | var items []Arg
17 | var offset uintptr
18 | size := unsafe.Sizeof(uintptr(0))
19 |
20 | for {
21 | mem, err := readSize(pid, raw+offset, size)
22 | if err != nil {
23 | return err
24 | }
25 | address := uintptr(decodeUint(mem))
26 | if address == 0 {
27 | break
28 | }
29 | str, err := readString(pid, address)
30 | if err != nil {
31 | return err
32 | }
33 | items = append(items, Arg{
34 | t: ArgTypeData,
35 | raw: address,
36 | data: []byte(str),
37 | })
38 | offset += size
39 | }
40 | arg.t = ArgTypeArray
41 | arg.array = items
42 | return nil
43 | })
44 | registerTypeHandler(argTypeString, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
45 | str, err := readString(pid, raw)
46 | if err != nil {
47 | return err
48 | }
49 | arg.data = []byte(str)
50 | arg.t = ArgTypeData
51 | return nil
52 | })
53 | }
54 |
55 | func readString(pid int, addr uintptr) (string, error) {
56 | var output string
57 | if addr == 0 {
58 | return output, nil
59 | }
60 | data := make([]byte, 1)
61 | for {
62 | if _, err := syscall.PtracePeekData(pid, addr, data); err != nil {
63 | return "", fmt.Errorf("read of 0x%x failed: %w", addr, err)
64 | }
65 | if data[0] == 0 {
66 | break
67 | }
68 | output += string(data)
69 | addr++
70 | }
71 | return output, nil
72 | }
73 |
--------------------------------------------------------------------------------
/tracer/types_sysinfo.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeSysinfo, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Sysinfo_t{}))
14 | if err != nil {
15 | return err
16 | }
17 |
18 | var sysinfo unix.Sysinfo_t
19 | if err := decodeStruct(rawVal, &sysinfo); err != nil {
20 | return err
21 | }
22 |
23 | arg.obj, err = convertSysinfo(&sysinfo, pid)
24 | if err != nil {
25 | return err
26 | }
27 | arg.t = ArgTypeObject
28 | } else {
29 | arg.annotation = "NULL"
30 | arg.replace = true
31 | }
32 | return nil
33 | })
34 | }
35 |
36 | func convertLoadsToArray(loads [3]uint64) []Arg {
37 | var loadsArray []Arg
38 | for _, load := range loads {
39 | loadsArray = append(loadsArray, Arg{
40 | name: "load",
41 | t: ArgTypeUnsignedLong,
42 | raw: uintptr(load),
43 | })
44 | }
45 | return loadsArray
46 | }
47 |
48 | func convertSysinfo(sysinfo *unix.Sysinfo_t, _ int) (*Object, error) {
49 | return &Object{
50 | Name: "sysinfo",
51 | Properties: []Arg{
52 | {
53 | name: "uptime",
54 | t: ArgTypeUnsignedLong,
55 | raw: uintptr(sysinfo.Uptime),
56 | },
57 | {
58 | name: "loads",
59 | t: ArgTypeArray,
60 | array: convertLoadsToArray(sysinfo.Loads),
61 | },
62 | {
63 | name: "totalram",
64 | t: ArgTypeUnsignedLong,
65 | raw: uintptr(sysinfo.Totalram),
66 | },
67 | {
68 | name: "freeram",
69 | t: ArgTypeUnsignedLong,
70 | raw: uintptr(sysinfo.Freeram),
71 | },
72 | {
73 | name: "sharedram",
74 | t: ArgTypeUnsignedLong,
75 | raw: uintptr(sysinfo.Sharedram),
76 | },
77 | {
78 | name: "bufferram",
79 | t: ArgTypeUnsignedLong,
80 | raw: uintptr(sysinfo.Bufferram),
81 | },
82 | {
83 | name: "totalswap",
84 | t: ArgTypeUnsignedLong,
85 | raw: uintptr(sysinfo.Totalswap),
86 | },
87 | {
88 | name: "freeswap",
89 | t: ArgTypeUnsignedLong,
90 | raw: uintptr(sysinfo.Freeswap),
91 | },
92 | {
93 | name: "procs",
94 | t: ArgTypeUnsignedInt,
95 | raw: uintptr(sysinfo.Procs),
96 | },
97 | {
98 | name: "totalhigh",
99 | t: ArgTypeUnsignedLong,
100 | raw: uintptr(sysinfo.Totalhigh),
101 | },
102 | {
103 | name: "freehigh",
104 | t: ArgTypeUnsignedLong,
105 | raw: uintptr(sysinfo.Freehigh),
106 | },
107 | {
108 | name: "mem_unit",
109 | t: ArgTypeUnsignedInt,
110 | raw: uintptr(sysinfo.Unit),
111 | },
112 | },
113 | }, nil
114 | }
115 |
--------------------------------------------------------------------------------
/tracer/types_timespec.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "unsafe"
7 |
8 | "golang.org/x/sys/unix"
9 | )
10 |
11 | func init() {
12 | registerTypeHandler(argTypeTimespec, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
13 |
14 | if raw > 0 {
15 | // read the raw C struct from the process memory
16 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Timespec{}))
17 | if err != nil {
18 | return err
19 | }
20 |
21 | var timeVal unix.Timespec
22 | if err := decodeStruct(rawTimeVal, &timeVal); err != nil {
23 | return err
24 | }
25 |
26 | arg.obj = convertTimeSpec(&timeVal)
27 | arg.t = ArgTypeObject
28 | } else {
29 | arg.annotation = "NULL"
30 | arg.replace = true
31 | }
32 | return nil
33 | })
34 | registerTypeHandler(argTypeTimespecArray, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
35 |
36 | if raw > 0 {
37 |
38 | var size int
39 |
40 | switch metadata.LenSource {
41 | case LenSourceFixed:
42 | size = metadata.FixedCount
43 | default:
44 | return fmt.Errorf("unsupported count_from: %d", metadata.LenSource)
45 | }
46 |
47 | rawVals, err := readSize(pid, raw, uintptr(size)*unsafe.Sizeof(unix.Timespec{}))
48 | if err != nil {
49 | return err
50 | }
51 |
52 | vals := make([]unix.Timespec, size)
53 | if err := decodeAnonymous(reflect.ValueOf(&vals).Elem(), rawVals); err != nil {
54 | return err
55 | }
56 |
57 | for _, val := range vals {
58 | arg.array = append(arg.array, Arg{
59 | t: ArgTypeObject,
60 | obj: convertTimeSpec(&val),
61 | })
62 | }
63 | }
64 |
65 | arg.t = ArgTypeArray
66 | return nil
67 | })
68 | }
69 |
70 | func convertTimeSpec(u *unix.Timespec) *Object {
71 | if u == nil {
72 | return nil
73 | }
74 | return &Object{
75 | Name: "timespec",
76 | Properties: []Arg{
77 | {
78 | name: "sec",
79 | t: ArgTypeUnsignedLong,
80 | raw: uintptr(u.Sec),
81 | },
82 | {
83 | name: "usec",
84 | t: ArgTypeUnsignedLong,
85 | raw: uintptr(u.Nsec),
86 | },
87 | },
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tracer/types_timeval.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "unsafe"
7 |
8 | "golang.org/x/sys/unix"
9 | )
10 |
11 | func init() {
12 | registerTypeHandler(argTypeTimeval, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
13 |
14 | if raw > 0 {
15 | // read the raw C struct from the process memory
16 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Timeval{}))
17 | if err != nil {
18 | return err
19 | }
20 |
21 | var timeVal unix.Timeval
22 | if err := decodeStruct(rawTimeVal, &timeVal); err != nil {
23 | return err
24 | }
25 |
26 | arg.obj = convertTimeVal(&timeVal)
27 | arg.t = ArgTypeObject
28 | } else {
29 | arg.annotation = "NULL"
30 | arg.replace = true
31 | }
32 | return nil
33 | })
34 | registerTypeHandler(argTypeTimevalArray, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
35 |
36 | if raw > 0 {
37 |
38 | var size int
39 |
40 | switch metadata.LenSource {
41 | case LenSourceFixed:
42 | size = metadata.FixedCount
43 | default:
44 | return fmt.Errorf("unsupported count_from: %d", metadata.LenSource)
45 | }
46 |
47 | rawVals, err := readSize(pid, raw, uintptr(size)*unsafe.Sizeof(unix.Timeval{}))
48 | if err != nil {
49 | return err
50 | }
51 |
52 | vals := make([]unix.Timeval, size)
53 | if err := decodeAnonymous(reflect.ValueOf(&vals).Elem(), rawVals); err != nil {
54 | return err
55 | }
56 |
57 | for _, val := range vals {
58 | arg.array = append(arg.array, Arg{
59 | t: ArgTypeObject,
60 | obj: convertTimeVal(&val),
61 | })
62 | }
63 | }
64 |
65 | arg.t = ArgTypeArray
66 | return nil
67 | })
68 | }
69 |
70 | func convertTimeVal(u *unix.Timeval) *Object {
71 | return &Object{
72 | Name: "timeval",
73 | Properties: []Arg{
74 | {
75 | name: "sec",
76 | t: ArgTypeUnsignedLong,
77 | raw: uintptr(u.Sec),
78 | },
79 | {
80 | name: "usec",
81 | t: ArgTypeUnsignedLong,
82 | raw: uintptr(u.Usec),
83 | },
84 | },
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/tracer/types_timex.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeTimex, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | // read the raw C struct from the process memory
14 | mem, err := readSize(pid, raw, unsafe.Sizeof(unix.Timex{}))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | var tx unix.Timex
20 | if err := decodeStruct(mem, &tx); err != nil {
21 | return err
22 | }
23 |
24 | arg.obj = convertTimex(&tx)
25 | arg.t = ArgTypeObject
26 | } else {
27 | arg.annotation = "NULL"
28 | arg.replace = true
29 | }
30 | return nil
31 | })
32 | }
33 |
34 | func convertTimex(tx *unix.Timex) *Object {
35 | return &Object{
36 | Name: "timezone",
37 | Properties: []Arg{
38 | {
39 | name: "modes",
40 | t: ArgTypeInt,
41 | raw: uintptr(tx.Modes),
42 | },
43 | {
44 | name: "offset",
45 | t: ArgTypeInt,
46 | raw: uintptr(tx.Offset),
47 | },
48 | {
49 | name: "freq",
50 | t: ArgTypeInt,
51 | raw: uintptr(tx.Freq),
52 | },
53 | {
54 | name: "maxerror",
55 | t: ArgTypeInt,
56 | raw: uintptr(tx.Maxerror),
57 | },
58 | {
59 | name: "esterror",
60 | t: ArgTypeInt,
61 | raw: uintptr(tx.Esterror),
62 | },
63 | {
64 | name: "status",
65 | t: ArgTypeInt,
66 | raw: uintptr(tx.Status),
67 | },
68 | {
69 | name: "constant",
70 | t: ArgTypeInt,
71 | raw: uintptr(tx.Constant),
72 | },
73 | {
74 | name: "precision",
75 | t: ArgTypeInt,
76 | raw: uintptr(tx.Precision),
77 | },
78 | {
79 | name: "tolerance",
80 | t: ArgTypeInt,
81 | raw: uintptr(tx.Tolerance),
82 | },
83 | {
84 | name: "time",
85 | t: ArgTypeObject,
86 | obj: convertTimeVal(&tx.Time),
87 | },
88 | {
89 | name: "tick",
90 | t: ArgTypeInt,
91 | raw: uintptr(tx.Tick),
92 | },
93 | {
94 | name: "ppsfreq",
95 | t: ArgTypeInt,
96 | raw: uintptr(tx.Ppsfreq),
97 | },
98 | {
99 | name: "jitter",
100 | t: ArgTypeInt,
101 | raw: uintptr(tx.Jitter),
102 | },
103 | {
104 | name: "shift",
105 | t: ArgTypeInt,
106 | raw: uintptr(tx.Shift),
107 | },
108 | {
109 | name: "stabil",
110 | t: ArgTypeInt,
111 | raw: uintptr(tx.Stabil),
112 | },
113 | {
114 | name: "jitcnt",
115 | t: ArgTypeInt,
116 | raw: uintptr(tx.Jitcnt),
117 | },
118 | {
119 | name: "calcnt",
120 | t: ArgTypeInt,
121 | raw: uintptr(tx.Calcnt),
122 | },
123 | {
124 | name: "errcnt",
125 | t: ArgTypeInt,
126 | raw: uintptr(tx.Errcnt),
127 | },
128 | {
129 | name: "stbcnt",
130 | t: ArgTypeInt,
131 | raw: uintptr(tx.Stbcnt),
132 | },
133 | {
134 | name: "tai",
135 | t: ArgTypeInt,
136 | raw: uintptr(tx.Tai),
137 | },
138 | },
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/tracer/types_timezone.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type timezone struct {
8 | Minuteswest int32
9 | Dsttime int32
10 | }
11 |
12 | func init() {
13 | registerTypeHandler(argTypeTimezone, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
14 |
15 | if raw > 0 {
16 | // read the raw C struct from the process memory
17 | mem, err := readSize(pid, raw, unsafe.Sizeof(timezone{}))
18 | if err != nil {
19 | return err
20 | }
21 |
22 | var tz timezone
23 | if err := decodeStruct(mem, &tz); err != nil {
24 | return err
25 | }
26 |
27 | arg.obj = convertTimezone(&tz)
28 | arg.t = ArgTypeObject
29 | } else {
30 | arg.annotation = "NULL"
31 | arg.replace = true
32 | }
33 | return nil
34 | })
35 | }
36 |
37 | func convertTimezone(tz *timezone) *Object {
38 | return &Object{
39 | Name: "timezone",
40 | Properties: []Arg{
41 | {
42 | name: "minuteswest",
43 | t: ArgTypeInt,
44 | raw: uintptr(tz.Minuteswest),
45 | },
46 | {
47 | name: "dsttime",
48 | t: ArgTypeInt,
49 | raw: uintptr(tz.Dsttime),
50 | },
51 | },
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tracer/types_tms.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeTms, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Tms{}))
14 | if err != nil {
15 | return err
16 | }
17 |
18 | var times unix.Tms
19 | if err := decodeStruct(rawVal, ×); err != nil {
20 | return err
21 | }
22 |
23 | arg.obj = convertTimes(×)
24 | arg.t = ArgTypeObject
25 | } else {
26 | arg.annotation = "NULL"
27 | arg.replace = true
28 | }
29 | return nil
30 | })
31 | }
32 |
33 | func convertTimes(times *unix.Tms) *Object {
34 | return &Object{
35 | Name: "times",
36 | Properties: []Arg{
37 | {
38 | name: "utime",
39 | t: ArgTypeUnsignedLong,
40 | raw: uintptr(times.Utime),
41 | },
42 | {
43 | name: "stime",
44 | t: ArgTypeUnsignedLong,
45 | raw: uintptr(times.Stime),
46 | },
47 | {
48 | name: "cutime",
49 | t: ArgTypeUnsignedLong,
50 | raw: uintptr(times.Cutime),
51 | },
52 | {
53 | name: "cstime",
54 | t: ArgTypeUnsignedLong,
55 | raw: uintptr(times.Cstime),
56 | },
57 | },
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tracer/types_uname.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "syscall"
5 | "unsafe"
6 | )
7 |
8 | func init() {
9 | registerTypeHandler(argTypeUname, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
10 | if raw > 0 {
11 | data, err := readSize(pid, raw, unsafe.Sizeof(syscall.Utsname{}))
12 | if err != nil {
13 | return err
14 | }
15 |
16 | var uname syscall.Utsname
17 | if err := decodeStruct(data, &uname); err != nil {
18 | return err
19 | }
20 |
21 | arg.obj = convertUname(&uname)
22 | arg.t = ArgTypeObject
23 | } else {
24 | arg.t = ArgTypeAddress
25 | arg.annotation = "NULL"
26 | arg.replace = true
27 | }
28 | return nil
29 | })
30 | }
31 |
32 | func getUtsField(f [65]int8) []byte {
33 | var str []byte
34 | for i := 0; i < len(f); i++ {
35 | if f[i] == 0 {
36 | break
37 | }
38 | str = append(str, byte(f[i]))
39 | }
40 | return str
41 | }
42 |
43 | func convertUname(uname *syscall.Utsname) *Object {
44 | return &Object{
45 | Name: "uname",
46 | Properties: []Arg{
47 | {
48 | name: "sysname",
49 | t: ArgTypeData,
50 | data: getUtsField(uname.Sysname),
51 | },
52 | {
53 | name: "nodename",
54 | t: ArgTypeData,
55 | data: getUtsField(uname.Nodename),
56 | },
57 | {
58 | name: "release",
59 | t: ArgTypeData,
60 | data: getUtsField(uname.Release),
61 | },
62 | {
63 | name: "version",
64 | t: ArgTypeData,
65 | data: getUtsField(uname.Version),
66 | },
67 | {
68 | name: "machine",
69 | t: ArgTypeData,
70 | data: getUtsField(uname.Machine),
71 | },
72 | {
73 | name: "domainname",
74 | t: ArgTypeData,
75 | data: getUtsField(uname.Domainname),
76 | },
77 | },
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/tracer/types_userdesc.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type ldt struct {
8 | EntryNumber uint32
9 | BaseAddr uint32
10 | Limit uint32
11 | }
12 |
13 | func init() {
14 | registerTypeHandler(argTypeUserDesc, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
15 |
16 | if raw > 0 {
17 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(ldt{}))
18 | if err != nil {
19 | return err
20 | }
21 |
22 | var table ldt
23 | if err := decodeStruct(rawVal, &table); err != nil {
24 | return err
25 | }
26 |
27 | arg.obj = convertLDT(table)
28 | if err != nil {
29 | return err
30 | }
31 | arg.t = ArgTypeObject
32 | } else {
33 | arg.annotation = "NULL"
34 | arg.replace = true
35 | }
36 | return nil
37 | })
38 | }
39 |
40 | func convertLDT(table ldt) *Object {
41 | return &Object{
42 | Name: "ldt",
43 | Properties: []Arg{
44 | {
45 | name: "entry_number",
46 | t: ArgTypeUnsignedLong,
47 | raw: uintptr(table.EntryNumber),
48 | },
49 | {
50 | name: "base_addr",
51 | t: ArgTypeUnsignedLong,
52 | raw: uintptr(table.BaseAddr),
53 | },
54 | {
55 | name: "limit",
56 | t: ArgTypeUnsignedLong,
57 | raw: uintptr(table.Limit),
58 | },
59 | },
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tracer/types_ustat.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeUstat, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | rawVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Ustat_t{}))
14 | if err != nil {
15 | return err
16 | }
17 |
18 | var stat unix.Ustat_t
19 | if err := decodeStruct(rawVal, &stat); err != nil {
20 | return err
21 | }
22 |
23 | arg.obj, err = convertUstat(&stat, pid)
24 | if err != nil {
25 | return err
26 | }
27 | arg.t = ArgTypeObject
28 | } else {
29 | arg.annotation = "NULL"
30 | arg.replace = true
31 | }
32 | return nil
33 | })
34 | }
35 |
36 | func convertUstat(stat *unix.Ustat_t, _ int) (*Object, error) {
37 |
38 | var fname []byte
39 | for _, b := range stat.Fname {
40 | if b == 0 {
41 | break
42 | }
43 | fname = append(fname, byte(b))
44 | }
45 |
46 | var fpack []byte
47 | for _, b := range stat.Fpack {
48 | if b == 0 {
49 | break
50 | }
51 | fpack = append(fpack, byte(b))
52 | }
53 |
54 | return &Object{
55 | Name: "ustat",
56 | Properties: []Arg{
57 | {
58 | name: "tfree",
59 | t: ArgTypeUnsignedLong,
60 | raw: uintptr(stat.Tfree),
61 | },
62 | {
63 | name: "tinode",
64 | t: ArgTypeUnsignedLong,
65 | raw: uintptr(stat.Tinode),
66 | },
67 | {
68 | name: "fname",
69 | t: ArgTypeData,
70 | data: fname,
71 | },
72 | {
73 | name: "fpack",
74 | t: ArgTypeData,
75 | data: fpack,
76 | },
77 | },
78 | }, nil
79 | }
80 |
--------------------------------------------------------------------------------
/tracer/types_utimbuf.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeUtimbuf, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | // read the raw C struct from the process memory
14 | rawTimeVal, err := readSize(pid, raw, unsafe.Sizeof(unix.Utimbuf{}))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | var timeVal unix.Utimbuf
20 | if err := decodeStruct(rawTimeVal, &timeVal); err != nil {
21 | return err
22 | }
23 |
24 | arg.obj = convertTimeBuf(&timeVal)
25 | arg.t = ArgTypeObject
26 | } else {
27 | arg.annotation = "NULL"
28 | arg.replace = true
29 | }
30 | return nil
31 | })
32 | }
33 |
34 | func convertTimeBuf(u *unix.Utimbuf) *Object {
35 | return &Object{
36 | Name: "timbuf",
37 | Properties: []Arg{
38 | {
39 | name: "actime",
40 | t: ArgTypeUnsignedLong,
41 | raw: uintptr(u.Actime),
42 | },
43 | {
44 | name: "modtime",
45 | t: ArgTypeUnsignedLong,
46 | raw: uintptr(u.Modtime),
47 | },
48 | },
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tracer/types_waitstatus.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "unsafe"
5 |
6 | "golang.org/x/sys/unix"
7 | )
8 |
9 | func init() {
10 | registerTypeHandler(argTypeWaitStatus, func(arg *Arg, metadata ArgMetadata, raw, next, prev, ret uintptr, pid int) error {
11 |
12 | if raw > 0 {
13 | // read the raw C struct from the process memory
14 | bytes, err := readSize(pid, raw, unsafe.Sizeof(unix.WaitStatus(0)))
15 | if err != nil {
16 | return err
17 | }
18 |
19 | status := uintptr(decodeUint(bytes))
20 |
21 | arg.raw = status
22 | arg.t = ArgTypeUnsignedInt
23 | } else {
24 | arg.t = ArgTypeAddress
25 | arg.annotation = "NULL"
26 | arg.replace = true
27 | }
28 | return nil
29 | })
30 | }
31 |
--------------------------------------------------------------------------------
/ux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liamg/grace/a28e5c24b4666a6c6674c152a5435fbde628f6b2/ux.png
--------------------------------------------------------------------------------