Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions internal/driver/adb/adb.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package adb

import (
"errors"
"fmt"
"os/exec"
"strings"
Expand All @@ -11,6 +12,16 @@ import (
"memodroid/internal/driver"
)

// execErr enriches an exec error with the stderr output from the failed command.
func execErr(op string, err error) error {
var exitErr *exec.ExitError
if errors.As(err, &exitErr) && len(exitErr.Stderr) > 0 {
detail := strings.TrimSpace(string(exitErr.Stderr))
return fmt.Errorf("%s: %s", op, detail)
}
return fmt.Errorf("%s: %w", op, err)
}

// ADB implements driver.Driver using the adb CLI.
type ADB struct {
mu sync.RWMutex
Expand Down Expand Up @@ -43,7 +54,7 @@ func (a *ADB) SelectDevice(serial string) error {
func (a *ADB) ConnectWifi(addr string) error {
out, err := exec.Command("adb", "connect", addr).Output()
if err != nil {
return fmt.Errorf("adb connect %s: %w", addr, err)
return execErr(fmt.Sprintf("adb connect %s", addr), err)
}
result := strings.TrimSpace(string(out))
if strings.HasPrefix(result, "failed") || strings.HasPrefix(result, "error") {
Expand All @@ -60,7 +71,7 @@ func (a *ADB) ConnectWifi(addr string) error {
func (a *ADB) DisconnectWifi(addr string) error {
_, err := exec.Command("adb", "disconnect", addr).Output()
if err != nil {
return fmt.Errorf("adb disconnect %s: %w", addr, err)
return execErr(fmt.Sprintf("adb disconnect %s", addr), err)
}
a.mu.Lock()
if a.serial == addr {
Expand All @@ -74,7 +85,7 @@ func (a *ADB) DisconnectWifi(addr string) error {
func (a *ADB) ListDevices() ([]string, error) {
out, err := exec.Command("adb", "devices").Output()
if err != nil {
return nil, fmt.Errorf("adb devices: %w", err)
return nil, execErr("adb devices", err)
}
var serials []string
for _, line := range strings.Split(string(out), "\n") {
Expand All @@ -96,7 +107,7 @@ func (a *ADB) shell(args ...string) ([]byte, error) {
cmdArgs = append(cmdArgs, args...)
out, err := exec.Command("adb", cmdArgs...).Output()
if err != nil {
return nil, fmt.Errorf("adb shell %s: %w", strings.Join(args, " "), err)
return nil, execErr(fmt.Sprintf("adb shell %s", strings.Join(args, " ")), err)
}
return out, nil
}
Expand Down
5 changes: 2 additions & 3 deletions internal/driver/adb/mem.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (a *ADB) Peek(pid int, addr uintptr, size int) ([]byte, error) {
return nil, fmt.Errorf("peek decode 0x%x: %w", addr, err)
}
if len(decoded) != size {
return nil, fmt.Errorf("peek 0x%x: wanted %d bytes, got %d", addr, size, len(decoded))
return nil, fmt.Errorf("peek 0x%x: short read (wanted %d bytes, got %d — address may be at region boundary or unmapped)", addr, size, len(decoded))
}
return decoded, nil
}
Expand Down Expand Up @@ -87,8 +87,7 @@ func (a *ADB) ReadRegion(pid int, addr uintptr, size int) ([]byte, error) {
return nil, fmt.Errorf("read region decode 0x%x: %w", cur, err)
}
if len(decoded) == 0 {
// Region is not readable (e.g. guard page); treat as error.
return nil, fmt.Errorf("read region 0x%x: empty read", cur)
return nil, fmt.Errorf("read region 0x%x+%d: empty output (region may be inaccessible or guard page)", cur, rem)
}
out = append(out, decoded...)
if len(decoded) < rem {
Expand Down
2 changes: 1 addition & 1 deletion internal/driver/adb/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func (a *ADB) ListProcesses() ([]driver.ProcessInfo, error) {
out, err := a.shell("ps", "-A")
if err != nil {
return nil, err
return nil, fmt.Errorf("list processes: %w", err)
}
var procs []driver.ProcessInfo
for _, line := range strings.Split(string(out), "\n") {
Expand Down
Loading