diff --git a/apps/tracer/src/DisassemblyView.css b/apps/tracer/src/DisassemblyView.css index aadaabbb..30502a4b 100644 --- a/apps/tracer/src/DisassemblyView.css +++ b/apps/tracer/src/DisassemblyView.css @@ -7,3 +7,7 @@ color: #e4e4e4; user-select: text; } + +a.disassembly-menu-open { + background-color: #ef6456; +} \ No newline at end of file diff --git a/apps/tracer/src/DisassemblyView.tsx b/apps/tracer/src/DisassemblyView.tsx index a0c332a7..8e240f4c 100644 --- a/apps/tracer/src/DisassemblyView.tsx +++ b/apps/tracer/src/DisassemblyView.tsx @@ -1,7 +1,7 @@ import "./DisassemblyView.css"; import { useR2 } from "./use-r2.js"; -import { Spinner } from "@blueprintjs/core"; -import { useEffect, useState } from "react"; +import { hideContextMenu, Menu, MenuItem, showContextMenu, Spinner } from "@blueprintjs/core"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; export interface DisassemblyViewProps { target?: DisassemblyTarget; @@ -21,8 +21,9 @@ export interface InstructionTarget { } export default function DisassemblyView({ target }: DisassemblyViewProps = {}) { - const [r2Output, setR2Output] = useState(""); + const [r2Output, setR2Output] = useState([]); const [isLoading, setIsLoading] = useState(false); + const highlightedAddressAnchorRef = useRef(null); const { executeR2Command } = useR2(); useEffect(() => { @@ -46,13 +47,20 @@ export default function DisassemblyView({ target }: DisassemblyViewProps = {}) { ].join("; ") : `s ${t.address}; pd`; let result = await executeR2Command(command); + if (ignore) { + return; + } if (result === "") { result = await executeR2Command("pdr"); } - if (!ignore) { - setR2Output(result); - setIsLoading(false); + if (ignore) { + return; } + + setR2Output(result + .split("
") + .map(line => line.replace(/\b0x[0-9a-f]+\b/, address => `${address}`))); + setIsLoading(false); } start(); @@ -62,13 +70,44 @@ export default function DisassemblyView({ target }: DisassemblyViewProps = {}) { }; }, [target]); - if (isLoading) { - return ( - - ); - } + const handleAddressMenuClose = useCallback(() => { + hideContextMenu(); + + highlightedAddressAnchorRef.current!.classList.remove("disassembly-menu-open"); + highlightedAddressAnchorRef.current = null; + }, []); + + const addressMenu = useMemo(() => ( + + + + ), [handleAddressMenuClose]); + + const handleContextMenu = useCallback((event: React.MouseEvent) => { + const target = event.target; + if (!(target instanceof HTMLAnchorElement)) { + return; + } + + event.preventDefault(); + + showContextMenu({ + content: addressMenu, + onClose: handleAddressMenuClose, + targetOffset: { + left: event.clientX, + top: event.clientY + }, + }); + + highlightedAddressAnchorRef.current = target; + target.classList.add("disassembly-menu-open"); + }, [handleAddressMenuClose, addressMenu]); return ( -
+
+ {isLoading ? () : undefined} + {r2Output.map((line, i) =>
)} +
); } diff --git a/apps/tracer/src/EventView.css b/apps/tracer/src/EventView.css index 6da03ac4..a1943c66 100644 --- a/apps/tracer/src/EventView.css +++ b/apps/tracer/src/EventView.css @@ -37,7 +37,7 @@ } .event-highlighted { - background-color: #EF6456; + background-color: #ef6456; } .event-highlighted .event-timestamp {