Commit Graph
135 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 2fd413ec9c core: Decode patterns from Pharo
Answer the image's requests on a task and signal a semaphore once
done, so only the asking process waits.
2026-10-01 20:49:11 +02:00
Ole André Vadla Ravnås 3f70d259d3 core: Persist pattern placements
Store them with the REPL cell and the address insight, as a JSON
column each, and bind the decode view to them. Older rows and wire
cells without the field decode as none.
2026-10-01 20:49:11 +02:00
Ole André Vadla Ravnås 8d12aa4d7f core: Carry the app icon on a spawn target 2026-09-28 17:35:15 +02:00
Ole André Vadla Ravnås 52fcf32ac0 Put the kernel first in the process list
It is the one process nothing else stands in for. Name it as such,
and let the device rows ellipsize rather than widen the column.
2026-09-10 16:30:19 +02:00
Ole André Vadla Ravnås a5355458fc core: Store insight addresses as a bit pattern
GRDB maps UInt64 through Int64(self), which traps above Int64.max.
Give the record its own container and row init.
2026-09-10 12:51:32 +02:00
Ole André Vadla Ravnås 21121accb1 disassembler: Ask the agent for functions only
Analysis pulled every export, import and symbol across the wire
and then kept the handful that name code -- 87k rows for a
kernel, each carrying a type and an address as text.

Ask for what it uses instead: the offset, name and source of each
function the module knows about, chosen where the rows already
are.
2026-09-09 23:27:01 +02:00
Ole André Vadla Ravnås 0e933206fb Boot virtual machines from the target picker
Add a machine abstraction to LumaCore, with QEMU as its first
backend: templates mirroring frida-core's test guests, a QMP client,
and a display that maps QEMU's surface over D-Bus rather than
copying frames.

Leave readiness to the user: drive the guest, mark it ready, and come
back to that snapshot later. Keep the machine in the project, so
booting it again resumes where it was marked. Hand the stub to
addBareboneDevice, so it joins the picker beside the other devices.

Show the display while booting, and afterwards in a Machines panel,
which the side panel now models as an enum to share its slot.
2026-08-20 14:52:52 +02:00
Ole André Vadla Ravnås f8d25015ae Drop the comments that only restate the code
A comment is a last resort, and these were not one: section banners,
doc headers naming what the declaration below already names, and
notes saying in prose what the next line says in code.

What is left is what the code cannot show -- an ordering that matters,
a platform quirk, why the obvious way fails.
2026-08-13 13:09:18 +02:00
Ole André Vadla Ravnås 88148b26c2 Check the catalogue, the patches and the drawing
The example catalogue is Smalltalk inside Swift string literals,
which no compiler reads: parse each one in the image and report the
syntax errors, the names nothing defines and the selectors nothing
implements. Play every patch offline. Draw the effects and a
lettered scene offscreen and write a PNG of each, since what goes
wrong in drawing is blank frames and mirrored glyphs.

Play a snippet in a canvas for a while and report what the process
holds as it goes, and let go of what the image lets go of.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås d3fe5014cd Letter a scene from a glyph atlas
Two triangles a letter, from an atlas the host rasterises -- Core
Text on macOS, Pango on GTK -- because what fonts an image can reach
is its own business, and the bundled one finds no scalable family.

The point size is in the units the rest of the interface uses and
the atlas is rasterised to match, so the quads land on whole pixels
rather than being scaled, which is what would make it soft.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås a1508524a0 Draw the author's own scene on a canvas
A scene the image holds by handle and changes; the host draws it.
Each drawable carries its own vertex and fragment stages, its own
attribute layout, named uniforms, buffers, a transform and a
visibility flag -- described as objects rather than staged globals.

A value says what it should do, ramp or oscillate, rather than what
it is each frame: nothing crosses per frame, since the image has no
business in the frame path any more than in the audio callback.
Both renderers work it out on the clock that draws it.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås ad7ffcdabc Add a synthesiser that sounds arriving events
Eight channels, each with its own patch and pattern on its own step
clock, mixed on the audio device's thread: storage allocated once,
reached through unsafe pointers, and a lock-free ring for control,
so nothing under the callback allocates, retains or locks.

The image performs a tune, names it, and sounds chords.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås 2528c8fed2 Keep a snippet and its result in the notebook
A notebook cell holds a Pharo snippet and what it produced, updated
field by field and synced back when it is re-run. Trace blobs move
to a store of their own, read through one loader.

The method mark's editor keeps its own keys and clicks, so editing
inside an opened body works like editing anywhere else.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås b47d66efd3 Settle the inspector seams and empty state
Even out the spacing between columns, fill the seam triangles, and
centre the collapse arrow. Complete as you type, and pare the empty
state back to what it needs to say.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås 0d6b9eb362 Build the Pharo surface on GTK
Give GTK what the SwiftUI surface has: a playground of snippet cards
over a GtkSourceView that highlights Smalltalk, completes identifiers
and browses implementors and senders; the moldable inspector as
Miller columns with an overview strip, collapsed miniatures and a
thumb; graphs and charts drawn natively and drilled.

The VM boots at the top of main: the Spur heap wants a fixed base,
and by the time the first evaluate booted it lazily, GTK, WebKit and
cairo had reserved that region.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås 1e66b7a4f9 Say what a failed snippet did, and where
A compile error reads in words with a dot at the failing spot.
Evaluate splits from evaluate-and-inspect, the snippet spins while
it runs, and print it, format and browse sit on GT's keys.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås a9917a2b4c Browse and edit classes natively
Open any class in a browser folded into the inspector: its methods,
class-side ones too, a method saved from the editor, a sent method
opened in place, and a wrench offering fixes for an undeclared name.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås a248d02832 Keep evaluation results
Results survive a restart through Fuel, so a page opens where it
was left. Luma's own records stay portable so the image can revive
what it stored.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 6080bff60c Open Pharo values in panes beside the page
Each value opens in a pane on the gutter, beside the page rather
than under it. Panes drag, close and walk, a crowded tab strip
scrolls, and the split and its divider stay where they were put.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 3aab17ca5a Run Pharo from the notebook and a playground
Boot the VM against a bundled image, evaluate from a notebook cell
or a playground snippet, and keep what each evaluation produced.
The image is staged on every build; the framework release is pinned.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 035160a1e8 Paginate module symbols and focus filter with Cmd+F
Serve symbol pages by offset and step through them with prev/next
controls showing the current range. Reset to the first page when
the filter or category changes. Clamp the page index at the
mutation site and floor the offset in the agent so hammering
prev/next can't run past the ends into a negative range.

Bind Cmd+F (Ctrl+F on GTK) to focus the filter input.
2026-07-10 18:40:22 +02:00
Ole André Vadla Ravnås 4ffcbc31f3 Page module symbols to keep the UI responsive
Modules like YouTube Kids export 100k+ symbols. Enumerating and
marshalling the whole set per open stalled the UI, and both
frontends re-filtered the full arrays on the main thread on every
keystroke.

Build a cached, pre-sorted, pre-lowercased index in the agent and
serve filtered, capped pages. Add queryModuleSymbols returning a
window plus match and category counts. Wire both frontends to it
with a debounced filter; drop the client-side filtering.
2026-07-10 17:01:44 +02:00
Ole André Vadla Ravnås b22d2dabf8 core: Classify rerooted system modules
Match the distinctive /usr/lib markers anywhere in the path so a
jailbroken iOS reroot resolves: dyld appears as /cores/usr/lib/dyld
and was misclassified as an app module. Keep generic roots anchored
so app libraries under /data/app and /home stay app, and add Android
system roots (/system, /apex, /vendor, /product, /system_ext).
2026-07-10 16:44:06 +02:00
Ole André Vadla Ravnås 8a8dc759fa core: Sort module symbols by name
Exports, imports and symbols were shown in enumeration order. Sort them
alphabetically when parsing so both frontends get ordered lists.
2026-07-09 17:31:45 +02:00
necpition205 83769a5e8e Harden custom instrument handling 2026-06-28 02:02:14 +02:00
Ole André Vadla Ravnås b2e1849901 Collapse the modules sidebar group by default
Match threads; both groups start collapsed. A stored expansion
state is still honored.
2026-06-27 23:55:55 +02:00
Ole André Vadla Ravnås 5ed87e6018 Make sidebar hooks collapsible like module groups
Give instruments that have hooks a disclosure chevron and persist
the per-instrument collapsed state in the session UI state. Toggle
the module and thread groups on a full header-row click. Pad the
module view so its tabs clear the top-left edge.
2026-06-27 15:30:30 +02:00
Ole André Vadla Ravnås 38e5198209 Move modules and threads into the sidebar
Drop the modules/threads tabs; show both as collapsible sidebar
groups mirroring the hooks UX: a handful of top picks plus a
browse popover for the rest. Default threads to collapsed.

Revert the eager re-analysis of persisted modules on attach; keep
disassembly analysis lazy and add a per-module Analyze action and
status indicator instead.

Share one sidebar-row and one browser-popover component across
hooks, modules, and threads in both the SwiftUI and GTK frontends.
2026-06-27 14:53:01 +02:00
Ole André Vadla Ravnås 7119d4ca7e Detect JSON booleans without CoreFoundation
CFGetTypeID and CFBooleanGetTypeID are absent from swift-corelibs
Foundation, breaking the Linux and Windows builds. Decode r2's
JSON with a singleValueContainer cascade like R2Hex, where a JSON
boolean decodes as Bool and a number never does.
2026-06-27 10:19:48 +02:00
Ole André Vadla Ravnås f480ae79ba Group program modules ahead of system ones
Classify modules by their path (system locations on macOS, Linux
and Windows) so the program's own modules sort first and render
with emphasis, alphabetically within each group.
2026-06-27 04:14:51 +02:00
Ole André Vadla Ravnås e0da0576cd Keep colors when pinning r2 results to notebook
Carry the styled text on NotebookEntry alongside the plain
details, capture it when pinning an r2 cell, and render it with
color in both notebook frontends.
2026-06-26 19:24:51 +02:00
Ole André Vadla Ravnås e711f772e3 Render r2 hexdumps in the hex view widget
Detect the plain px and x commands and fetch their bytes via
pxj, rendering them in our interactive hex view rather than as
text. Resolve the target address so the offset column shows the
real addresses, carrying it on the binary result's metadata.
2026-06-26 19:13:57 +02:00
Ole André Vadla Ravnås 7d38ac2f7f Persist the r2 REPL seek as an address anchor
Snapshot the r2 seek after each r2 eval, storing it on
SessionUIState as an AddressAnchor so it re-bases across runs.
Resolve and restore it during the session warm-up, which now
also runs when only a seek (no analysis) was saved.
2026-06-26 18:49:13 +02:00
Ole André Vadla Ravnås 0285de051a Enrich r2 REPL completion and persist input state
Carry a display/insert split through completion so command
suggestions show r2's help text via the native secondary title,
and complete command arguments against eval vars and flagspaces
in addition to flags. Recall the language alongside the code when
cycling history, and keep r2 output's leading whitespace intact.

Persist the REPL draft and active language per session in
SessionUIState so they survive reopening the project. Defer the
input field's first-responder change out of the view update.
2026-06-26 17:46:01 +02:00
Ole André Vadla Ravnås b84bfa0a2b Add r2 as a first-class REPL language
Make the REPL prompt a clickable mode toggle between JavaScript
and r2; ":", ":r2" and ":js" switch from the keyboard. Carry the
language on REPLCell and REPLResult, route r2 input through the
session disassembler, and render output as a JSInspectValue tree
for JSON commands or ANSI-parsed styled text otherwise.
2026-06-26 16:45:21 +02:00
Ole André Vadla Ravnås 9606ec4930 Drop the driver concept; await host-claim ack
The driver seat became fully redundant with the host once session
interaction moved to owner gating: it was always equal to the host and
nothing read it for authorization. Remove it wholesale — the
claim-driver op, driverBySession, localUserIsDriver, Session.driver,
and the REPL "Driving" indicator.

Gate REPL submission on ownership (solo always). Claim hosting through
an acknowledged request and attach only once the server accepts,
instead of optimistically attaching before the claim is even sent.
2026-06-26 15:34:02 +02:00
Ole André Vadla Ravnås 87e2972f2e Share register layout between CFG and thread views
Extract the arm64 register ordering into CpuRegisterLayout and
have both CFG views and the thread snapshot consume it. Drop the
now-dead arch plumbing from the CFG views.
2026-06-23 00:18:34 +02:00
Ole André Vadla Ravnås 5a60db2618 core: Order thread registers like the CFG view
Canonicalize arm64 register order in the snapshot: GPRs, then
sp/pc/nzcv, then vectors. Both frontends inherit it.
2026-06-22 23:51:23 +02:00
Ole André Vadla Ravnås c6d07ca32a Derive hook and insight names from symbol
Modules-view actions built names via anchor.displayString,
yielding module!symbol for hooks and module+offset for
disassembly/memory insights. Route both through the symbol the
tracer search already uses.

Add AddressAnchor.symbolName; default tracer hook names to it.
Thread the context anchor hint into getOrCreateInsight so
insights opened on exports and imports inherit the symbol name.
Drop the unused title parameter from ModuleDetailView.
2026-06-22 22:26:27 +02:00
Ole André Vadla Ravnås de4c469393 itrace: Give each trace its own buffer
Drop the shared-buffer rendezvous. Each trace now owns its
buffer, created before Stalker is armed and announced to Luma
via a token-keyed start/ack handshake. The ack carries the
drain verdict: Luma remaps the buffer out-of-process while the
agent blocks, so an early crash still yields data; on
task_for_pid denial (cached per target) the agent drains and
pushes chunks itself.

Fold all itrace into the tracer instrument. Function-arm traces
and thread traces share one Trace registry; thread traces become
threadTraces config entries on a find-or-created tracer instance.
Core no longer exports itrace, and the drain agent keys its
readers by session so concurrent traces stay separate.
2026-05-31 15:12:17 +02:00
Ole André Vadla Ravnås 8d6f91fe1e Plumb image attachments through to the LLM
Console widgets get an appendImage / respond.image API on the
agent. read_widget_state surfaces image entries as attachments
scaled to at most max_dimension pixels (default 1568) on the
longest edge. Anthropic nests image blocks inside tool_result;
OpenAI gets a synthetic follow-up user message. The host scales
via CoreImage on macOS and GdkPixbuf on GTK.
2026-05-22 12:15:53 +02:00
Ole André Vadla Ravnås d0acb79a14 agent: Use friendly names for AI-installed hooks 2026-05-21 02:01:40 +02:00
Ole André Vadla Ravnås 0b8f09d4d9 Hide arm action on non-arm-flow sessions 2026-05-21 00:23:58 +02:00
Ole André Vadla Ravnås 0384896e9d core: Sync persisted module symbols via collab
New update-module-symbols SessionOp carries a batch of
(modulePath, offset, name) entries. persistSymbolicateResults
enqueues one op per symbolicate roundtrip; non-drivers upsert
into module_symbol on receive. Late-joiner snapshots ingest
the whole table.
2026-05-20 21:15:55 +02:00
Ole André Vadla Ravnås 211c8d25e2 Carry symbolicate names offline
Engine.symbolDisplay returns a richer SymbolDisplay (overlay,
source, raw, primary) and persists every live symbolicate
result into module_symbol (sessionID, modulePath, function-entry
offset → name). Offline rendering falls through to that table
first, then to enclosingFunction from the persisted block
ranges, then to module+offset. ProcessNode delegates trace
block annotation back through this path via
onResolveBlockNames so the same names show up on detached
traces.
2026-05-20 19:18:13 +02:00
Ole André Vadla Ravnås dc6af656fd Persist basic blocks per analyzed function
Split ModuleAnalysis persistence into module_analysis,
module_analysis_function and module_analysis_block tables.
Harvest blocks via afbj and use them to answer enclosingFunction
offline. R2Hex accepts both 0x-prefixed strings and raw integers,
since cfg.json.num=hex doesn't cover afbj. When the cache is
present but blocks are missing, replay anyway unless we're online
and can re-analyze.
2026-05-20 19:17:57 +02:00
Ole André Vadla Ravnås dd71943d94 Allow naming address insights
Replace the auto-derived title with userTitle (nil = auto)
and a parentInsightID link. Display name is userTitle, else
<parent.title>+0x<delta>, else sub_<offset> if at a function
start, else module+offset. Sidebar context menu Rename… and
an LLM rename_insight tool both go through Engine.renameInsight,
which broadcasts via the existing updateInsight op and pushes
the new name into r2 as a flag (plus afn at function starts).

getOrCreateInsight kicks off a background pass that links a
new insight to its enclosing function-start insight, and
adopts siblings inside its region when the new insight is
itself the function start. The same adoption runs when a
fresh ModuleAnalysis newly reveals a function start under an
existing insight.
2026-05-19 16:01:25 +02:00
Ole André Vadla Ravnås 12d5491c22 Sync disasm cache across collab
Identify a process instance by a deterministic identity returned
from the agent (per-OS, with a Process.mainModule + pid fallback)
and stash it on ProcessSession.processInfo. Rekey memory_page
into memory_page_module (module UUID + offset) so cached bytes
survive ASLR, and memory_page_anon (process identity + address)
for JIT / heap regions that only survive within one process
instance. Purge stale anon pages on every fresh attach.

Add updateProcessInfo, updateModuleAnalysis and updateInsight
SessionOps plus a side-channel publish-memory-page op and a
+fetch-memory-page request. The driver write-throughs every
page it fetches; non-drivers pull on miss and persist locally.
Module-analysis rows flow the same way so non-drivers can key
their cache by module UUID. The lab-join snapshot now carries
processInfo and module_analyses too.

Refresh actions on the insight detail view: Reread Bytes drops
the pages overlapping the visible range; Reanalyze Module drops
the module's analysis and pages, re-running r2 on next access.

The macOS detail view now reads the insight live from
insightsBySession via observation; GTK forwards .insightUpdated
into the detail and reschedules a refresh when the resolved
address changes.
2026-05-19 15:16:48 +02:00
Ole André Vadla Ravnås aa87467bbb Cache memory pages across detach
Decouple Disassembler from ProcessNode via MemoryReader and
ModuleIntrospector protocols, and add a per-session page store
that r2 reads flow through. The disassembler now survives
detach; insights render from cache, with live reads
re-populating it on reattach.
2026-05-19 09:53:50 +02:00
Ole André Vadla Ravnås 143df80073 Bound disasm at function end
Persist per-session module analysis (executable ranges + known
functions, keyed by module name + LC_UUID) so on-demand
analysis runs once per binary and rebases on reattach. The
agent gains enumerateModuleRanges and getModuleIdentity; the
store gains a module_analysis table.

Disassembler queries $FB/$FE for the request address; when it
hits a function start, fetch via pDJ bounded to the function's
byte range. Otherwise fall back to pdJ N. Filter pdJ
decoration entries (xrefs, fcn headers, var summaries) that
share the addr of an instruction.

DisassemblyPage carries a scope (.function/.span) so the
SwiftUI and GTK insight views can disable loadMore when the
page is function-bounded. The disassemble AI tool surfaces the
scope too, so the model knows whether it has the whole
function or just an N-instruction span.

Go-to-Function-Start now opens (or selects) the insight rooted
at the function start, which then renders via the bounded
path.
2026-05-19 09:53:41 +02:00