From 0d4005f163490280ae2009166bd5abad678d563e Mon Sep 17 00:00:00 2001 From: Corwin Date: Thu, 18 Apr 2024 19:10:53 +0100 Subject: [PATCH] make backtrace view fancy --- website/agb/src/app/crash/backtrace.tsx | 121 +++++++++++++++++++----- 1 file changed, 96 insertions(+), 25 deletions(-) diff --git a/website/agb/src/app/crash/backtrace.tsx b/website/agb/src/app/crash/backtrace.tsx index 2d0d8d3e..2178673b 100644 --- a/website/agb/src/app/crash/backtrace.tsx +++ b/website/agb/src/app/crash/backtrace.tsx @@ -46,52 +46,121 @@ export function BacktracePage() { ); } +const BacktraceListWrapper = styled.div` + font-size: 1rem; + position: relative; + width: calc(100vw - 20px); + margin-left: calc(-1 * (100vw - 20px) / 2); + left: 50%; +`; + +const BacktraceList = styled.ol` + overflow-x: scroll; + white-space: nowrap; +`; + function Backtrace() { const backtrace = useClientValue(getBacktrace) ?? ""; const backtraceAddresses = useBacktraceData(backtrace); const [files, setFile] = useState([]); + const backtraceAddressesList = + typeof backtraceAddresses === "object" ? backtraceAddresses : []; + const backtraceError = + typeof backtraceAddresses === "string" ? backtraceAddresses : undefined; + const backtraceLocations = useBacktraceLocations( - backtraceAddresses ?? [], + backtraceAddressesList, files ?? [] ); return (
Addresses in the backtrace - { - const files = evt.target.files; - const filesArr = (files && Array.from(files)) ?? []; - setFile(filesArr); - }} - /> -
    - {backtraceAddresses && - backtraceAddresses.map((x, idx) => ( + + + + {backtraceError} + {backtraceAddressesList.map((x, idx) => (
  1. - 0x{x.toString(16).padStart(8, "0")} - + {backtraceLocations[idx] ? ( + + ) : ( + 0x{x.toString(16).padStart(8, "0")} + )}
  2. ))} -
+ +
); } +function makeNicePath(path: string) { + const srcIndex = path.lastIndexOf("/src/"); + if (srcIndex < 0) return path; + + const crateNameStartIndex = path.slice(0, srcIndex).lastIndexOf("/"); + const crateName = + crateNameStartIndex < 0 + ? "" + : path.slice(crateNameStartIndex + 1, srcIndex); + + return `<${crateName}>/${path.slice(srcIndex + 5)}`; +} + +const GreenSpan = styled.span` + color: green; +`; + +const BacktraceAddressLine = styled.ul` + list-style-type: none; + padding-left: 20px; +`; + function BacktraceAddressInfo({ info }: { info: AddressInfo[] | undefined }) { if (!info) return; + function FunctionName({ + interesting, + functionName, + }: { + interesting: boolean; + functionName: string; + }) { + if (interesting) { + return {functionName}; + } + return functionName; + } + return ( -
    + {info.map((x, idx) => (
  1. - {x.is_inline && "(inlined into)"} {x.function_name}:{x.column}{" "} - {x.filename}:{x.line_number} + + {x.is_inline && "(inlined into)"}{" "} + {" "} + + {makeNicePath(x.filename)}:{x.line_number}:{x.column} + +
  2. ))} -
+ ); } @@ -100,17 +169,17 @@ function useBacktraceLocations(addresses: number[], file: File[]) { const [debugInfo, setDebugInfo] = useState([]); useEffect(() => { - const f = file[0]; - if (!f) return; - if (!debug) return; (async () => { + const f = file[0]; + if (!f) return; + if (!debug) return; 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); - })(); + return debugInfo; + })().then((x) => setDebugInfo(x ?? [])); }, [addresses, debug, file]); return debugInfo; @@ -124,7 +193,9 @@ function useBacktraceData(trace?: string) { if (!trace) return; const addresses = debug?.decode_backtrace(trace); return addresses && Array.from(addresses); - } catch {} + } catch (e: unknown) { + return `${e}`; + } }, [debug, trace]); }