fortify/ldd/ldd.go

85 lines
1.7 KiB
Go

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")
result := make([]*Entry, len(payload))
for i, ent := range payload {
if len(ent) == 0 {
continue
}
segment := strings.SplitN(ent, " ", 5)
var iL int
switch len(segment) {
case 2: // /lib/ld-musl-x86_64.so.1 (0x7f04d14ef000)
iL = 1
result[i] = &Entry{Name: segment[0]}
case 4: // libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f04d14ef000)
iL = 3
if segment[1] != "=>" {
return nil, ErrUnexpectedSeparator
}
if !path.IsAbs(segment[2]) {
return nil, ErrPathNotAbsolute
}
result[i] = &Entry{
Name: segment[0],
Path: segment[2],
}
default:
return nil, &EntryUnexpectedSegmentsError{ent}
}
if loc, err := parseLocation(segment[iL]); err != nil {
return nil, err
} else {
result[i].Location = loc
}
}
return result, nil
}
func parseLocation(s string) (uint64, error) {
if len(s) < 4 || s[len(s)-1] != ')' || s[:3] != "(0x" {
return math.MaxUint64, ErrBadLocationFormat
}
return strconv.ParseUint(s[3:len(s)-1], 16, 64)
}