Skip to content

Commit 07dc74d

Browse files
committed
Address review feedback: use findJITRegion, restore Detach cleanup
- Restore findJITRegion() from base (open-telemetry#1102) which was incorrectly removed during rebase - PR #26 now reuses the shared function instead of inline code - Remove redundant inline first-pass JIT detection (now handled by findJITRegion) - Detach cleanup is inherited from the updated base (open-telemetry#1102)
1 parent 1842c44 commit 07dc74d

File tree

3 files changed

+51
-27
lines changed

3 files changed

+51
-27
lines changed

interpreter/ruby/ruby.go

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,56 @@ func profileFrameFullLabel(classPath, label, baseLabel, methodName libpf.String,
12861286
// On x86_64, frame pointers are only emitted when --yjit-perf or --yjit-perf=fp is used.
12871287
// When --yjit-perf is active, YJIT also creates /tmp/perf-PID.map, which we use as the
12881288
// detection signal on x86_64.
1289+
// findJITRegion detects the YJIT JIT code region from process memory mappings.
1290+
// YJIT reserves a large contiguous address range (typically 48-128 MiB) via mmap
1291+
// with PROT_NONE and then mprotects individual 16k codepages to r-x as needed.
1292+
// On systems with CONFIG_ANON_VMA_NAME, Ruby labels the region via prctl(PR_SET_VMA)
1293+
// giving it a path like "[anon:Ruby:rb_yjit_reserve_addr_space]".
1294+
// On systems without that config, we fall back to a heuristic: the first anonymous
1295+
// executable mapping (by address) is assumed to be the JIT region since YJIT
1296+
// initializes before any gems could create anonymous executable mappings.
1297+
// Returns (start, end, found).
1298+
func findJITRegion(mappings []process.RawMapping) (uint64, uint64, bool) {
1299+
var jitStart, jitEnd uint64
1300+
labelFound := false
1301+
var heuristicStart, heuristicEnd uint64
1302+
heuristicFound := false
1303+
1304+
for idx := range mappings {
1305+
m := &mappings[idx]
1306+
1307+
// Check for prctl-labeled JIT region. These mappings may be ---p (PROT_NONE)
1308+
// or r-xp depending on whether YJIT has activated codepages in this region.
1309+
if strings.Contains(m.Path, "jit_reserve_addr_space") {
1310+
if !labelFound || m.Vaddr < jitStart {
1311+
jitStart = m.Vaddr
1312+
}
1313+
if !labelFound || m.Vaddr+m.Length > jitEnd {
1314+
jitEnd = m.Vaddr + m.Length
1315+
}
1316+
labelFound = true
1317+
continue
1318+
}
1319+
1320+
// Heuristic fallback: first anonymous executable mapping by address.
1321+
// Mappings from /proc/pid/maps are sorted by address, so the first
1322+
// match is the lowest address.
1323+
if !heuristicFound && m.IsExecutable() && m.IsAnonymous() {
1324+
heuristicStart = m.Vaddr
1325+
heuristicEnd = m.Vaddr + m.Length
1326+
heuristicFound = true
1327+
}
1328+
}
1329+
1330+
if labelFound {
1331+
return jitStart, jitEnd, true
1332+
}
1333+
if heuristicFound {
1334+
return heuristicStart, heuristicEnd, true
1335+
}
1336+
return 0, 0, false
1337+
}
1338+
12891339
func hasJitFramePointers(pr process.Process) bool {
12901340
machine := pr.GetMachineData().Machine
12911341
if machine == elf.EM_AARCH64 {
@@ -1310,33 +1360,7 @@ func (r *rubyInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler,
13101360

13111361
log.Debugf("Synchronizing ruby mappings")
13121362

1313-
// First pass: detect JIT bounds from ALL mappings (including non-executable).
1314-
// Ruby reserves a large address range for JIT code via mmap and labels it with
1315-
// prctl(PR_SET_VMA), giving it a path like "[anon:Ruby:rb_jit_reserve_addr_space]".
1316-
// The reserved region is typically ---p (non-executable). Ruby then mprotects individual
1317-
// pages to r-xp as JIT code is compiled. We need the full reserved region bounds for
1318-
// jit_start/jit_end so the eBPF program can recognize any PC within the JIT range,
1319-
// even as new pages are made executable.
1320-
var jitStart, jitEnd uint64
1321-
jitFound := false
1322-
for idx := range mappings {
1323-
m := &mappings[idx]
1324-
if strings.Contains(m.Path, "jit_reserve_addr_space") {
1325-
if !jitFound || m.Vaddr < jitStart {
1326-
jitStart = m.Vaddr
1327-
}
1328-
if !jitFound || m.Vaddr+m.Length > jitEnd {
1329-
jitEnd = m.Vaddr + m.Length
1330-
}
1331-
jitFound = true
1332-
}
1333-
}
1334-
1335-
// Second pass: register LPM prefixes for executable anonymous/JIT mappings.
1336-
// This only covers r-xp pages so the eBPF unwinder is invoked for JIT code that
1337-
// has actually been committed. If no labeled JIT region was found above, fall back
1338-
// to heuristic detection from executable anonymous mappings.
1339-
var heuristicJitMapping *process.RawMapping
1363+
// Register LPM prefixes for executable anonymous mappings.
13401364
for idx := range mappings {
13411365
m := &mappings[idx]
13421366
if !m.IsExecutable() || !m.IsAnonymous() {

support/ebpf/tracer.ebpf.amd64

15.5 KB
Binary file not shown.

support/ebpf/tracer.ebpf.arm64

15.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)