Skip to content

Commit ac260aa

Browse files
authored
Merge pull request #60 from ilmanzo/improve_wrap_unwrap
Allow wrap/unwrap many binaries at once - give useful error on finding the .so library
2 parents 6631485 + a52d3b7 commit ac260aa

File tree

3 files changed

+95
-11
lines changed

3 files changed

+95
-11
lines changed

cmd/funkoverage.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"strings"
99
)
1010

11-
const versionString = "0.4.2"
11+
const versionString = "0.4.3"
1212

1313
// --- CLI ---
1414

@@ -34,20 +34,20 @@ func main() {
3434
case "wrap", "-w":
3535
wrapCmd.Parse(os.Args[2:])
3636
if wrapCmd.NArg() < 1 {
37-
fmt.Println("wrap: missing binary path")
37+
fmt.Println("wrap: missing binary path(s)")
3838
os.Exit(1)
3939
}
40-
if err := wrap(wrapCmd.Arg(0)); err != nil {
40+
if err := wrapMany(wrapCmd.Args()); err != nil {
4141
fmt.Println("wrap error:", err)
4242
os.Exit(1)
4343
}
4444
case "unwrap", "-u":
4545
unwrapCmd.Parse(os.Args[2:])
4646
if unwrapCmd.NArg() < 1 {
47-
fmt.Println("unwrap: missing binary path")
47+
fmt.Println("unwrap: missing binary path(s)")
4848
os.Exit(1)
4949
}
50-
if err := unwrap(unwrapCmd.Arg(0)); err != nil {
50+
if err := unwrapMany(unwrapCmd.Args()); err != nil {
5151
fmt.Println("unwrap error:", err)
5252
os.Exit(1)
5353
}

cmd/funkoverage_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,57 @@ func TestWrapUnwrapLogic(t *testing.T) {
173173
}
174174
}
175175

176+
func TestWrapManyAndUnwrapMany(t *testing.T) {
177+
tmp := t.TempDir()
178+
os.Setenv("PIN_ROOT", "/tmp/pin")
179+
os.Setenv("PIN_TOOL_SEARCH_DIR", tmp)
180+
os.Setenv("SAFE_BIN_DIR", tmp)
181+
os.Setenv("LOG_DIR", tmp)
182+
// Create dummy FuncTracer.so
183+
funcTracer := filepath.Join(tmp, "FuncTracer.so")
184+
if err := os.WriteFile(funcTracer, []byte("dummy"), 0644); err != nil {
185+
t.Fatal(err)
186+
}
187+
188+
// Create multiple fake ELF binaries
189+
bin1 := filepath.Join(tmp, "bin1")
190+
bin2 := filepath.Join(tmp, "bin2")
191+
bin3 := filepath.Join(tmp, "bin3")
192+
for _, bin := range []string{bin1, bin2, bin3} {
193+
if err := os.WriteFile(bin, []byte("\x7fELFfoobar"), 0755); err != nil {
194+
t.Fatalf("failed to create %s: %v", bin, err)
195+
}
196+
}
197+
198+
// Wrap all binaries
199+
if err := wrapMany([]string{bin1, bin2, bin3}); err != nil {
200+
t.Fatalf("wrapMany failed: %v", err)
201+
}
202+
for _, bin := range []string{bin1, bin2, bin3} {
203+
content, err := os.ReadFile(bin)
204+
if err != nil {
205+
t.Fatalf("failed to read wrapped binary %s: %v", bin, err)
206+
}
207+
if !strings.Contains(string(content), wrapperIDComment) {
208+
t.Errorf("binary %s was not wrapped", bin)
209+
}
210+
}
211+
212+
// Unwrap all binaries
213+
if err := unwrapMany([]string{bin1, bin2, bin3}); err != nil {
214+
t.Fatalf("unwrapMany failed: %v", err)
215+
}
216+
for _, bin := range []string{bin1, bin2, bin3} {
217+
_, err := os.ReadFile(bin)
218+
if err != nil {
219+
t.Fatalf("failed to read unwrapped binary %s: %v", bin, err)
220+
}
221+
if !isELF(bin) {
222+
t.Errorf("binary %s was not restored to ELF", bin)
223+
}
224+
}
225+
}
226+
176227
func TestGenerateHTMLReportBaseName(t *testing.T) {
177228
tmp := t.TempDir()
178229
data := &CoverageData{

cmd/wrapunwrap.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import (
1010
"time"
1111
)
1212

13-
const wrapperIDComment = "# Pin Wrapper generated by Go tool funkoverage"
13+
const (
14+
wrapperIDComment = "# Pin Wrapper generated by Go tool funkoverage"
15+
defaultPinToolSearchDir = "/usr/lib64/coverage-tools"
16+
defaultLogDir = "/var/coverage/data"
17+
defaultSafeBinDir = "/var/coverage/bin"
18+
)
1419

1520
// --- Wrapper Management ---
1621

@@ -73,15 +78,15 @@ func wrap(targetBinary string) error {
7378
}
7479
PIN_TOOL_SEARCH_DIR := os.Getenv("PIN_TOOL_SEARCH_DIR")
7580
if PIN_TOOL_SEARCH_DIR == "" {
76-
PIN_TOOL_SEARCH_DIR = "/usr/lib64/coverage-tools"
81+
PIN_TOOL_SEARCH_DIR = defaultPinToolSearchDir
7782
}
7883
LOG_DIR := os.Getenv("LOG_DIR")
7984
if LOG_DIR == "" {
80-
LOG_DIR = "/var/coverage/data"
85+
LOG_DIR = defaultLogDir
8186
}
8287
SAFE_BIN_DIR := os.Getenv("SAFE_BIN_DIR")
8388
if SAFE_BIN_DIR == "" {
84-
SAFE_BIN_DIR = "/var/coverage/bin"
89+
SAFE_BIN_DIR = defaultSafeBinDir
8590
}
8691
pinTool, err := findPinTool(PIN_TOOL_SEARCH_DIR)
8792
if err != nil {
@@ -110,7 +115,7 @@ func wrap(targetBinary string) error {
110115
if err != nil {
111116
return err
112117
}
113-
// change tmpdir permissions to allow execution from all users
118+
// change tmpdir permissions to allow execution from all users
114119
if err := os.Chmod(tmpDir, 0755); err != nil {
115120
return fmt.Errorf("could not set permissions on temp dir: %w", err)
116121
}
@@ -184,7 +189,35 @@ func findPinTool(searchDir string) (string, error) {
184189
return nil
185190
})
186191
if found == "" {
187-
return "", errors.New("FuncTracer.so not found")
192+
return "", errors.New("FuncTracer.so not found. Look for it in the $PIN_TOOL_SEARCH_DIR env variable or " + defaultPinToolSearchDir + " directory")
188193
}
189194
return found, nil
190195
}
196+
197+
func wrapMany(binaries []string) error {
198+
var failed []string
199+
for _, bin := range binaries {
200+
if err := wrap(bin); err != nil {
201+
fmt.Fprintf(os.Stderr, "wrap error for %s: %v\n", bin, err)
202+
failed = append(failed, bin)
203+
}
204+
}
205+
if len(failed) > 0 {
206+
return fmt.Errorf("failed to wrap: %v", failed)
207+
}
208+
return nil
209+
}
210+
211+
func unwrapMany(binaries []string) error {
212+
var failed []string
213+
for _, bin := range binaries {
214+
if err := unwrap(bin); err != nil {
215+
fmt.Fprintf(os.Stderr, "unwrap error for %s: %v\n", bin, err)
216+
failed = append(failed, bin)
217+
}
218+
}
219+
if len(failed) > 0 {
220+
return fmt.Errorf("failed to unwrap: %v", failed)
221+
}
222+
return nil
223+
}

0 commit comments

Comments
 (0)