Skip to content

Commit

Permalink
tracer: Add support for muting handlers
Browse files Browse the repository at this point in the history
Co-authored-by: Håvard Sørbø <[email protected]>
  • Loading branch information
oleavr and hsorbo committed Oct 17, 2024
1 parent 0250cbd commit bfaa242
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 27 deletions.
16 changes: 14 additions & 2 deletions agents/tracer/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,9 +528,14 @@ class Agent {

private invokeNativeHandler(id: TraceTargetId, callback: TraceEnterHandler | TraceLeaveHandler | TraceProbeHandler,
config: HandlerConfig, context: InvocationContext, param: any, cutPoint: CutPoint) {
const timestamp = Date.now() - this.started;
const threadId = context.threadId;
const depth = this.updateDepth(threadId, cutPoint);

if (config.muted) {
return;
}

const timestamp = Date.now() - this.started;
const caller = context.returnAddress.toString();
const backtrace = config.capture_backtraces ? Thread.backtrace(context.context).map(p => p.toString()) : null;

Expand All @@ -543,10 +548,15 @@ class Agent {

private invokeJavaHandler(id: TraceTargetId, callback: TraceEnterHandler | TraceLeaveHandler, config: HandlerConfig,
instance: Java.Wrapper, param: any, cutPoint: CutPoint) {
const timestamp = Date.now() - this.started;
const threadId = Process.getCurrentThreadId();
const depth = this.updateDepth(threadId, cutPoint);

if (config.muted) {
return;
}

const timestamp = Date.now() - this.started;

const log = (...message: string[]) => {
this.emit([id, timestamp, threadId, depth, null, null, message.join(" ")]);
};
Expand Down Expand Up @@ -901,6 +911,7 @@ async function getHandlers(request: HandlerRequest): Promise<HandlerResponse> {

function makeDefaultHandlerConfig(): HandlerConfig {
return {
muted: false,
capture_backtraces: false,
};
}
Expand Down Expand Up @@ -1115,6 +1126,7 @@ interface HandlerResponse {
}
type HandlerScript = string;
interface HandlerConfig {
muted: boolean;
capture_backtraces: boolean;
}

Expand Down
5 changes: 4 additions & 1 deletion apps/tracer/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,16 @@
display: flex;
justify-content: space-between;
flex: 0;
padding-right: 10px;
}

.editor-toolbar .bp5-switch {
padding-top: 10px;
}

.handler-muted input:checked ~ .bp5-control-indicator {
background: #cd4246 !important;
}

.monaco-editor {
position: absolute !important;
}
Expand Down
28 changes: 19 additions & 9 deletions apps/tracer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
Tabs,
Tab,
} from "@blueprintjs/core";
import { useRef } from "react";
import { Resplit } from "react-resplit";

export default function App() {
Expand All @@ -34,6 +33,8 @@ export default function App() {
draftedCode,
setDraftedCode,
deployCode,
handlerMuted,
setHandlerMuted,
captureBacktraces,
setCaptureBacktraces,

Expand Down Expand Up @@ -62,7 +63,6 @@ export default function App() {

symbolicate,
} = useModel();
const captureBacktracesSwitchRef = useRef<HTMLInputElement>(null);

const connectionError = lostConnection
? <Callout
Expand Down Expand Up @@ -155,13 +155,23 @@ export default function App() {
Disassemble
</Button>
</ButtonGroup>
<Switch
inputRef={captureBacktracesSwitchRef}
checked={captureBacktraces}
onChange={() => setCaptureBacktraces(captureBacktracesSwitchRef.current!.checked)}
>
Capture Backtraces
</Switch>
<div>
<Switch
className="handler-muted"
inline={true}
checked={handlerMuted}
onChange={e => setHandlerMuted(e.target.checked)}
>
Muted
</Switch>
<Switch
inline={true}
checked={captureBacktraces}
onChange={e => setCaptureBacktraces(e.target.checked)}
>
Capture Backtraces
</Switch>
</div>
</section>
<HandlerEditor
handlerId={selectedHandler?.id ?? null}
Expand Down
4 changes: 4 additions & 0 deletions apps/tracer/src/HandlerList.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.handler-list {
min-width: 200px;
}

.handler-node-muted svg {
color: #cd4246;
}
3 changes: 2 additions & 1 deletion apps/tracer/src/HandlerList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ export default function HandlerList({ handlers, selectedScope, onScopeSelect, se
icon: isExpanded ? "folder-open" : "folder-close",
childNodes: handlers
.filter(h => h.scope === scope)
.map(({ id, display_name }) => {
.map(({ id, display_name, config }) => {
return {
id,
label: display_name,
isSelected: id === selectedHandler,
icon: "code-block",
className: config.muted ? "handler-node-muted" : "",
};
}),
};
Expand Down
60 changes: 49 additions & 11 deletions apps/tracer/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function useModel() {
const [selectedHandler, setSelectedHandler] = useState<Handler | null>(null);
const [handlerCode, setHandlerCode] = useState("");
const [draftedCode, setDraftedCode] = useState("");
const [handlerMuted, _setHandlerMuted] = useState(false);
const [captureBacktraces, _setCaptureBacktraces] = useState(false);

const [selectedTab, _setSelectedTab] = useState<TabId>("events");
Expand Down Expand Up @@ -95,34 +96,44 @@ export function useModel() {
if (id === null) {
setSelectedScope("");
setSelectedHandler(null);
setHandlerCode("");
setDraftedCode("");
_setHandlerMuted(false);
_setCaptureBacktraces(false);
return;
}

const handler = handlers.find(h => h.id === id)!;
setSelectedScope(handler.scope);
setSelectedHandler(handler);
_setCaptureBacktraces(false);
const { config } = handler;
_setHandlerMuted(config.muted);
_setCaptureBacktraces(config.capture_backtraces);
}, [selectedHandlerId, handlers, request]);

useEffect(() => {
setHandlerCode("");
setDraftedCode("");

const id = selectedHandlerId;
if (id === null) {
return;
}

let ignore = false;

async function loadCodeAndConfig() {
const { code, config } = await request("handler:load", { id: id! });
async function loadCode() {
const { code } = await request("handler:load", { id: id! });
if (!ignore) {
setHandlerCode(code);
setDraftedCode(code);
_setCaptureBacktraces(config.capture_backtraces);
}
}

loadCodeAndConfig();
loadCode();

return () => {
ignore = true;
};
}, [selectedHandlerId, handlers, request]);
}, [selectedHandlerId, request]);

const deployCode = useCallback(async (code: string) => {
setHandlerCode(code);
Expand All @@ -135,13 +146,21 @@ export function useModel() {
pushState({ handler });
}, [pushState]);

const setHandlerMuted = useCallback(async (muted: boolean) => {
setHandlers(updateHandlerConfig(selectedHandlerId!, { muted }, handlers));
_setHandlerMuted(muted);
await request("handler:configure", {
id: selectedHandlerId!,
parameters: { muted }
});
}, [request, selectedHandler]);

const setCaptureBacktraces = useCallback(async (enabled: boolean) => {
setHandlers(updateHandlerConfig(selectedHandlerId!, { capture_backtraces: enabled }, handlers));
_setCaptureBacktraces(enabled);
await request("handler:configure", {
id: selectedHandler!.id,
parameters: {
capture_backtraces: enabled
}
parameters: { capture_backtraces: enabled }
});
}, [request, selectedHandler]);

Expand Down Expand Up @@ -343,6 +362,8 @@ export function useModel() {
draftedCode,
setDraftedCode,
deployCode,
handlerMuted,
setHandlerMuted,
captureBacktraces,
setCaptureBacktraces,

Expand Down Expand Up @@ -373,6 +394,21 @@ export function useModel() {
};
}

function updateHandlerConfig(id: HandlerId, updates: Partial<HandlerConfig>, handlers: Handler[]): Handler[] {
return handlers.map(h => {
if (h.id === id) {
return {
...h,
config: {
...h.config,
...updates
}
};
}
return h;
});
}

type TraceSpec = TraceSpecItem[];
type TraceSpecItem = [TraceSpecOperation, TraceSpecScope, TraceSpecPattern];
type TraceSpecOperation = "include" | "exclude";
Expand All @@ -395,12 +431,14 @@ export interface Handler {
scope: ScopeId;
display_name: string;
address: string | null;
config: HandlerConfig;
}
export type HandlerId = number;
export type TargetFlavor = "insn" | "c" | "objc" | "swift" | "java";
export type ScopeId = string;

interface HandlerConfig {
muted: boolean;
capture_backtraces: boolean;
}

Expand Down
13 changes: 10 additions & 3 deletions frida_tools/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def on_trace_handler_load(self, target: TraceTarget, handler: str, source: Path)
self._print(f'{target}: Loaded handler at "{source}"')

def _register_handler(self, target: TraceTarget, source: str) -> None:
config = {"capture_backtraces": False}
config = {"muted": False, "capture_backtraces": False}
self._handlers[target.identifier] = (target, source, config)

def _get_style(self, thread_id):
Expand Down Expand Up @@ -397,7 +397,7 @@ async def process_messages(self) -> None:
"type": "tracer:sync",
"spawned_program": app._spawned_argv[0] if app._spawned_argv is not None else None,
"process": app._tracer.process,
"handlers": [target.to_json() for target, _, _ in app._handlers.values()],
"handlers": [self._handler_entry_to_json(entry) for entry in app._handlers.values()],
}
)

Expand Down Expand Up @@ -462,7 +462,9 @@ async def _on_targets_commit(self, payload: dict) -> None:
await self.post(
{
"type": "handlers:add",
"handlers": [self.app._handlers[target_id][0].to_json() for target_id in target_ids],
"handlers": [
self._handler_entry_to_json(self.app._handlers[target_id]) for target_id in target_ids
],
}
)

Expand All @@ -476,6 +478,11 @@ async def _on_symbols_resolve_addresses(self, payload: dict) -> None:
names = self.app._tracer.resolve_addresses(payload["addresses"])
return {"names": names}

@staticmethod
def _handler_entry_to_json(entry: tuple[str, str, str]) -> dict:
target, _source, config = entry
return {**target.to_json(), "config": config}

app = TracerApplication()
app.run()

Expand Down

0 comments on commit bfaa242

Please sign in to comment.