mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
add debug information to the crash page
This commit is contained in:
parent
1d9a7d51a3
commit
121ebe312c
19
justfile
19
justfile
|
@ -87,6 +87,15 @@ release +args: (_run-tool "release" args)
|
||||||
miri:
|
miri:
|
||||||
(cd agb-hashmap && cargo miri test)
|
(cd agb-hashmap && cargo miri test)
|
||||||
|
|
||||||
|
setup-cargo-wasm:
|
||||||
|
cargo install wasm-pack
|
||||||
|
|
||||||
|
build-agb-wasm:
|
||||||
|
(cd agb-wasm && wasm-pack build --target web)
|
||||||
|
rm -rf website/agb/src/app/vendor/agb_wasm
|
||||||
|
mkdir website/agb/src/app/vendor
|
||||||
|
cp agb-wasm/pkg website/agb/src/app/vendor/agb_wasm -r
|
||||||
|
|
||||||
build-mgba-wasm:
|
build-mgba-wasm:
|
||||||
rm -rf website/agb/src/app/mgba/vendor
|
rm -rf website/agb/src/app/mgba/vendor
|
||||||
mkdir website/agb/src/app/mgba/vendor
|
mkdir website/agb/src/app/mgba/vendor
|
||||||
|
@ -94,13 +103,19 @@ build-mgba-wasm:
|
||||||
|
|
||||||
build-combo-rom-site:
|
build-combo-rom-site:
|
||||||
just _build-rom "examples/combo" "AGBGAMES"
|
just _build-rom "examples/combo" "AGBGAMES"
|
||||||
|
|
||||||
build-site-app: build-mgba-wasm build-combo-rom-site
|
|
||||||
mkdir -p website/agb/public
|
mkdir -p website/agb/public
|
||||||
gzip -9 -c examples/target/examples/combo.gba > website/agb/public/combo.gba.gz
|
gzip -9 -c examples/target/examples/combo.gba > website/agb/public/combo.gba.gz
|
||||||
|
|
||||||
|
|
||||||
|
setup-app-build: build-mgba-wasm build-combo-rom-site build-agb-wasm
|
||||||
(cd website/agb && npm install --no-save --prefer-offline --no-audit)
|
(cd website/agb && npm install --no-save --prefer-offline --no-audit)
|
||||||
|
|
||||||
|
build-site-app: setup-app-build
|
||||||
(cd website/agb && npm run build)
|
(cd website/agb && npm run build)
|
||||||
|
|
||||||
|
serve-site-dev: setup-app-build
|
||||||
|
(cd website/agb && npm run dev)
|
||||||
|
|
||||||
build-site: build-site-app build-book
|
build-site: build-site-app build-book
|
||||||
rm -rf website/build
|
rm -rf website/build
|
||||||
cp website/agb/out website/build -r
|
cp website/agb/out website/build -r
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
import { ContentBlock } from "../contentBlock";
|
import { ContentBlock } from "../contentBlock";
|
||||||
import { useClientValue } from "../useClientValue.hook";
|
import { useClientValue } from "../useClientValue.hook";
|
||||||
import { styled } from "styled-components";
|
import { styled } from "styled-components";
|
||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import { useAgbDebug } from "../useAgbDebug.hook";
|
||||||
|
import { AddressInfo } from "../vendor/agb_wasm/agb_wasm";
|
||||||
|
|
||||||
export function BacktracePage() {
|
export function BacktracePage() {
|
||||||
return (
|
return (
|
||||||
|
@ -38,10 +41,93 @@ export function BacktracePage() {
|
||||||
<li>Configure the backtrace page to not point to a site at all</li>
|
<li>Configure the backtrace page to not point to a site at all</li>
|
||||||
<li>Not use the backtrace feature</li>
|
<li>Not use the backtrace feature</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
<Backtrace />
|
||||||
</ContentBlock>
|
</ContentBlock>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Backtrace() {
|
||||||
|
const backtrace = useClientValue(getBacktrace) ?? "";
|
||||||
|
const backtraceAddresses = useBacktraceData(backtrace);
|
||||||
|
|
||||||
|
const [files, setFile] = useState<File[]>([]);
|
||||||
|
const backtraceLocations = useBacktraceLocations(
|
||||||
|
backtraceAddresses ?? [],
|
||||||
|
files ?? []
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<details>
|
||||||
|
<summary>Addresses in the backtrace</summary>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
onChange={(evt) => {
|
||||||
|
const files = evt.target.files;
|
||||||
|
const filesArr = (files && Array.from(files)) ?? [];
|
||||||
|
setFile(filesArr);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ol>
|
||||||
|
{backtraceAddresses &&
|
||||||
|
backtraceAddresses.map((x, idx) => (
|
||||||
|
<li key={x}>
|
||||||
|
<code>0x{x.toString(16).padStart(8, "0")}</code>
|
||||||
|
<BacktraceAddressInfo info={backtraceLocations[idx]} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function BacktraceAddressInfo({ info }: { info: AddressInfo[] | undefined }) {
|
||||||
|
if (!info) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ol>
|
||||||
|
{info.map((x, idx) => (
|
||||||
|
<li key={idx}>
|
||||||
|
{x.is_inline && "(inlined into)"} {x.function_name}:{x.column}{" "}
|
||||||
|
{x.filename}:{x.line_number}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useBacktraceLocations(addresses: number[], file: File[]) {
|
||||||
|
const debug = useAgbDebug();
|
||||||
|
const [debugInfo, setDebugInfo] = useState<AddressInfo[][]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const f = file[0];
|
||||||
|
if (!f) return;
|
||||||
|
if (!debug) return;
|
||||||
|
(async () => {
|
||||||
|
const buf = await f.arrayBuffer();
|
||||||
|
const view = new Uint8Array(buf);
|
||||||
|
|
||||||
|
const agbDebugFile = debug.debug_file(view);
|
||||||
|
const debugInfo = addresses.map((x) => agbDebugFile.address_info(x));
|
||||||
|
setDebugInfo(debugInfo);
|
||||||
|
})();
|
||||||
|
}, [addresses, debug, file]);
|
||||||
|
|
||||||
|
return debugInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useBacktraceData(trace?: string) {
|
||||||
|
const debug = useAgbDebug();
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
try {
|
||||||
|
if (!trace) return;
|
||||||
|
const addresses = debug?.decode_backtrace(trace);
|
||||||
|
return addresses && Array.from(addresses);
|
||||||
|
} catch {}
|
||||||
|
}, [debug, trace]);
|
||||||
|
}
|
||||||
|
|
||||||
function BacktraceDisplay() {
|
function BacktraceDisplay() {
|
||||||
const backtrace = useClientValue(getBacktrace) ?? "";
|
const backtrace = useClientValue(getBacktrace) ?? "";
|
||||||
|
|
||||||
|
|
35
website/agb/src/app/useAgbDebug.hook.ts
Normal file
35
website/agb/src/app/useAgbDebug.hook.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import debugInit, {
|
||||||
|
decode_backtrace,
|
||||||
|
DebugFile,
|
||||||
|
InitOutput,
|
||||||
|
} from "./vendor/agb_wasm/agb_wasm";
|
||||||
|
|
||||||
|
let agbDebug: Promise<InitOutput> | undefined;
|
||||||
|
|
||||||
|
interface AgbDebug {
|
||||||
|
decode_backtrace: (backtrace: string) => Uint32Array;
|
||||||
|
debug_file: (file: Uint8Array) => DebugFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAgbDebug() {
|
||||||
|
const [debug, setDebug] = useState<AgbDebug>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
if (agbDebug === undefined) {
|
||||||
|
agbDebug = debugInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
await agbDebug;
|
||||||
|
console.log("Loaded agb debug");
|
||||||
|
|
||||||
|
setDebug({
|
||||||
|
decode_backtrace,
|
||||||
|
debug_file: (file: Uint8Array) => new DebugFile(file),
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return debug;
|
||||||
|
}
|
Loading…
Reference in a new issue