Skip to content

Commit

Permalink
Wire up some more
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Sep 12, 2024
1 parent 2f5b868 commit c1aae18
Show file tree
Hide file tree
Showing 10 changed files with 1,616 additions and 742 deletions.
1,928 changes: 1,223 additions & 705 deletions agents/tracer/package-lock.json

Large diffs are not rendered by default.

32 changes: 26 additions & 6 deletions frida_tools/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from collections import OrderedDict
from dataclasses import dataclass
from pathlib import Path
from typing import Callable, Generator, List, Optional, Union
from typing import Callable, Generator, List, Optional, Set, Union

import frida
import websockets.asyncio.server
Expand Down Expand Up @@ -48,6 +48,8 @@ class TracerApplication(ConsoleApplication, UI):
def __init__(self) -> None:
super().__init__(await_ctrl_c)
self._handlers = OrderedDict()
self._ui_sockets: Set[websockets.asyncio.server.ServerConnection] = set()
self._asyncio_loop = None
self._palette = [Fore.CYAN, Fore.MAGENTA, Fore.YELLOW, Fore.GREEN, Fore.RED, Fore.BLUE]
self._next_color = 0
self._attributes_by_thread_id = {}
Expand Down Expand Up @@ -187,6 +189,9 @@ def _needs_target(self) -> bool:
return True

def _start(self) -> None:
worker = threading.Thread(target=self._run_ui_server, name="ui-server", daemon=True)
worker.start()

if self._output_path is not None:
self._output = OutputFile(self._output_path)

Expand All @@ -207,9 +212,6 @@ def _start(self) -> None:
self._exit(1)
return

worker = threading.Thread(target=self._run_ui_server, name="ui-server", daemon=True)
worker.start()

def _stop(self) -> None:
self._tracer.stop()
self._tracer = None
Expand Down Expand Up @@ -241,8 +243,10 @@ def on_trace_error(self, message: str) -> None:
self._exit(1)

def on_trace_events(self, events) -> None:
self._asyncio_loop.call_soon_threadsafe(lambda: self._asyncio_loop.create_task(self._broadcast_trace_events(events)))

no_attributes = Style.RESET_ALL
for timestamp, thread_id, depth, message in events:
for target_id, timestamp, thread_id, depth, message in events:
if self._output is not None:
self._output.append(message + "\n")
elif self._quiet:
Expand Down Expand Up @@ -285,6 +289,7 @@ def _run_ui_server(self):
asyncio.run(self._handle_ui_requests())

async def _handle_ui_requests(self):
self._asyncio_loop = asyncio.get_running_loop()
async with websockets.asyncio.server.serve(
self._handle_websocket_connection, "localhost", 1337, process_request=self._handle_asset_request
):
Expand All @@ -294,6 +299,7 @@ async def _handle_websocket_connection(self, websocket: websockets.asyncio.serve
if self._tracer is None:
return

self._ui_sockets.add(websocket)
try:
message = {
"type": "handlers:sync",
Expand Down Expand Up @@ -345,6 +351,20 @@ async def _handle_websocket_connection(self, websocket: websockets.asyncio.serve
import traceback
traceback.print_exc()
#pass
finally:
self._ui_sockets.remove(websocket)

async def _broadcast_trace_events(self, events):
for websocket in self._ui_sockets:
print("Sending", len(events), "events")
await websocket.send(
json.dumps(
{
"type": "events:add",
"events": events,
}
)
)

def _handle_asset_request(
self, connection: websockets.asyncio.server.ServerConnection, request: websockets.asyncio.server.Request
Expand Down Expand Up @@ -539,7 +559,7 @@ def _on_message(self, message, data, ui) -> None:
def _try_handle_message(self, mtype, params, data, ui) -> False:
if mtype == "events:add":
events = [
(timestamp, thread_id, depth, message)
(target_id, timestamp, thread_id, depth, message)
for target_id, timestamp, thread_id, depth, message in params["events"]
]
ui.on_trace_events(events)
Expand Down
1 change: 1 addition & 0 deletions ui/tracer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"monaco-editor": "^0.51.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scroll-to-bottom": "^4.2.0",
"react-use-websocket": "^4.8.1",
"use-debounce": "^10.0.3"
},
Expand Down
5 changes: 5 additions & 0 deletions ui/tracer/src/App.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.top-area {
display: flex;
flex: 1;
}

.navigation-area {
display: flex;
flex-direction: column;
Expand Down
79 changes: 52 additions & 27 deletions ui/tracer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import "./App.css";
import AddTargetsDialog from "./AddTargetsDialog.tsx";
import EventView from "./EventView.tsx";
import HandlerEditor from "./HandlerEditor.tsx";
import HandlerList from "./HandlerList.tsx";
import {
Event,
Handler,
HandlerId,
ScopeId,
Expand All @@ -12,6 +14,7 @@ import {
import {
BlueprintProvider,
Callout,
Collapse,
Button,
ButtonGroup,
} from "@blueprintjs/core";
Expand All @@ -25,9 +28,13 @@ export default function App() {
const [handlerCode, setHandlerCode] = useState("");
const [draftedCode, setDraftedCode] = useState("");
const [addingTargets, setAddingTargets] = useState(false);
const [eventsVisible, setEventsVisible] = useState(false);
const [events, setEvents] = useState<Event[]>([]);
const [stagedItems, setStagedItems] = useState<StagedItem[]>([]);
const { sendJsonMessage, lastJsonMessage, readyState } = useWebSocket<TracerMessage>("ws://localhost:1337" /* window.location.origin */);

console.log("render() events.length:", events.length);

function handleHandlerSelection(id: HandlerId) {
setSelectedHandler(id);
sendJsonMessage({ type: "handler:load", id });
Expand Down Expand Up @@ -72,14 +79,20 @@ export default function App() {
case "handlers:add":
setHandlers(handlers.concat(lastJsonMessage.handlers));
break;
case "handler:loaded":
case "handler:loaded": {
const { code } = lastJsonMessage;
setHandlerCode(code);
setDraftedCode(code);
break;
}
case "targets:staged":
setStagedItems(lastJsonMessage.items)
break;
case "events:add":
console.log("Old events length:", events.length);
console.log("Message events length:", lastJsonMessage.events.length);
setEvents(events.concat(lastJsonMessage.events));
break;
default:
console.log("TODO:", lastJsonMessage);
break;
Expand All @@ -96,33 +109,39 @@ export default function App() {

return (
<>
<section className="navigation-area">
<HandlerList
handlers={handlers}
selectedScope={selectedScope}
onScopeSelect={scope => setSelectedScope(scope)}
selectedHandler={selectedHandler}
onHandlerSelect={handleHandlerSelection}
/>
<ButtonGroup className="target-actions" vertical={true}>
<Button intent="success" icon="add" fill={true} onClick={() => setAddingTargets(true)}>Add</Button>
</ButtonGroup>
</section>
<section className="work-area">
{connectionError}
<ButtonGroup minimal={true}>
<Button
icon="rocket-slant"
disabled={draftedCode === handlerCode}
onClick={() => deploy(draftedCode)}>Deploy</Button>
</ButtonGroup>
<HandlerEditor
handlerId={selectedHandler}
handlerCode={handlerCode}
onChange={setDraftedCode}
onSave={deploy}
/>
<section className="top-area">
<section className="navigation-area">
<HandlerList
handlers={handlers}
selectedScope={selectedScope}
onScopeSelect={scope => setSelectedScope(scope)}
selectedHandler={selectedHandler}
onHandlerSelect={handleHandlerSelection}
/>
<ButtonGroup className="target-actions" vertical={true} minimal={true} alignText="left">
<Button intent="success" icon="add" onClick={() => setAddingTargets(true)}>Add</Button>
<Button icon="lightning" onClick={() => setEventsVisible(!eventsVisible)}>{eventsVisible ? "Hide Events" : "Show Events"}</Button>
</ButtonGroup>
</section>
<section className="work-area">
{connectionError}
<ButtonGroup minimal={true}>
<Button
icon="rocket-slant"
disabled={draftedCode === handlerCode}
onClick={() => deploy(draftedCode)}>Deploy</Button>
</ButtonGroup>
<HandlerEditor
handlerId={selectedHandler}
handlerCode={handlerCode}
onChange={setDraftedCode}
onSave={deploy}
/>
</section>
</section>
<Collapse className="bottom-area" isOpen={eventsVisible}>
<EventView events={events} />
</Collapse>
<AddTargetsDialog
isOpen={addingTargets}
stagedItems={stagedItems}
Expand All @@ -142,6 +161,7 @@ type TracerMessage =
| HandlersAddMessage
| HandlerLoadedMessage
| TargetsStagedMessage
| EventsAddMessage
;

interface HandlersSyncMessage {
Expand All @@ -163,3 +183,8 @@ interface TargetsStagedMessage {
type: "targets:staged";
items: StagedItem[];
}

interface EventsAddMessage {
type: "events:add";
events: Event[];
}
20 changes: 20 additions & 0 deletions ui/tracer/src/EventView.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.event-view {
border-top: 5px groove #ef6456;
}

.event-items {
min-height: 200px;
max-height: 200px;
padding: 5px;
font-family: monospace;
font-size: 10px;
}

.event-timestamp {
margin-right: 15px;
color: #555;
}

.event-message {
font-weight: bold;
}
22 changes: 22 additions & 0 deletions ui/tracer/src/EventView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import "./EventView.css";
import { Event } from "./model.js";
import ScrollToBottom from "react-scroll-to-bottom";

export default function EventView({ events }: { events: Event[] }) {
return (
<ScrollToBottom className="event-view">
<div className="event-items">
{
events.map(([targetId, timestamp, threadId, depth, message], i) => {
return (
<div key={i}>
<span className="event-timestamp">{timestamp} ms</span>
<span className="event-message">{message}</span>
</div>
);
})
}
</div>
</ScrollToBottom>
);
}
1 change: 1 addition & 0 deletions ui/tracer/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ html, body, #root {

#root {
display: flex;
flex-direction: column;
}
2 changes: 2 additions & 0 deletions ui/tracer/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ export type StagedItemId = number;

export type ScopeName = string;
export type MemberName = string | [string, string];

export type Event = [targetId: HandlerId, timestamp: number, threadId: number, depth: number, message: string];
Loading

0 comments on commit c1aae18

Please sign in to comment.