---
name: vcl-self-discovery
description: Use when the user wants you to autonomously explore an unfamiliar Delphi GUI app, fuzz it for crashes, find which controls trigger which handlers, or build a UI map without source. Covers bootstrapping the VCL tree from RTTI, breadth-first input fuzzing, and crash detection — entirely without human input.
---

# VCL self-discovery and autonomous fuzzing

You can build a complete model of a Delphi GUI app's user
interface — every form, button, edit, menu, with their captions
and event handlers — purely from RTTI inspection at runtime, no
source needed. Then drive that model to find crashes.

## Step 1 — Map the UI

After `attach` (and a `paused` event), bootstrap the form tree:

```
mainform = get_main_form()    # returns Application.MainForm address
tree = enumerate_vcl_tree(root=mainform.address, max_depth=5)
```

`enumerate_vcl_tree` returns a JSON tree of every `Component`
and `Control` reachable from the root, with each node's:

- `address` — for `inspect_object` calls.
- `class` — `TButton`, `TEdit`, `TMenuItem`, etc.
- `name` — Delphi-side `Name` (e.g. `Button1`).
- `caption` / `text` — visible label.
- `hwnd` — Win32 handle (only for `TWinControl` descendants).
- `event_handlers` — map of `OnClick`, `OnChange`, etc. to
  resolved symbols (e.g. `MainForm.Button1Click`). These are
  greppable in the source tree.

For windows that aren't on the main form (popup dialogs, MDI
children), enumerate via `list_windows` then call
`find_vcl_for_hwnd(hwnd=...)` to resolve each HWND to its
`TWinControl` address. Then `enumerate_vcl_tree` on each.

## Step 2 — Set the catch-all

```
set_breakpoint(kind="symbol", symbol="kernelbase!RaiseException")
set_exception_filter(first_chance=false)
```

The breakpoint catches every raised exception. The filter
suppresses noise from VCL internals (which raise lots of handled
exceptions during normal operation). Together: the `events`
pump only fires for **actual** crashes during your fuzzing
loop.

## Step 3 — Walk and inject

Strategy: breadth-first walk of the tree, classifying each node
by its class and choosing an action.

For **`TButton`**, **`TBitBtn`**, **`TSpeedButton`**:

```
click_at(hwnd=<button.hwnd>)
events(timeout_ms=500, filter=["exception", "paused"])
screenshot_desktop()   # catches any modal dialog
```

For **`TEdit`**, **`TMemo`**, **`TLabeledEdit`**:

```
set_text_field(hwnd=<edit.hwnd>, text=<payload>)
events(timeout_ms=300, filter=["exception"])
```

Where `<payload>` rotates through:

- Empty string `""`.
- Single space `" "`.
- Long string (10k chars) — `"A" * 10000`.
- Embedded NULs — `"hello\x00world"`.
- Edge unicode — surrogate pairs (`"𐀀"`), zero-width
  joiners (`"a‍b"`), bidi marks (`"‮"`).
- Path traversal — `"..\\..\\..\\windows\\system32"`.
- Format strings — `"%s%s%s%n"`, `"{0}{1}{2}"`.
- SQL chars — `"' OR 1=1 --"`, `"; DROP TABLE x;"`.
- Numbers in edit-as-text — `"1e999"`, `"-9999999999999"`.

For **`TMenuItem`**: items have an `Action` (TAction) or
`OnClick`. Resolve the popup via the parent's HWND and
`click_at`. Cascade carefully — closing menus may need
`Escape`.

For **`TComboBox`** / **`TListBox`**: cycle through items via
`post_message(WM_SETCURSEL)` or by typing the first letter of
each item.

## Step 4 — Crash analysis

When `events` returns an `exception` event:

1. Note the exception `class`, `address`, and the input
   sequence that produced it.
2. `inspect_object(address=<exception_address>)` for the
   `Message`.
3. Walk `frames[]` to the first user-code frame.
4. Capture state: `screenshot_desktop`, `get_registers`,
   `get_self()` if applicable.
5. Record this as one reproduction. **Resume** with
   `continue` and keep walking the tree — you may find more.

After the walk completes, report:

- One section per distinct exception class found.
- For each: the minimal input sequence, the crash site
  (`.pas:line`), the exception message, and a hypothesis about
  the cause.

## Hard rules

These are non-negotiable. The bug-hunter agent's system prompt
repeats them verbatim.

- **Destructive captions.** Never `click_at` a button whose
  caption matches `^(Close|Quit|Exit|Logout|Delete\b|Format\b
  |Drop\b|Reset\b|Reformat\b|Wipe\b)` without explicit user
  confirmation. Even if the app *looks* sandboxed, you don't
  know.
- **Sensitive fields.** Never `set_text_field` into a field
  whose `Name`, parent caption, or class matches
  `(?i)(password|secret|key|token|api[_-]?key|credit)`. These
  can lock accounts or trigger lockout policies.
- **Action budget.** Cap at 50 input actions per session unless
  the user explicitly lifts the limit. UX exploration can wedge
  a target through accumulated state.
- **Crash → stop and report.** When you find one crash, capture
  state and decide: keep walking (if breadth was the goal) or
  hand the diagnosis to the user (if depth was). Don't blindly
  continue and lose the trace.

## When to stop

You're done when one of:

- The action budget is exhausted.
- You've found `N` distinct exception classes (default `N=3`).
- The walk has visited every node in the tree without an
  exception → report a clean run with the coverage list.
