diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-10-09 23:51:15 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-10-09 23:51:15 +0900 |
| commit | d41b9d2d9ceb60ceb601af991441e70929801c42 (patch) | |
| tree | ec5b9e35e650f6bec9fd9e603301f0d87b7ede76 /ldd | |
| parent | 22dfa73efe8a7a15b8867404e6504041a7139406 (diff) | |
ldd: separate Parse from Exec and trim space
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'ldd')
| -rw-r--r-- | ldd/error.go | 26 | ||||
| -rw-r--r-- | ldd/exec.go | 18 | ||||
| -rw-r--r-- | ldd/ldd.go | 28 | ||||
| -rw-r--r-- | ldd/ldd_test.go | 95 |
4 files changed, 139 insertions, 28 deletions
diff --git a/ldd/error.go b/ldd/error.go index 51aef948..39b63ef9 100644 --- a/ldd/error.go +++ b/ldd/error.go @@ -1,11 +1,27 @@ package ldd -import "fmt" +import ( + "errors" + "fmt" +) -type EntryUnexpectedSegmentsError struct { - Entry string +var ( + ErrUnexpectedSeparator = errors.New("unexpected separator") + ErrPathNotAbsolute = errors.New("path not absolute") + ErrBadLocationFormat = errors.New("bad location format") + ErrUnexpectedNewline = errors.New("unexpected newline") +) + +type EntryUnexpectedSegmentsError string + +func (e EntryUnexpectedSegmentsError) Is(err error) bool { + var eq EntryUnexpectedSegmentsError + if !errors.As(err, &eq) { + return false + } + return e == eq } -func (e *EntryUnexpectedSegmentsError) Error() string { - return fmt.Sprintf("unexpected segments in entry %q", e.Entry) +func (e EntryUnexpectedSegmentsError) Error() string { + return fmt.Sprintf("unexpected segments in entry %q", string(e)) } diff --git a/ldd/exec.go b/ldd/exec.go new file mode 100644 index 00000000..d6a2af58 --- /dev/null +++ b/ldd/exec.go @@ -0,0 +1,18 @@ +package ldd + +import ( + "fmt" + "os" + "os/exec" + "strings" +) + +func Exec(p string) ([]*Entry, error) { + t := exec.Command("ldd", p) + t.Stdout, t.Stderr = new(strings.Builder), os.Stderr + if err := t.Run(); err != nil { + return nil, err + } + + return Parse(t.Stdout.(fmt.Stringer)) +} @@ -1,49 +1,31 @@ package ldd import ( - "errors" "fmt" "math" - "os" - "os/exec" "path" "strconv" "strings" ) -var ( - ErrUnexpectedSeparator = errors.New("unexpected separator") - ErrPathNotAbsolute = errors.New("path not absolute") - ErrBadLocationFormat = errors.New("bad location format") -) - type Entry struct { Name string `json:"name,omitempty"` Path string `json:"path,omitempty"` Location uint64 `json:"location"` } -func Exec(p string) ([]*Entry, error) { - t := exec.Command("ldd", p) - t.Stdout = new(strings.Builder) - t.Stderr = os.Stderr - - if err := t.Run(); err != nil { - return nil, err - } - - out := t.Stdout.(fmt.Stringer).String() - payload := strings.Split(out, "\n") - +func Parse(stdout fmt.Stringer) ([]*Entry, error) { + payload := strings.Split(strings.TrimSpace(stdout.String()), "\n") result := make([]*Entry, len(payload)) for i, ent := range payload { if len(ent) == 0 { - continue + return nil, ErrUnexpectedNewline } segment := strings.SplitN(ent, " ", 5) + // location index var iL int switch len(segment) { @@ -63,7 +45,7 @@ func Exec(p string) ([]*Entry, error) { Path: segment[2], } default: - return nil, &EntryUnexpectedSegmentsError{ent} + return nil, EntryUnexpectedSegmentsError(ent) } if loc, err := parseLocation(segment[iL]); err != nil { diff --git a/ldd/ldd_test.go b/ldd/ldd_test.go new file mode 100644 index 00000000..ec8a5d0c --- /dev/null +++ b/ldd/ldd_test.go @@ -0,0 +1,95 @@ +package ldd_test + +import ( + "errors" + "reflect" + "strings" + "testing" + + "git.ophivana.moe/cat/fortify/ldd" +) + +func TestParseError(t *testing.T) { + testCases := []struct { + name, out string + wantErr error + }{ + {"unexpected newline", ` +/lib/ld-musl-x86_64.so.1 (0x7ff71c0a4000) + +libzstd.so.1 => /usr/lib/libzstd.so.1 (0x7ff71bfd2000) +`, ldd.ErrUnexpectedNewline}, + {"unexpected separator", ` +libzstd.so.1 = /usr/lib/libzstd.so.1 (0x7ff71bfd2000) +`, ldd.ErrUnexpectedSeparator}, + {"path not absolute", ` +libzstd.so.1 => usr/lib/libzstd.so.1 (0x7ff71bfd2000) +`, ldd.ErrPathNotAbsolute}, + {"unexpected segments", ` +meow libzstd.so.1 => /usr/lib/libzstd.so.1 (0x7ff71bfd2000) +`, ldd.EntryUnexpectedSegmentsError("meow libzstd.so.1 => /usr/lib/libzstd.so.1 (0x7ff71bfd2000)")}, + {"bad location format", ` +libzstd.so.1 => /usr/lib/libzstd.so.1 7ff71bfd2000 +`, ldd.ErrBadLocationFormat}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + stdout := new(strings.Builder) + stdout.WriteString(tc.out) + + if _, err := ldd.Parse(stdout); !errors.Is(err, tc.wantErr) { + t.Errorf("Parse() error = %v, wantErr %v", err, tc.wantErr) + } + }) + } +} + +func TestParse(t *testing.T) { + testCases := []struct { + file, out string + want []*ldd.Entry + }{ + {"musl /bin/kmod", ` +/lib/ld-musl-x86_64.so.1 (0x7ff71c0a4000) +libzstd.so.1 => /usr/lib/libzstd.so.1 (0x7ff71bfd2000) +liblzma.so.5 => /usr/lib/liblzma.so.5 (0x7ff71bf9a000) +libz.so.1 => /lib/libz.so.1 (0x7ff71bf80000) +libcrypto.so.3 => /lib/libcrypto.so.3 (0x7ff71ba00000) +libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7ff71c0a4000)`, + []*ldd.Entry{ + {"/lib/ld-musl-x86_64.so.1", "", 0x7ff71c0a4000}, + {"libzstd.so.1", "/usr/lib/libzstd.so.1", 0x7ff71bfd2000}, + {"liblzma.so.5", "/usr/lib/liblzma.so.5", 0x7ff71bf9a000}, + {"libz.so.1", "/lib/libz.so.1", 0x7ff71bf80000}, + {"libcrypto.so.3", "/lib/libcrypto.so.3", 0x7ff71ba00000}, + {"libc.musl-x86_64.so.1", "/lib/ld-musl-x86_64.so.1", 0x7ff71c0a4000}, + }}, + {"glibc /nix/store/rc3n2r3nffpib2gqpxlkjx36frw6n34z-kmod-31/bin/kmod", ` +linux-vdso.so.1 (0x00007ffed65be000) +libzstd.so.1 => /nix/store/80pxmvb9q43kh9rkjagc4h41vf6dh1y6-zstd-1.5.6/lib/libzstd.so.1 (0x00007f3199cd1000) +liblzma.so.5 => /nix/store/g78jna1i5qhh8gqs4mr64648f0szqgw4-xz-5.4.7/lib/liblzma.so.5 (0x00007f3199ca2000) +libc.so.6 => /nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6 (0x00007f3199ab5000) +libpthread.so.0 => /nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libpthread.so.0 (0x00007f3199ab0000) +/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/ld-linux-x86-64.so.2 => /nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib64/ld-linux-x86-64.so.2 (0x00007f3199da5000)`, + []*ldd.Entry{ + {"linux-vdso.so.1", "", 0x00007ffed65be000}, + {"libzstd.so.1", "/nix/store/80pxmvb9q43kh9rkjagc4h41vf6dh1y6-zstd-1.5.6/lib/libzstd.so.1", 0x00007f3199cd1000}, + {"liblzma.so.5", "/nix/store/g78jna1i5qhh8gqs4mr64648f0szqgw4-xz-5.4.7/lib/liblzma.so.5", 0x00007f3199ca2000}, + {"libc.so.6", "/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6", 0x00007f3199ab5000}, + {"libpthread.so.0", "/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libpthread.so.0", 0x00007f3199ab0000}, + {"/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/ld-linux-x86-64.so.2", "/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib64/ld-linux-x86-64.so.2", 0x00007f3199da5000}, + }}, + } + for _, tc := range testCases { + t.Run(tc.file, func(t *testing.T) { + stdout := new(strings.Builder) + stdout.WriteString(tc.out) + + if got, err := ldd.Parse(stdout); err != nil { + t.Errorf("Parse() error = %v", err) + } else if !reflect.DeepEqual(got, tc.want) { + t.Errorf("Parse() got = %#v, want %#v", got, tc.want) + } + }) + } +} |
