@henols/vice-mcp 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/THIRD-PARTY-NOTICES.md +422 -1
- package/anno-bank.ts +171 -0
- package/anno-cli.ts +1736 -163
- package/anno-confidence.ts +2 -2
- package/anno-derive.ts +6 -6
- package/anno-details.ts +4 -4
- package/anno-enum-gen.ts +416 -30
- package/anno-export-asm.ts +1211 -126
- package/anno-graphics.ts +338 -0
- package/anno-hazard-report.ts +1367 -0
- package/anno-import.ts +495 -0
- package/anno-index.ts +8 -8
- package/anno-join.ts +480 -0
- package/anno-memmap-render.ts +22 -21
- package/anno-provenance-ledger.ts +472 -0
- package/anno-regbits-gen.ts +13 -13
- package/anno-register.ts +159 -0
- package/anno-store-export.ts +661 -0
- package/anno-store.ts +635 -124
- package/anno-symbols.ts +7 -7
- package/anno-tools.ts +1169 -16
- package/anno-types.ts +313 -40
- package/backend-detect.mts +124 -312
- package/build.ts +3 -1
- package/capture-predicate.ts +597 -0
- package/channel-lock.ts +349 -0
- package/evid-ingest.ts +217 -0
- package/evid-reconcile.ts +316 -0
- package/host-tool-client.ts +430 -0
- package/incident-record.ts +23 -12
- package/install-resources.ts +29 -13
- package/memmap-lookup.ts +285 -0
- package/package.json +27 -8
- package/prg-image.ts +1 -2
- package/repo-root.ts +87 -3
- package/resources/backend-detect.mjs +98 -236
- package/resources/broker-control.mjs +220 -54
- package/resources/broker-epoch.mjs +7 -8
- package/resources/broker-kill.mjs +36 -31
- package/resources/broker-launch.mjs +511 -374
- package/resources/broker-state.mjs +69 -24
- package/resources/container-guard.mjs +1 -1
- package/resources/ghidra-project.mjs +790 -0
- package/resources/host-tool.mjs +2533 -0
- package/resources/vice-broker.mjs +434 -290
- package/resources/vice-launcher.sh +127 -9
- package/stock-address.ts +1 -1
- package/stock-condition.ts +1 -1
- package/stock-connect.ts +9 -5
- package/stock-derived.ts +29 -37
- package/stock-diagnose.ts +200 -36
- package/stock-dispatch.ts +179 -77
- package/stock-handler.ts +1 -1
- package/stock-paths.ts +18 -14
- package/stock-petscii.ts +1 -1
- package/stock-protocol.ts +1 -1
- package/stock-recycle.ts +83 -2
- package/stock-reproducible-run.ts +811 -0
- package/stock-run-until.ts +100 -1
- package/stock-symbols.ts +4 -4
- package/stock-timing.ts +1 -1
- package/stop-oracle.ts +167 -0
- package/text-capability-probe.ts +660 -0
- package/text-connect.ts +157 -0
- package/text-protocol.ts +810 -0
- package/text-tools.ts +778 -0
- package/textmon-backtrace.ts +385 -0
- package/textmon-cpuhistory.ts +335 -0
- package/textmon-memmap.ts +494 -0
- package/textmon-profile.ts +458 -0
- package/textmon-registers.ts +748 -0
- package/tools-manifest.stock.json +864 -3
- package/vice-broker-client.ts +253 -108
- package/vice-errors.ts +268 -0
- package/vice-proxy.ts +339 -2144
- package/vsf-slice.ts +640 -0
- package/anno-d64.ts +0 -310
- package/capability-registry.ts +0 -390
- package/refresh-manifest.ts +0 -124
- package/tools-manifest.json +0 -1223
- package/vice-probe.ts +0 -278
- package/vice-sync.ts +0 -336
- package/vice.ts +0 -772
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
// textmon-backtrace.ts
|
|
2
|
+
//
|
|
3
|
+
// THE ONE owning module for VICE's `bt` (backtrace) text-monitor output
|
|
4
|
+
// (PARSE-02, PARSE-03). Nothing else in this tree reads or interprets a
|
|
5
|
+
// `bt` reply -- a handler dials the wire, this module is the only place
|
|
6
|
+
// that turns the framed text into structured data. This module's sibling
|
|
7
|
+
// is `textmon-cpuhistory.ts` (Task 1 of this same plan); both share the
|
|
8
|
+
// address/bytes/disassembly column layout the `chis` format established,
|
|
9
|
+
// and both inherit D-42-3 (a parser returns a discriminated refusal, never
|
|
10
|
+
// throws) from plan 42-01's `textmon-memmap.ts`.
|
|
11
|
+
//
|
|
12
|
+
// WHY THIS FILE EXISTS RATHER THAN LIVING INSIDE THE TOOL HANDLER: the same
|
|
13
|
+
// reasoning `textmon-memmap.ts` and `textmon-cpuhistory.ts` state for
|
|
14
|
+
// themselves applies here unchanged.
|
|
15
|
+
//
|
|
16
|
+
// WHAT NOT TO DO:
|
|
17
|
+
// - Never import anything -- not `node:` anything, not `text-protocol.ts`,
|
|
18
|
+
// not `textmon-fixtures.ts`, not even a type-only import of a sibling
|
|
19
|
+
// module. Purity is asserted mechanically by this file's own test.
|
|
20
|
+
// - Never throw on a malformed or drifted input (D-42-3). Return the
|
|
21
|
+
// discriminated `BacktraceParseResult` instead.
|
|
22
|
+
// - Never re-sort or reverse `frames`. VICE emits the JSR chain in its own
|
|
23
|
+
// order -- the chain's own order IS the evidence; silently re-sorting
|
|
24
|
+
// or reversing it would restate which call is innermost.
|
|
25
|
+
// - Never truncate the frame list to a caller-requested depth. That is
|
|
26
|
+
// the tool's concern (plan 42-07), never this module's -- a parser that
|
|
27
|
+
// truncated would make the frame count a function of a caller's
|
|
28
|
+
// argument rather than of the machine.
|
|
29
|
+
// - Never read an unrecognised origin token as if it were an address. An
|
|
30
|
+
// unknown origin means the format has drifted from what this parser
|
|
31
|
+
// has ever seen; fabricating a caller from it would be worse than
|
|
32
|
+
// refusing.
|
|
33
|
+
// - Never treat the literal `+-` form (a negative SP offset) as a sign to
|
|
34
|
+
// "honour" separately from the digits -- the `+` is a fixed part of the
|
|
35
|
+
// field VICE always prints, and the sign lives in the digits' own
|
|
36
|
+
// prefix (see `parseSpOffset()` below).
|
|
37
|
+
// - Never strip a leading entry-echo prompt. `bt` never emits one
|
|
38
|
+
// (`fixtures/textmon/README.md`'s "Framing" section) -- stripping a
|
|
39
|
+
// first line here would delete the current-PC line.
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The current-PC frame: where execution is actually paused. Carries no
|
|
43
|
+
* caller, callee or SP offset -- those only apply to the call frames below
|
|
44
|
+
* it in the reconstructed chain.
|
|
45
|
+
*/
|
|
46
|
+
export interface BacktraceCurrentPc {
|
|
47
|
+
readonly address: number;
|
|
48
|
+
readonly bytes: readonly number[];
|
|
49
|
+
readonly disassembly: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The closed set of non-numeric frame origins: the three interrupt
|
|
53
|
+
* vectors. A numeric origin (a 4-hex-digit return address) is represented
|
|
54
|
+
* as a `number` instead -- see {@link BacktraceFrame.origin}. */
|
|
55
|
+
export type BacktraceOriginName = "reset" | "irq" | "nmi";
|
|
56
|
+
|
|
57
|
+
/** One reconstructed call frame. `origin` is either the caller's own
|
|
58
|
+
* address (a `number`) or one of the three interrupt-vector names -- never
|
|
59
|
+
* a token this parser has not explicitly recognised. `spOffset` is signed;
|
|
60
|
+
* VICE's own literal `+-` form for a negative offset is decoded, never
|
|
61
|
+
* treated as an edge case. */
|
|
62
|
+
export interface BacktraceFrame {
|
|
63
|
+
readonly origin: number | BacktraceOriginName;
|
|
64
|
+
readonly callee: number;
|
|
65
|
+
readonly spOffset: number;
|
|
66
|
+
readonly address: number;
|
|
67
|
+
readonly bytes: readonly number[];
|
|
68
|
+
readonly disassembly: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The full decoded backtrace: the current-PC frame plus every call frame,
|
|
72
|
+
* in VICE's own emitted order -- never re-sorted, never reversed, never
|
|
73
|
+
* truncated. */
|
|
74
|
+
export interface Backtrace {
|
|
75
|
+
readonly currentPc: BacktraceCurrentPc;
|
|
76
|
+
readonly frames: readonly BacktraceFrame[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The closed refusal-code union (D-42-3). `malformed-frame-line` covers a
|
|
80
|
+
* frame line whose overall layout does not match at all -- a STRUCTURAL
|
|
81
|
+
* mismatch, distinct from `unrecognised-origin` and `malformed-sp-offset`,
|
|
82
|
+
* each of which covers a line that IS laid out correctly but carries a
|
|
83
|
+
* value this parser has never seen at that position. */
|
|
84
|
+
export type BacktraceRefusalCode =
|
|
85
|
+
| "empty-response"
|
|
86
|
+
| "missing-current-pc-line"
|
|
87
|
+
| "malformed-frame-line"
|
|
88
|
+
| "unrecognised-origin"
|
|
89
|
+
| "malformed-sp-offset"
|
|
90
|
+
| "unrecognised-memspace";
|
|
91
|
+
|
|
92
|
+
/** A parser refusal (D-42-3): returned, never thrown. */
|
|
93
|
+
export interface TextParseRefusal {
|
|
94
|
+
readonly code: BacktraceRefusalCode;
|
|
95
|
+
readonly message: string;
|
|
96
|
+
readonly line: string;
|
|
97
|
+
readonly lineNumber: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** D-42-3's discriminated shape: a parser never throws, it returns one of
|
|
101
|
+
* these two arms. */
|
|
102
|
+
export type BacktraceParseResult = { ok: true; value: Backtrace } | { ok: false; refusal: TextParseRefusal };
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Framing constants -- this module's OWN copy, never imported from
|
|
106
|
+
// text-protocol.ts. The transport strips the trailing `(C:$xxxx)` prompt on
|
|
107
|
+
// the live wire path, but a fixture's raw `text` still carries it, so this
|
|
108
|
+
// module strips it defensively too -- never a leading prompt, since `bt`
|
|
109
|
+
// carries no entry-echo (README.md's "Framing" section).
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
const TRAILING_PROMPT_RE = /\(C:\$[0-9A-Fa-f]{4}\)\s*$/;
|
|
113
|
+
|
|
114
|
+
/** The one recognised memspace letter: the main CPU. Any other letter means
|
|
115
|
+
* the monitor's default memspace is pointed at a drive (CLAUDE.md's
|
|
116
|
+
* `default_memspace` contamination constraint). */
|
|
117
|
+
const MAIN_CPU_MEMSPACE = "C";
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The shared suffix every line (the current-PC line and every frame line
|
|
121
|
+
* alike) carries: an arbitrary prefix (captured separately and validated by
|
|
122
|
+
* the caller), then a memspace marker (`.`, one letter, `:`, 4 hex digits),
|
|
123
|
+
* three literal spaces, a 12-character-wide raw-bytes column, then the
|
|
124
|
+
* disassembly text running to the end of the line (never padded here --
|
|
125
|
+
* unlike `chis`, nothing follows it on this format, so trailing width is
|
|
126
|
+
* whatever the mnemonic and operand actually need). The non-greedy prefix
|
|
127
|
+
* capture matches the SHORTEST text before the first occurrence of the
|
|
128
|
+
* memspace-marker pattern, which is exactly once per line by construction.
|
|
129
|
+
*/
|
|
130
|
+
const SUFFIX_RE = /^(.*?)\.([A-Za-z]):([0-9A-Fa-f]{4}) (.{12})(.*)$/;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A frame line's prefix, once split from the shared suffix above: an origin
|
|
134
|
+
* token (captured loosely as any 4 characters, validated separately against
|
|
135
|
+
* the closed origin set below), ` -> `, the callee address (exactly 4 hex
|
|
136
|
+
* digits), ` [SP +`, the offset field (captured loosely, validated
|
|
137
|
+
* separately -- VICE's own literal `+-` form for a negative offset means
|
|
138
|
+
* the digits' own prefix carries the sign, never a separate sign to
|
|
139
|
+
* honour), `]`, one trailing space.
|
|
140
|
+
*/
|
|
141
|
+
const FRAME_PREFIX_RE = /^(.{4}) -> ([0-9A-Fa-f]{4}) \[SP \+([^\]]*)\] $/;
|
|
142
|
+
|
|
143
|
+
/** The closed origin-name set: VICE's three interrupt vectors, each printed
|
|
144
|
+
* padded to 4 characters (`"RST "`, `"IRQ "`, `"NMI "`) -- the same width
|
|
145
|
+
* as a 4-hex-digit numeric origin. */
|
|
146
|
+
const ORIGIN_NAMES: ReadonlyArray<{ token: string; name: BacktraceOriginName }> = [
|
|
147
|
+
{ token: "RST ", name: "reset" },
|
|
148
|
+
{ token: "IRQ ", name: "irq" },
|
|
149
|
+
{ token: "NMI ", name: "nmi" },
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
function makeRefusal(code: BacktraceRefusalCode, message: string, line: string, lineNumber: number): TextParseRefusal {
|
|
153
|
+
return { code, message, line, lineNumber };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Decodes the 12-character-wide raw-bytes column (1 to 3 space-separated
|
|
157
|
+
* hex byte pairs, space-padded on the right to a fixed width) -- the exact
|
|
158
|
+
* same shape `chis` uses. */
|
|
159
|
+
function parseBytesField(field: string): { ok: true; bytes: number[] } | { ok: false } {
|
|
160
|
+
const trimmed = field.trimEnd();
|
|
161
|
+
if (!/^[0-9A-Fa-f]{2}(?: [0-9A-Fa-f]{2}){0,2}$/.test(trimmed)) return { ok: false };
|
|
162
|
+
const bytes = trimmed.split(" ").map((token) => parseInt(token, 16));
|
|
163
|
+
return { ok: true, bytes };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Decodes the SP-offset field's raw captured text (whatever sat between
|
|
167
|
+
* `+` and `]`) into a signed integer. VICE's own literal `+-` form for a
|
|
168
|
+
* negative offset means the field can read `-241` directly (no leading
|
|
169
|
+
* spaces) or ` 3` (spaces then an unsigned magnitude) -- both are valid
|
|
170
|
+
* shapes of "optional leading spaces, optional minus, digits"; anything
|
|
171
|
+
* else refuses. */
|
|
172
|
+
function parseSpOffset(raw: string): { ok: true; value: number } | { ok: false } {
|
|
173
|
+
if (!/^ *-?\d+$/.test(raw)) return { ok: false };
|
|
174
|
+
return { ok: true, value: parseInt(raw.trim(), 10) };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Matches the shared address/bytes/disassembly suffix against `line`,
|
|
178
|
+
* returning its four parts, or `undefined` if the line does not carry the
|
|
179
|
+
* memspace-marker-plus-address pattern at all. */
|
|
180
|
+
function matchSuffix(
|
|
181
|
+
line: string,
|
|
182
|
+
): { prefix: string; memspace: string; addrHex: string; bytesField: string; disasm: string } | undefined {
|
|
183
|
+
const match = SUFFIX_RE.exec(line);
|
|
184
|
+
if (!match) return undefined;
|
|
185
|
+
return { prefix: match[1]!, memspace: match[2]!, addrHex: match[3]!, bytesField: match[4]!, disasm: match[5]! };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Parses `bt`'s framed text-monitor reply into a structured
|
|
190
|
+
* {@link Backtrace}. Never throws (D-42-3): every failure mode returns
|
|
191
|
+
* `{ ok: false, refusal }` naming exactly what was wrong and where.
|
|
192
|
+
*
|
|
193
|
+
* Bounded by construction: one pass over the payload's lines, each
|
|
194
|
+
* iteration consumes exactly one line, no recursion anywhere in this
|
|
195
|
+
* function.
|
|
196
|
+
*/
|
|
197
|
+
export function parseBacktrace(text: string): BacktraceParseResult {
|
|
198
|
+
if (typeof text !== "string" || text.trim() === "") {
|
|
199
|
+
return {
|
|
200
|
+
ok: false,
|
|
201
|
+
refusal: makeRefusal(
|
|
202
|
+
"empty-response",
|
|
203
|
+
"bt: the response was empty or whitespace-only -- never decoded as a zero-frame backtrace, because an " +
|
|
204
|
+
"empty response and a real capture that recorded nothing are two different facts",
|
|
205
|
+
"",
|
|
206
|
+
0,
|
|
207
|
+
),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const body = text.replace(TRAILING_PROMPT_RE, "");
|
|
212
|
+
|
|
213
|
+
if (body.trim() === "") {
|
|
214
|
+
return {
|
|
215
|
+
ok: false,
|
|
216
|
+
refusal: makeRefusal(
|
|
217
|
+
"empty-response",
|
|
218
|
+
"bt: the response contained only prompt text and no current-PC line -- never decoded as a zero-frame backtrace",
|
|
219
|
+
"",
|
|
220
|
+
0,
|
|
221
|
+
),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const lines = body.split("\n");
|
|
226
|
+
// A trailing "\n" before the (already-stripped) prompt splits into one
|
|
227
|
+
// trailing empty element -- drop exactly that split artifact, never any
|
|
228
|
+
// other blank line, so a genuinely blank line inside the payload still
|
|
229
|
+
// reaches the line parser below and refuses structurally rather than
|
|
230
|
+
// being silently swallowed here.
|
|
231
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
232
|
+
lines.pop();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const pcLine = lines[0] ?? "";
|
|
236
|
+
const pcMatch = matchSuffix(pcLine);
|
|
237
|
+
if (!pcMatch || !/^\s*PC\s*$/.test(pcMatch.prefix)) {
|
|
238
|
+
return {
|
|
239
|
+
ok: false,
|
|
240
|
+
refusal: makeRefusal(
|
|
241
|
+
"missing-current-pc-line",
|
|
242
|
+
`bt: the first line is not a recognised current-PC line: ${JSON.stringify(pcLine)}`,
|
|
243
|
+
pcLine,
|
|
244
|
+
1,
|
|
245
|
+
),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
if (pcMatch.memspace !== MAIN_CPU_MEMSPACE) {
|
|
249
|
+
return {
|
|
250
|
+
ok: false,
|
|
251
|
+
refusal: makeRefusal(
|
|
252
|
+
"unrecognised-memspace",
|
|
253
|
+
`bt: the current-PC line carries memspace marker ${JSON.stringify(pcMatch.memspace)}, not the main CPU's ` +
|
|
254
|
+
`${JSON.stringify(MAIN_CPU_MEMSPACE)} -- reset the default memspace with the vice_device_console tool`,
|
|
255
|
+
pcLine,
|
|
256
|
+
1,
|
|
257
|
+
),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const pcBytesResult = parseBytesField(pcMatch.bytesField);
|
|
261
|
+
if (!pcBytesResult.ok) {
|
|
262
|
+
return {
|
|
263
|
+
ok: false,
|
|
264
|
+
refusal: makeRefusal(
|
|
265
|
+
"malformed-frame-line",
|
|
266
|
+
`bt: the current-PC line has a malformed raw-bytes column: ${JSON.stringify(pcMatch.bytesField)}`,
|
|
267
|
+
pcLine,
|
|
268
|
+
1,
|
|
269
|
+
),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const currentPc: BacktraceCurrentPc = {
|
|
274
|
+
address: parseInt(pcMatch.addrHex, 16),
|
|
275
|
+
bytes: pcBytesResult.bytes,
|
|
276
|
+
disassembly: pcMatch.disasm.trimEnd(),
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const frames: BacktraceFrame[] = [];
|
|
280
|
+
|
|
281
|
+
for (let i = 1; i < lines.length; i++) {
|
|
282
|
+
const line = lines[i]!;
|
|
283
|
+
const lineNumber = i + 1;
|
|
284
|
+
|
|
285
|
+
const suffixMatch = matchSuffix(line);
|
|
286
|
+
if (!suffixMatch) {
|
|
287
|
+
return {
|
|
288
|
+
ok: false,
|
|
289
|
+
refusal: makeRefusal(
|
|
290
|
+
"malformed-frame-line",
|
|
291
|
+
`bt: line ${lineNumber} does not match the expected frame layout: ${JSON.stringify(line)}`,
|
|
292
|
+
line,
|
|
293
|
+
lineNumber,
|
|
294
|
+
),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const frontMatch = FRAME_PREFIX_RE.exec(suffixMatch.prefix);
|
|
299
|
+
if (!frontMatch) {
|
|
300
|
+
return {
|
|
301
|
+
ok: false,
|
|
302
|
+
refusal: makeRefusal(
|
|
303
|
+
"malformed-frame-line",
|
|
304
|
+
`bt: line ${lineNumber} does not match the expected "origin -> callee [SP +offset]" layout: ${JSON.stringify(line)}`,
|
|
305
|
+
line,
|
|
306
|
+
lineNumber,
|
|
307
|
+
),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const originToken = frontMatch[1]!;
|
|
312
|
+
const calleeHex = frontMatch[2]!;
|
|
313
|
+
const offsetRaw = frontMatch[3]!;
|
|
314
|
+
|
|
315
|
+
let origin: number | BacktraceOriginName;
|
|
316
|
+
if (/^[0-9A-Fa-f]{4}$/.test(originToken)) {
|
|
317
|
+
origin = parseInt(originToken, 16);
|
|
318
|
+
} else {
|
|
319
|
+
const named = ORIGIN_NAMES.find((entry) => entry.token === originToken);
|
|
320
|
+
if (!named) {
|
|
321
|
+
return {
|
|
322
|
+
ok: false,
|
|
323
|
+
refusal: makeRefusal(
|
|
324
|
+
"unrecognised-origin",
|
|
325
|
+
`bt: line ${lineNumber} carries an unrecognised frame origin ${JSON.stringify(originToken)} -- not a ` +
|
|
326
|
+
`4-hex-digit address and not one of the three recognised interrupt-vector names`,
|
|
327
|
+
line,
|
|
328
|
+
lineNumber,
|
|
329
|
+
),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
origin = named.name;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (suffixMatch.memspace !== MAIN_CPU_MEMSPACE) {
|
|
336
|
+
return {
|
|
337
|
+
ok: false,
|
|
338
|
+
refusal: makeRefusal(
|
|
339
|
+
"unrecognised-memspace",
|
|
340
|
+
`bt: line ${lineNumber} carries memspace marker ${JSON.stringify(suffixMatch.memspace)}, not the main ` +
|
|
341
|
+
`CPU's ${JSON.stringify(MAIN_CPU_MEMSPACE)} -- reset the default memspace with the vice_device_console tool`,
|
|
342
|
+
line,
|
|
343
|
+
lineNumber,
|
|
344
|
+
),
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const spOffsetResult = parseSpOffset(offsetRaw);
|
|
349
|
+
if (!spOffsetResult.ok) {
|
|
350
|
+
return {
|
|
351
|
+
ok: false,
|
|
352
|
+
refusal: makeRefusal(
|
|
353
|
+
"malformed-sp-offset",
|
|
354
|
+
`bt: line ${lineNumber} has a malformed SP-offset field ${JSON.stringify(offsetRaw)} -- never defaulted to zero`,
|
|
355
|
+
line,
|
|
356
|
+
lineNumber,
|
|
357
|
+
),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const bytesResult = parseBytesField(suffixMatch.bytesField);
|
|
362
|
+
if (!bytesResult.ok) {
|
|
363
|
+
return {
|
|
364
|
+
ok: false,
|
|
365
|
+
refusal: makeRefusal(
|
|
366
|
+
"malformed-frame-line",
|
|
367
|
+
`bt: line ${lineNumber} has a malformed raw-bytes column: ${JSON.stringify(suffixMatch.bytesField)}`,
|
|
368
|
+
line,
|
|
369
|
+
lineNumber,
|
|
370
|
+
),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
frames.push({
|
|
375
|
+
origin,
|
|
376
|
+
callee: parseInt(calleeHex, 16),
|
|
377
|
+
spOffset: spOffsetResult.value,
|
|
378
|
+
address: parseInt(suffixMatch.addrHex, 16),
|
|
379
|
+
bytes: bytesResult.bytes,
|
|
380
|
+
disassembly: suffixMatch.disasm.trimEnd(),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return { ok: true, value: { currentPc, frames } };
|
|
385
|
+
}
|