Documentation
¶
Overview ¶
Package explorer contains format-neutral navigation and service logic shared by the TUI.
Index ¶
- Constants
- func DefaultExecAddr(f *binfile.File, strategy string) uint64
- func IsDyldSharedCacheLib(lib string) bool
- func ResolveLibPath(lib, binaryPath string, info *binfile.Info, exists FileExists) (string, bool)
- type CursorMode
- type DisasmService
- func (s *DisasmService) CanDecode() bool
- func (s *DisasmService) DecodeAt(addr uint64, before int) (binfile.Window, []disasm.Inst)
- func (s *DisasmService) DecodeRange(start, size, lead int) []disasm.Inst
- func (s *DisasmService) DecodeRangeFunc(start, size, lead int, fn func(disasm.Inst) bool)
- func (s *DisasmService) DecodeSpanAt(addr uint64, before int) Span
- func (s *DisasmService) DecodeSpanWindow(win binfile.Window) Span
- func (s *DisasmService) DecodeWindow(win binfile.Window) []disasm.Inst
- func (s *DisasmService) LeadBytes() int
- func (s *DisasmService) MaxBytes() int
- func (s *DisasmService) OverlapBytes() int
- func (s *DisasmService) PrefetchAround(addr uint64)
- func (s *DisasmService) ScanMatching(match func(text string) bool, limit int, done <-chan struct{}) []Match
- func (s *DisasmService) SearchBatchChunks() int
- func (s *DisasmService) SearchChunkBytes() int
- func (s *DisasmService) SearchWorkersFor(chunks int) int
- func (s *DisasmService) SetOptions(maxBytes, searchWorkers int)
- func (s *DisasmService) SpanFor(win binfile.Window, insts []disasm.Inst) Span
- type FileExists
- type Match
- type SearchCache
- func (c *SearchCache) Add(hits []SearchHit, forward bool)
- func (c *SearchCache) Boundary(forward bool) (uint64, bool)
- func (c *SearchCache) Complete(imgLen int) bool
- func (c *SearchCache) Coverage() (lo, hi int)
- func (c *SearchCache) EnsureQuery(query string) bool
- func (c *SearchCache) Exhausted(forward bool) bool
- func (c *SearchCache) Hits() []SearchHit
- func (c *SearchCache) Next(cur uint64, mode CursorMode, forward, inclusive bool) (SearchHit, bool)
- func (c *SearchCache) NoteCoverage(lo, hi int)
- func (c *SearchCache) Overflow() bool
- func (c *SearchCache) Query() string
- func (c *SearchCache) Reset(query string)
- func (c *SearchCache) SetExhausted(forward bool)
- type SearchHit
- type Span
Constants ¶
const CacheCap = 100
CacheCap bounds how many hits one query's cache retains.
Variables ¶
This section is empty.
Functions ¶
func DefaultExecAddr ¶
DefaultExecAddr resolves a guaranteed-executable address for the disasm view to land on, honouring the requested strategy and falling back down a sensible chain when the choice can't be resolved. Returns 0 only when the binary has no executable code at all.
Strategies: "entry" (the entry point), "main"/"start" (those symbols), "text" (the .text/__text section), "lowest" (lowest executable address).
func IsDyldSharedCacheLib ¶
IsDyldSharedCacheLib reports whether lib is normally served from Apple's dyld shared cache instead of as a standalone user-openable file.
func ResolveLibPath ¶
ResolveLibPath resolves a dynamic-library reference to an on-disk path. Mach-O @loader_path, @executable_path, and @rpath tokens are expanded using the binary path and loader-provided runpath/rpath entries.
Types ¶
type CursorMode ¶
type CursorMode uint8
CursorMode says where the search cursor sits relative to the hits, which decides what "the next one" means when the cursor has run off an end.
const ( CursorAtMatch CursorMode = iota // on a hit (or anywhere in the image) CursorAfterEnd // ran off the end going forward CursorBeforeStart // ran off the start going backward )
type DisasmService ¶
type DisasmService struct {
// contains filtered or unexported fields
}
DisasmService owns bounded disassembly window decoding and its cache. It is independent of the TUI event loop; callers decide how decoded windows affect UI state.
func NewDisasmService ¶
func NewDisasmService(file *binfile.File, dis disasm.Disassembler, maxBytes, searchWorkers int) *DisasmService
NewDisasmService creates a bounded disassembly decoder/cache.
func (*DisasmService) CanDecode ¶
func (s *DisasmService) CanDecode() bool
CanDecode reports whether a disassembler exists for this file's architecture. Every decode method is a safe no-op without one; callers that would otherwise mutate state on an empty decode check this first.
func (*DisasmService) DecodeAt ¶
DecodeAt returns a window containing addr and the instructions overlapping it.
func (*DisasmService) DecodeRange ¶
func (s *DisasmService) DecodeRange(start, size, lead int) []disasm.Inst
DecodeRange decodes the instructions in [start, start+size) of the executable image, using only `lead` bytes of context before start to re-synchronise the decoder (vs DecodeWindow's large interactive overlap). It is uncached, so a contiguous full-image scan neither re-decodes each chunk's predecessor (~2× less work) nor evicts the interactive decode cache. `lead` should keep the architecture's instruction alignment (a multiple of 4 covers arm64/riscv).
func (*DisasmService) DecodeRangeFunc ¶
func (s *DisasmService) DecodeRangeFunc(start, size, lead int, fn func(disasm.Inst) bool)
DecodeRangeFunc is DecodeRange streamed: it calls fn for each instruction in the range instead of returning a slice, so a scan that keeps only matching instructions never allocates the full decoded slice. fn returns false to stop.
func (*DisasmService) DecodeSpanAt ¶
func (s *DisasmService) DecodeSpanAt(addr uint64, before int) Span
DecodeSpanAt decodes a bounded window around addr, using `before` bytes of lead-in context, and returns it as a Span.
func (*DisasmService) DecodeSpanWindow ¶
func (s *DisasmService) DecodeSpanWindow(win binfile.Window) Span
DecodeSpanWindow decodes an explicit image window as a Span.
func (*DisasmService) DecodeWindow ¶
func (s *DisasmService) DecodeWindow(win binfile.Window) []disasm.Inst
DecodeWindow decodes instructions overlapping win, using cache and overlap.
func (*DisasmService) LeadBytes ¶
func (s *DisasmService) LeadBytes() int
LeadBytes returns the preferred bytes of context before a target address.
func (*DisasmService) MaxBytes ¶
func (s *DisasmService) MaxBytes() int
MaxBytes returns the current decode budget per window.
func (*DisasmService) OverlapBytes ¶
func (s *DisasmService) OverlapBytes() int
OverlapBytes returns the context decoded before each visible window.
func (*DisasmService) PrefetchAround ¶
func (s *DisasmService) PrefetchAround(addr uint64)
PrefetchAround warms the decode cache around addr for smoother navigation.
func (*DisasmService) ScanMatching ¶
func (s *DisasmService) ScanMatching(match func(text string) bool, limit int, done <-chan struct{}) []Match
ScanMatching decodes the executable image in parallel chunks and returns the `limit` lowest-addressed instructions whose text satisfies match. It stops early when done is closed.
Retained memory is bounded by limit, not by the number of matches. Each worker used to accumulate *every* match in its chunk, and the cap was applied only after all of them had been joined and sorted: searching "mov" over exex's own 15 MB binary matches ~98,000 instructions, so ~10 MB was allocated (and sorted) to show 500 rows — and it grew linearly with the target's size.
Bounding it also fixes what the cap discarded. The old merge stopped after the first chunks filled the quota, so matches in later chunks were dropped before the sort even looked at them; a low-addressed hit late in the image lost to a high-addressed one early in it. The shared heap below compares every match, so the result is exactly the lowest `limit` by address.
func (*DisasmService) SearchBatchChunks ¶
func (s *DisasmService) SearchBatchChunks() int
SearchBatchChunks returns how many chunks should be queued per search batch.
func (*DisasmService) SearchChunkBytes ¶
func (s *DisasmService) SearchChunkBytes() int
SearchChunkBytes returns the background-search chunk size.
func (*DisasmService) SearchWorkersFor ¶
func (s *DisasmService) SearchWorkersFor(chunks int) int
SearchWorkersFor returns the worker count capped by available chunks.
func (*DisasmService) SetOptions ¶
func (s *DisasmService) SetOptions(maxBytes, searchWorkers int)
SetOptions updates the decode budget and search worker preference.
func (*DisasmService) SpanFor ¶
SpanFor pairs an already-decoded window with its bounds, for callers that decoded it themselves (the instruction-text search decodes in parallel chunks).
PosLo is the first instruction's position, not the window's start. The two differ when DecodeAt began at a symbol (a section or function jump): the window reserves lead bytes that hold no decoded instructions, so anchoring "scroll up" on win.Start would jump far before the actual preceding code.
type FileExists ¶
FileExists abstracts filesystem probes for tests and alternate resolvers.
type Match ¶
type Match struct {
Addr uint64 // address of the matching instruction
Text string // its (trimmed) assembly text
Sym string // display name of the symbol it lives in, or ""
}
Match is one instruction a whole-image scan kept.
type SearchCache ¶
type SearchCache struct {
// contains filtered or unexported fields
}
SearchCache is the per-query cache. The zero value is an empty cache for the empty query; call Reset before use.
func (*SearchCache) Add ¶
func (c *SearchCache) Add(hits []SearchHit, forward bool)
Add merges freshly found hits, keeping the slice sorted and deduplicated by address. Past CacheCap it trims to the window nearest the direction of travel: forward keeps the highest addresses, backward the lowest.
Add reorders hits in place.
func (*SearchCache) Boundary ¶
func (c *SearchCache) Boundary(forward bool) (uint64, bool)
Boundary returns the outermost cached hit in a direction: the last one going forward, the first going backward. It is where an incremental scan resumes.
func (*SearchCache) Complete ¶
func (c *SearchCache) Complete(imgLen int) bool
Complete reports whether the cache holds every hit in an image of imgLen bytes: the whole image was scanned and nothing was dropped.
func (*SearchCache) Coverage ¶
func (c *SearchCache) Coverage() (lo, hi int)
Coverage returns the scanned image range; lo is -1 when nothing was scanned.
func (*SearchCache) EnsureQuery ¶
func (c *SearchCache) EnsureQuery(query string) bool
EnsureQuery resets the cache when the query has changed, and reports whether it did.
func (*SearchCache) Exhausted ¶
func (c *SearchCache) Exhausted(forward bool) bool
Exhausted reports whether scanning in this direction has reached the image's end without finding anything more.
func (*SearchCache) Hits ¶
func (c *SearchCache) Hits() []SearchHit
Hits returns the cached hits, in ascending address order.
func (*SearchCache) Next ¶
func (c *SearchCache) Next(cur uint64, mode CursorMode, forward, inclusive bool) (SearchHit, bool)
Next returns the cached hit the search would move to from cur, or ok=false when the cache cannot answer and the image must be scanned.
inclusive keeps a hit exactly at cur (the initial Enter); n / N pass false to step past it. When the cursor has run off an end, the search wraps to the hit at the opposite end.
func (*SearchCache) NoteCoverage ¶
func (c *SearchCache) NoteCoverage(lo, hi int)
NoteCoverage widens the scanned image range.
func (*SearchCache) Overflow ¶
func (c *SearchCache) Overflow() bool
Overflow reports whether more hits were found than the cache can hold, so it no longer holds all of them.
func (*SearchCache) Query ¶
func (c *SearchCache) Query() string
Query returns the query this cache holds hits for.
func (*SearchCache) Reset ¶
func (c *SearchCache) Reset(query string)
Reset empties the cache for a new query.
func (*SearchCache) SetExhausted ¶
func (c *SearchCache) SetExhausted(forward bool)
SetExhausted records that a direction has been scanned to its end.
type SearchHit ¶
SearchHit is a cached match: only the address and the instruction text.
Deliberately *not* the decoded window that found it. Retaining those would pin a decoded chunk per hit; a repeat jump re-decodes around the address instead, which the service's window cache usually satisfies anyway.
type Span ¶
type Span struct {
Insts []disasm.Inst
// PosLo is the image position of the *first decoded instruction*, which is
// what bounds "is there code above / where does it start".
PosLo int
// PosHi is the image position just past the decoded window.
PosHi int
}
Span is a decoded, bounded slice of the executable image: the instructions themselves plus the image offsets that bound them.