DynamoRIO / DynamoRIO/dynamorio

rseq side exit in native run results in PC discontinuity in drmemtrace

Open
#5,953 3 comments 0 reactions 1 assignee Claimed by @derekbruening View on GitHub
Component-DrMemtrace Google-Affecting
Dominant language
C
Stars
3.2k
Forks
629
Avg merge
2d 18h
Merged PRs (30d)
30

Description

With our run-twice solution, drmemtrace always records the full rseq sequence, yet the native execution might take a side branch and not complete execution (this is distinct from an rseq abort due to a kernel event). When that happens, the next block executed is not the logically next block after the rseq sequence. This results in a PC discontinuity in the resulting trace.

This is compounded by the possibility of a signal arriving in between the side exit and next block.

This is our plan to solve this:

the client needs to know when a side exit from the native
rseq execution happened. This is a regular exit cti which will be linked up. We want to
keep overhead small: even if these are sort of rare it's still hot code in
general. Maybe DR can add one store to a TLS field on each side exit (via local control
flow during mangling) storing the branch's PC, and the client identifies all exits of
side exits (DR either passes all regions up front for each module and client maps to
blocks, or DR adds a label to the top of exit target blocks) and adds a check looking
for this field (which DR exports a query for) and adds a marker (tracer itself can't
roll back b/c for long rseq region could have already written out erroneous instrs)
whose value is the PC of the exit branch and raw2trace sees that and rolls back.

raw2trace now needs to be able to go backward multiple blocks; plus a signal could
arrive before the side exit target block. Should DR tell the tracer about all rseq
regions? A label for the start block? And the tracer adds a marker; then raw2trace
buffers all rseq blocks. Plus a label for the end too.

So 4 new labels added by DR:

1. Rseq region entry at top of block (DR arranges for start of block)
2. Rseq region end before committing store (to avoid hiccups with label as final instr in
block): call it a committing store label. Tracer adds marker after store.
3. Rseq region side entry target block, at top of block
4. Rseq abort handler, at top of block

Tracer converts labels to markers for raw2trace.

New DR API:

Query side exit PC TLS field: clear field at this point.
Also instrumentation-level opnd API so can inline a check and then clean call to write
marker. Clean call required to call API query to clear value.

Raw2trace:

If see rseq entry marker, start buffering. Flush buffer at rseq end marker (moved to
after store by tracer) or side exit marker or abort handler marker.
If see rseq side exit marker, roll back in buffer until marker value PC found.
If signal came in: raw2trace would not have flushed buffer yet: so this would naturally
handle the signal interruption.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.