Skip to content

Commit

Permalink
fix: improve LC_THREAD output formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
blacktop committed May 30, 2024
1 parent a49eaa3 commit 261acfb
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 60 deletions.
37 changes: 32 additions & 5 deletions cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,14 +577,40 @@ func (t *Thread) Write(buf *bytes.Buffer, o binary.ByteOrder) error {
return nil
}
func (t *Thread) String() string {
regPadding := 9
padding := strings.Repeat(" ", 7)
var out []string
for _, thread := range t.Threads {
if thread.Flavor == types.ARM_THREAD_STATE64 {
regs := make([]uint64, thread.Count/2)
switch thread.Flavor {
case types.X86_THREAD_STATE32:
var regs Regs386
binary.Read(bytes.NewReader(thread.Data), t.bo, &regs)
return fmt.Sprintf("Threads: %d, ARM64 EntryPoint: %#016x", len(t.Threads), regs[len(regs)-2])
out = append(out, fmt.Sprintf("%s%s EntryPoint: %#08x\n%s", padding, thread.Flavor, regs.IP, regs.String(regPadding)))
case types.X86_THREAD_STATE64:
var regs RegsAMD64
binary.Read(bytes.NewReader(thread.Data), t.bo, &regs)
out = append(out, fmt.Sprintf("%s%s EntryPoint: %#016x\n%s", padding, thread.Flavor, regs.IP, regs.String(regPadding)))
case types.ARM_THREAD_STATE32:
var regs RegsARM
binary.Read(bytes.NewReader(thread.Data), t.bo, &regs)
out = append(out, fmt.Sprintf("%s%s EntryPoint: %#08x\n%s", padding, thread.Flavor, regs.PC, regs.String(regPadding)))
case types.ARM_THREAD_STATE64:
var regs RegsARM64
binary.Read(bytes.NewReader(thread.Data), t.bo, &regs)
out = append(out, fmt.Sprintf("%s%s EntryPoint: %#016x\n%s", padding, thread.Flavor, regs.PC, regs.String(regPadding)))
case types.ARM_EXCEPTION_STATE:
var regs ArmExceptionState
binary.Read(bytes.NewReader(thread.Data), t.bo, &regs)
out = append(out, fmt.Sprintf("%s%s:\n%s", padding, thread.Flavor, regs.String(regPadding)))
case types.ARM_EXCEPTION_STATE64:
var regs ArmExceptionState64
binary.Read(bytes.NewReader(thread.Data), t.bo, &regs)
out = append(out, fmt.Sprintf("%s%s:\n%s", padding, thread.Flavor, regs.String(regPadding)))
default:
out = append(out, fmt.Sprintf("%s%s", padding, thread.Flavor))
}
}
return fmt.Sprintf("Threads: %d", len(t.Threads))
return fmt.Sprintf("Threads: %d\n%s", len(t.Threads), strings.Join(out, "\n"))
}
func (t *Thread) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Expand Down Expand Up @@ -1984,6 +2010,7 @@ type VersionMinWatchOS struct {
type Note struct {
LoadBytes
types.NoteCmd
Data []byte
}

func (n *Note) LoadSize() uint32 {
Expand All @@ -1996,7 +2023,7 @@ func (n *Note) Write(buf *bytes.Buffer, o binary.ByteOrder) error {
return nil
}
func (n *Note) String() string {
return fmt.Sprintf("DataOwner=%s, offset=0x%08x-0x%08x size=%5d", string(n.DataOwner[:]), n.Offset, n.Offset+n.Size, n.Size)
return fmt.Sprintf("DataOwner: \"%s\", offset=0x%08x-0x%08x size=%5d", string(n.DataOwner[:]), n.Offset, n.Offset+n.Size, n.Size)
}
func (n *Note) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Expand Down
5 changes: 5 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ func NewFile(r io.ReaderAt, config ...FileConfig) (*File, error) {
l.LoadBytes = cmddat
l.LoadCmd = cmd
l.Len = siz
l.bo = bo
for {
var thread types.ThreadState
err := binary.Read(b, bo, &thread.Flavor)
Expand Down Expand Up @@ -1160,6 +1161,10 @@ func NewFile(r io.ReaderAt, config ...FileConfig) (*File, error) {
l.DataOwner = n.DataOwner
l.Offset = n.Offset
l.Size = n.Size
l.Data = make([]byte, l.Size)
if _, err := f.cr.ReadAt(l.Data, int64(l.Offset)); err != nil {
return nil, fmt.Errorf("failed to read Note data at offset=%#x; %v", int64(l.Offset), err)
}
f.Loads = append(f.Loads, l)
case types.LC_BUILD_VERSION:
var build types.BuildVersionCmd
Expand Down
92 changes: 46 additions & 46 deletions file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,57 +454,57 @@ func TestNewFile(t *testing.T) {

fmt.Println(got.FileTOC.String())

cs := got.CodeSignature()
if cs != nil {
if cs := got.CodeSignature(); cs != nil {
fmt.Println(cs.Requirements[0].Detail)
}
if len(cs.LaunchConstraintsSelf) > 0 {
os.WriteFile("lc_self.bin", cs.LaunchConstraintsSelf, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LaunchConstraintsSelf)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
}
fmt.Println(string(dat))
}
if len(cs.LaunchConstraintsParent) > 0 {
os.WriteFile("lc_parent.bin", cs.LaunchConstraintsParent, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LaunchConstraintsParent)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
}
fmt.Println(string(dat))
}
if len(cs.LaunchConstraintsResponsible) > 0 {
os.WriteFile("lc_responsible.bin", cs.LaunchConstraintsResponsible, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LaunchConstraintsResponsible)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)

if len(cs.LaunchConstraintsSelf) > 0 {
os.WriteFile("lc_self.bin", cs.LaunchConstraintsSelf, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LaunchConstraintsSelf)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
}
fmt.Println(string(dat))
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
if len(cs.LaunchConstraintsParent) > 0 {
os.WriteFile("lc_parent.bin", cs.LaunchConstraintsParent, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LaunchConstraintsParent)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
}
fmt.Println(string(dat))
}
fmt.Println(string(dat))
}
if len(cs.LibraryConstraints) > 0 {
os.WriteFile("lib_constraints.bin", cs.LibraryConstraints, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LibraryConstraints)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
if len(cs.LaunchConstraintsResponsible) > 0 {
os.WriteFile("lc_responsible.bin", cs.LaunchConstraintsResponsible, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LaunchConstraintsResponsible)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
}
fmt.Println(string(dat))
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
if len(cs.LibraryConstraints) > 0 {
os.WriteFile("lib_constraints.bin", cs.LibraryConstraints, 0644)
lc, err := cstypes.ParseLaunchContraints(cs.LibraryConstraints)
if err != nil {
t.Fatalf("ParseLaunchContraints() error = %v", err)
}
dat, err := json.MarshalIndent(lc, "", " ")
if err != nil {
t.Fatalf("json.MarshalIndent() error = %v", err)
}
fmt.Println(string(dat))
}
fmt.Println(string(dat))
}

d, err := got.DWARF()
Expand Down
113 changes: 106 additions & 7 deletions macho.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

package macho

import (
"fmt"
"strings"
)

// Regs386 is the Mach-O 386 register structure.
type Regs386 struct {
AX uint32
Expand All @@ -32,6 +37,18 @@ type Regs386 struct {
GS uint32
}

func (r Regs386) String(padding int) string {
return fmt.Sprintf(
"%seax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n"+
"%sedi 0x%08x esi 0x%08x ebp 0x%08x esp 0x%08x\n"+
"%sss 0x%08x eflags 0x%08x eip 0x%08x cs 0x%08x\n"+
"%sds 0x%08x es 0x%08x fs 0x%08x gs 0x%08x\n",
strings.Repeat(" ", padding), r.AX, r.BX, r.CX, r.DX,
strings.Repeat(" ", padding), r.DI, r.SI, r.BP, r.SP,
strings.Repeat(" ", padding), r.SS, r.FLAGS, r.IP, r.CS,
strings.Repeat(" ", padding), r.DS, r.ES, r.FS, r.GS)
}

// RegsAMD64 is the Mach-O AMD64 register structure.
type RegsAMD64 struct {
AX uint64
Expand All @@ -57,6 +74,26 @@ type RegsAMD64 struct {
GS uint64
}

func (r RegsAMD64) String(padding int) string {
return fmt.Sprintf(
"%s rax %#016x rbx %#016x rcx %#016x\n"+
"%s rdx %#016x rdi %#016x rsi %#016x\n"+
"%s rbp %#016x rsp %#016x r8 %#016x\n"+
"%s r9 %#016x r10 %#016x r11 %#016x\n"+
"%s r12 %#016x r13 %#016x r14 %#016x\n"+
"%s r15 %#016x rip %#016x\n"+
"%srflags %#016x cs %#016x fs %#016x\n"+
"%s gs %#016x\n",
strings.Repeat(" ", padding), r.AX, r.BX, r.CX,
strings.Repeat(" ", padding), r.DX, r.DI, r.SI,
strings.Repeat(" ", padding), r.BP, r.SP, r.R8,
strings.Repeat(" ", padding), r.R9, r.R10, r.R11,
strings.Repeat(" ", padding), r.R12, r.R13, r.R14,
strings.Repeat(" ", padding), r.R15, r.IP,
strings.Repeat(" ", padding), r.FLAGS, r.CS, r.FS,
strings.Repeat(" ", padding), r.GS)
}

// RegsARM is the Mach-O ARM register structure.
type RegsARM struct {
R0 uint32
Expand All @@ -78,9 +115,23 @@ type RegsARM struct {
CPSR uint32
}

func (r RegsARM) String(padding int) string {
return fmt.Sprintf(
"%s r0 %#08x r1 %#08x r2 %#08x r3 %#08x\n"+
"%s r4 %#08x r5 %#08x r6 %#08x r7 %#08x\n"+
"%s r8 %#08x r9 %#08x r10 %#08x r11 %#08x\n"+
"%s r12 %#08x sp %#08x lr %#08x pc %#08x\n"+
"%scpsr %#08x",
strings.Repeat(" ", padding), r.R0, r.R1, r.R2, r.R3,
strings.Repeat(" ", padding), r.R4, r.R5, r.R6, r.R7,
strings.Repeat(" ", padding), r.R8, r.R9, r.R10, r.R11,
strings.Repeat(" ", padding), r.R12, r.SP, r.LR, r.PC,
strings.Repeat(" ", padding), r.CPSR)
}

// RegsARM64 is the Mach-O ARM 64 register structure.
type RegsARM64 struct {
X0 uint64
X0 uint64 /* General purpose registers x0-x28 */
X1 uint64
X2 uint64
X3 uint64
Expand Down Expand Up @@ -109,10 +160,58 @@ type RegsARM64 struct {
X26 uint64
X27 uint64
X28 uint64
FP uint64
LR uint64
SP uint64
PC uint64
CPSR uint32
PAD uint32
FP uint64 /* Frame pointer x29 */
LR uint64 /* Link register x30 */
SP uint64 /* Stack pointer x31 */
PC uint64 /* Program counter */
CPSR uint32 /* Current program status register */
PAD uint32 /* Same size for 32-bit or 64-bit clients */
}

func (r RegsARM64) String(padding int) string {
return fmt.Sprintf(
"%s x0: %#016x x1: %#016x x2: %#016x x3: %#016x\n"+
"%s x4: %#016x x5: %#016x x6: %#016x x7: %#016x\n"+
"%s x8: %#016x x9: %#016x x10: %#016x x11: %#016x\n"+
"%sx12: %#016x x13: %#016x x14: %#016x x15: %#016x\n"+
"%sx16: %#016x x17: %#016x x18: %#016x x19: %#016x\n"+
"%sx20: %#016x x21: %#016x x22: %#016x x23: %#016x\n"+
"%sx24: %#016x x25: %#016x x26: %#016x x27: %#016x\n"+
"%sx28: %#016x fp: %#016x lr: %#016x\n"+
"%s sp: %#016x pc: %#016x cpsr: %#08x\n"+
"%sesr: %#08x",
strings.Repeat(" ", padding), r.X0, r.X1, r.X2, r.X3,
strings.Repeat(" ", padding), r.X4, r.X5, r.X6, r.X7,
strings.Repeat(" ", padding), r.X8, r.X9, r.X10, r.X11,
strings.Repeat(" ", padding), r.X12, r.X13, r.X14, r.X15,
strings.Repeat(" ", padding), r.X16, r.X17, r.X18, r.X19,
strings.Repeat(" ", padding), r.X20, r.X21, r.X22, r.X23,
strings.Repeat(" ", padding), r.X24, r.X25, r.X26, r.X27,
strings.Repeat(" ", padding), r.X28, r.FP, r.LR,
strings.Repeat(" ", padding), r.SP, r.PC, r.CPSR,
strings.Repeat(" ", padding), r.PAD)
}

type ArmExceptionState struct {
FAR uint32 /* Virtual Fault Address */
ESR uint32 /* Exception syndrome */
Exception uint32 /* number of arm exception taken */
}

func (r ArmExceptionState) String(padding int) string {
return fmt.Sprintf(
"%sfar: %#08x esr: %#08x exception: %#08x",
strings.Repeat(" ", padding), r.FAR, r.ESR, r.Exception)
}

type ArmExceptionState64 struct {
FAR uint64 /* Virtual Fault Address */
ESR uint32 /* Exception syndrome */
Exception uint32 /* number of arm exception taken */
}

func (r ArmExceptionState64) String(padding int) string {
return fmt.Sprintf(
"%sfar: %#016x esr: %#08x exception: %#08x",
strings.Repeat(" ", padding), r.FAR, r.ESR, r.Exception)
}
2 changes: 1 addition & 1 deletion types/commands.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package types

//go:generate stringer -type=LoadCmd -output commands_string.go
//go:generate stringer -type=LoadCmd,ThreadFlavor -output commands_string.go

import (
"encoding/json"
Expand Down
Loading

0 comments on commit 261acfb

Please sign in to comment.