Skip to content

Commit

Permalink
One long weekend.
Browse files Browse the repository at this point in the history
  • Loading branch information
liamg committed Oct 30, 2022
1 parent e5a254e commit f0ca668
Show file tree
Hide file tree
Showing 39 changed files with 2,896 additions and 1 deletion.
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: release

on:
push:
tags:
- v*

jobs:
build:
name: releasing
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- uses: actions/setup-go@v3
with:
go-version: "1.19"
- uses: goreleaser/goreleaser-action@v3
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 changes: 22 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: tests
on:
push:
branches:
- main
pull_request:
jobs:
test:
name: tests
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest ]

steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.19'
cache: true
- name: Run tests
run: sudo apt install -y musl-tools && make test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
/grace
/dist
33 changes: 33 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
before:
hooks:
- sudo apt install -y musl-tools

builds:
- id: grace
main: .
binary: grace
ldflags:
- "-linkmode external -s -w -extldflags '-fno-PIC -static'"
env:
- CGO_ENABLED=1
- CC=musl-gcc
goos:
- linux
goarch:
- "amd64"
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"

archives:
- format: binary
name_template: "{{ .Binary}}-{{ .Os }}-{{ .Arch }}"

release:
prerelease: auto
github:
owner: liamg
name: grace
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Contributing

## Useful Links

- [List of syscalls with descriptions](https://linuxhint.com/list_of_linux_syscalls/)
- [Syscall table](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md)
- [Another Syscall table](https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/)
24 changes: 24 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
default: build

.PHONY: test
test:
CC=musl-gcc CGO_ENABLED=1 go test ./...

.PHONY: build
build:
CGO_ENABLED=1 CC=musl-gcc go build --ldflags '-linkmode external -extldflags "-static"'

.PHONY: demo
demo: build
./grace -- cat /dev/null
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,51 @@
# grace
It's strace, with colours.

_grace_ is a tool for monitoring and modifying 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)

// TODO: new screenshot

## 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.

| 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 |||
| Tamper with syscalls |||
| Print extra information about file descriptors, such as path, socket addresses etc. | some ||
| Print stack traces |||
| Filter by return value |||
| Decode SELinux context info |||
| Pretty colours to make output easier to read |||

### 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.
17 changes: 17 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module github.com/liamg/grace

go 1.19

require (
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
golang.org/x/sys v0.1.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
27 changes: 27 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
102 changes: 102 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package main

import (
"fmt"
"os"

"github.com/liamg/grace/printer"

"github.com/liamg/grace/tracer"
"github.com/spf13/cobra"
)

var (
flagDisableColours = false
flagMaxStringLen = 32
flagHexDumpLongStrings = true
flagMaxHexDumpLen = 4096
flagPID = 0
flagSuppressOutput = false
flagMaxObjectProperties = 2
flagVerbose = false
flagExtraNewLine = false
flagMultiline = false
)

var rootCmd = &cobra.Command{
Use: "grace [flags] [command [args]]",
Example: `grace -- cat /etc/passwd`,
Short: `grace is a CLI tool for monitoring and modifying syscalls for a given process.
It's essentially strace, in Go, with colours and pretty output.`,
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceErrors = true
cmd.SilenceUsage = true

if len(args) == 0 && flagPID == 0 {
return cmd.Help()
}

var t *tracer.Tracer
var err error
if flagPID > 0 {
t = tracer.New(flagPID)
} else {
t, err = tracer.FromCommand(flagSuppressOutput, args[0], args[1:]...)
if err != nil {
return err
}
}

p := printer.New(cmd.OutOrStdout())

p.SetUseColours(!flagDisableColours)
p.SetMaxStringLen(flagMaxStringLen)
p.SetMaxHexDumpLen(flagMaxHexDumpLen)
p.SetExtraNewLine(flagExtraNewLine)
p.SetMultiLine(flagMultiline)

if flagVerbose {
p.SetHexDumpLongStrings(true)
p.SetMaxObjectProperties(0)
} else {
p.SetHexDumpLongStrings(flagHexDumpLongStrings)
p.SetMaxObjectProperties(flagMaxObjectProperties)
}

t.SetSyscallEnterHandler(p.PrintSyscallEnter)
t.SetSyscallExitHandler(p.PrintSyscallExit)
t.SetSignalHandler(p.PrintSignal)
t.SetProcessExitHandler(p.PrintProcessExit)

// TODO: set signal handler!

defer func() { _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "") }()

return t.Start()
},
}

func init() {
rootCmd.Flags().BoolVarP(&flagDisableColours, "no-colours", "C", flagDisableColours, "disable colours in output")
rootCmd.Flags().IntVarP(&flagMaxStringLen, "max-string-len", "s", flagMaxStringLen, "maximum length of strings to print")
rootCmd.Flags().BoolVarP(&flagHexDumpLongStrings, "hex-dump-long-strings", "x", flagHexDumpLongStrings, "hex dump strings longer than --max-string-len")
rootCmd.Flags().IntVarP(&flagMaxHexDumpLen, "max-hex-dump-len", "l", flagMaxHexDumpLen, "maximum length of hex dumps")
rootCmd.Flags().IntVarP(&flagPID, "pid", "p", flagPID, "trace an existing process by PID")
rootCmd.Flags().BoolVarP(&flagSuppressOutput, "suppress-output", "S", flagSuppressOutput, "suppress output of command")
rootCmd.Flags().IntVarP(&flagMaxObjectProperties, "max-object-properties", "o", flagMaxObjectProperties, "maximum number of properties to print for objects (recursive) - this also applies to array elements")
rootCmd.Flags().BoolVarP(&flagVerbose, "verbose", "v", flagVerbose, "enable verbose output (overrides other verbosity settings)")
rootCmd.Flags().BoolVarP(&flagExtraNewLine, "extra-newline", "n", flagExtraNewLine, "print an extra newline after each syscall to aid readability")
rootCmd.Flags().BoolVarP(&flagMultiline, "multiline", "m", flagMultiline, "print each syscall argument on a separate line to aid readability")
}

func main() {

if err := rootCmd.Execute(); err != nil {
if err.Error() == "no such process" {
os.Exit(0)
}
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Binary file added pipe
Binary file not shown.
Loading

0 comments on commit f0ca668

Please sign in to comment.