-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
158 changed files
with
14,378 additions
and
942 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.idea | ||
/grace | ||
/dist | ||
/linux | ||
/headers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
FROM ubuntu:22.04 | ||
|
||
RUN apt-get update -y && apt-get install -y git build-essential golang ca-certificates rsync | ||
RUN git clone --depth 1 https://github.com/torvalds/linux.git /linux | ||
COPY . /src | ||
WORKDIR /src | ||
RUN make test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,124 @@ | ||
# grace | ||
|
||
_grace_ is a tool for monitoring and modifying syscalls for a given process. | ||
_grace_ is a tool for monitoring and annotating syscalls for a given process. | ||
|
||
It's essentially a lightweight [strace](https://en.wikipedia.org/wiki/Strace), in Go, with colours and pretty output. | ||
|
||
![](screenshot.png) | ||
<p align="center"> | ||
<img src="demo.gif"/> | ||
</p> | ||
|
||
// TODO: new screenshot | ||
<p align="center"> | ||
<img src="compare.png"/> | ||
</p> | ||
|
||
It's possible to tweak and filter the output to make it quite readable, for example (using `-vnmx`): | ||
|
||
<p align="center"> | ||
<img src="ux.png"/> | ||
</p> | ||
|
||
You can also review a summary of encountered syscalls (and sort by various columns): | ||
|
||
<p align="center"> | ||
<img src="summary.png"/> | ||
</p> | ||
|
||
## Features/Usage Examples | ||
|
||
### grace vs. strace | ||
|
||
_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. | ||
|
||
Over time grace is meant to become a simpler, more readable alternative to strace (_strace for dummies?_), albeit with reduced functionality/advanced features. | ||
|
||
| Feature | grace | strace | | ||
|---------------------------------------------------------------------------------------|-------|--------| | ||
| Start a program and print all syscalls it makes | ✅ | ✅ | | ||
| Attach to an existing process by `pid` and print all syscalls it makes | ✅ | ✅ | | ||
| Filter syscalls by name, e.g. only show occurrences of the `open` syscall | ❌ | ✅ | | ||
| Filter syscalls using a given path, e.g. only show syscalls that access `/etc/passwd` | ❌ | ✅ | | ||
| Dump I/O for certain file descriptors | ❌ | ✅ | | ||
| Count occurrences and duration of all syscalls and present in a useful format | ❌ | ✅ | | ||
| Print relative/absolute timestamps | ❌ | ✅ | | ||
| Filter syscalls by name, e.g. only show occurrences of the `open` syscall | ✅ | ✅ | | ||
| Filter syscalls using a given path, e.g. only show syscalls that access `/etc/passwd` | ✅ | ✅ | | ||
| Dump I/O for certain file descriptors | ✅ | ✅ | | ||
| Count occurrences and duration of all syscalls and present in a useful format | ✅ | ✅ | | ||
| Print relative/absolute timestamps | ✅ | ✅ | | ||
| Tamper with syscalls | ❌ | ✅ | | ||
| Print extra information about file descriptors, such as path, socket addresses etc. | some | ✅ | | ||
| Print extra information about file descriptors, such as path, socket addresses etc. | ✅ | ✅ | | ||
| Print stack traces | ❌ | ✅ | | ||
| Filter by return value | ❌ | ✅ | | ||
| Decode SELinux context info | ❌ | ✅ | | ||
| Filter by return value | ✅ | ✅ | | ||
| Pretty colours to make output easier to read | ✅ | ❌ | | ||
| Lots of output options and customisation vectors | ✅ | ✅ | | ||
| Output to file | ✅ | ✅ | | ||
| Filter by failing/non-failing syscalls | ✅ | ✅ | | ||
|
||
_NOTE: Please feel free to add important strace features to this table, I'm working with a limited knowledge of strace._ | ||
|
||
### Usage Examples | ||
|
||
``` | ||
// TODO | ||
``` | ||
|
||
## Installation | ||
|
||
Grab a statically compiled binary from the [latest release](https://github.com/liamg/grace/releases/latest). | ||
|
||
## Build Dependencies | ||
|
||
If you want to build _grace_ yourself instead of using the precompiled binaries, you'll need a recent version of Go (1.19+), `musl-gcc` installed (you can install `musl-tools` on Ubuntu or `musl` on Arch), and kernel headers (install `linux-headers-$(uname -r)` on Ubuntu or `linux-headers` on Arch). _grace_ mainly just pulls constants from the kernel headers, so it's not a huge dependency. You should then have some success running `make build`. Note that many architectures are not yet supported (see below.) | ||
|
||
## Supported Platforms/Architecture | ||
|
||
Currently only Linux/amd64 is supported. Other architectures coming soon. | ||
|
||
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. | ||
|
||
### Usage Examples | ||
|
||
#### Trace a program | ||
|
||
```bash | ||
grace -- cat /dev/null # replace 'cat /dev/null' with your program | ||
``` | ||
|
||
#### Trace an existing process | ||
|
||
```bash | ||
grace -p 123 # replace 123 with your pid | ||
|
||
# e.g. you could use pgrep to find the pid of a process | ||
grace -p `pgrep ping` | ||
``` | ||
|
||
#### Trace a program and filter by syscall name | ||
|
||
```bash | ||
grace -f "name=openat" -- cat /dev/null | ||
|
||
# you can also look for multiple syscalls | ||
grace -f "name=openat&name=close" -- cat /dev/null | ||
``` | ||
|
||
#### Trace a program and filter by syscall name and path | ||
|
||
```bash | ||
grace -f "name=openat&path=/dev/null" -- cat /dev/null | ||
``` | ||
|
||
#### Trace a program and wire up stdin/out/err with the terminal | ||
|
||
```bash | ||
grace -F -- cat | ||
``` | ||
|
||
#### Trace a program with maximum readability options | ||
|
||
```bash | ||
grace -vnmx -- cat /dev/null | ||
``` | ||
|
||
#### Trace only failing syscalls | ||
|
||
```bash | ||
grace -Z -- cat /dev/null | ||
``` | ||
|
||
#### Show a summary of syscalls with durations, counts and errors | ||
|
||
```bash | ||
grace -S -- cat /dev/null | ||
``` | ||
|
||
## Build Dependencies | ||
|
||
If you want to build _grace_ yourself instead of using the precompiled binaries, you'll need a recent version of Go (1.19+), `musl-gcc` installed (you can install `musl-tools` on Ubuntu or `musl` on Arch), and kernel headers (install `linux-headers-$(uname -r)` on Ubuntu or `linux-headers` and `kernel-headers-musl` on Arch). _grace_ mainly just pulls constants from the kernel headers, so it's not a huge dependency. You should then have some success running `make build`. Note that many architectures are not yet supported (see below.) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package filter | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/liamg/grace/tracer" | ||
) | ||
|
||
type Filter struct { | ||
allowNames []string | ||
allowPaths []string | ||
allowReturns []uint64 | ||
failingOnly bool | ||
passingOnly bool | ||
} | ||
|
||
func Parse(input string) (*Filter, error) { | ||
filter := NewFilter() | ||
parts := strings.Split(input, "&") | ||
for _, part := range parts { | ||
if part == "" { | ||
continue | ||
} | ||
bits := strings.Split(part, "=") | ||
key := bits[0] | ||
value := bits[len(bits)-1] | ||
switch key { | ||
case "syscall", "name", "trace": | ||
filter.allowNames = append(filter.allowNames, strings.Split(value, ",")...) | ||
case "path": | ||
filter.allowPaths = append(filter.allowPaths, strings.Split(value, ",")...) | ||
case "ret", "retval", "return": | ||
ret, err := parseUint64(value) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse return value filter: %w", err) | ||
} | ||
filter.allowReturns = append(filter.allowReturns, ret) | ||
default: | ||
return nil, fmt.Errorf("invalid filter key: %s", key) | ||
} | ||
} | ||
return filter, nil | ||
} | ||
|
||
func parseUint64(input string) (uint64, error) { | ||
if strings.HasPrefix(input, "0x") { | ||
return strconv.ParseUint(input[2:], 16, 64) | ||
} | ||
return strconv.ParseUint(input, 10, 64) | ||
} | ||
|
||
func NewFilter() *Filter { | ||
return &Filter{} | ||
} | ||
|
||
func (f *Filter) Match(call *tracer.Syscall, exit bool) bool { | ||
|
||
if len(f.allowNames) > 0 { | ||
var match bool | ||
for _, name := range f.allowNames { | ||
if name == call.Name() { | ||
match = true | ||
break | ||
} | ||
} | ||
if !match { | ||
return false | ||
} | ||
} | ||
|
||
if len(f.allowPaths) > 0 { | ||
var match bool | ||
for _, path := range f.allowPaths { | ||
for _, realPath := range call.Paths() { | ||
if realPath == path { | ||
match = true | ||
break | ||
} | ||
} | ||
} | ||
if !match { | ||
return false | ||
} | ||
} | ||
|
||
if len(f.allowReturns) > 0 { | ||
if !exit { | ||
return false | ||
} | ||
var match bool | ||
for _, ret := range f.allowReturns { | ||
if uintptr(ret) == call.Return().Raw() { | ||
match = true | ||
break | ||
} | ||
} | ||
if !match { | ||
return false | ||
} | ||
} | ||
|
||
if (f.passingOnly || f.failingOnly) && !exit { | ||
return false | ||
} | ||
|
||
if f.failingOnly && call.Return().Int() >= 0 { | ||
return false | ||
} | ||
|
||
if f.passingOnly && call.Return().Int() < 0 { | ||
return false | ||
} | ||
|
||
// TODO check more filters | ||
|
||
return true | ||
} | ||
|
||
func (f *Filter) SetFailingOnly(failing bool) { | ||
f.failingOnly = failing | ||
} | ||
|
||
func (f *Filter) SetPassingOnly(passing bool) { | ||
f.passingOnly = passing | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.