Skip to content

Commit 222e3a4

Browse files
committed
Test flf trampoline
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
1 parent efd9fb9 commit 222e3a4

File tree

6 files changed

+147
-3
lines changed

6 files changed

+147
-3
lines changed

Cargo.lock

Lines changed: 39 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

profiling/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ cfg-if = { version = "1.0" }
2222
cpu-time = { version = "1.0" }
2323
chrono = { version = "0.4" }
2424
crossbeam-channel = { version = "0.5", default-features = false, features = ["std"] }
25+
dynasmrt = "2.0"
2526
libdd-alloc = { git = "https://github.com/DataDog/libdatadog", tag = "v25.0.0" }
2627
libdd-profiling = { git = "https://github.com/DataDog/libdatadog", tag = "v25.0.0" }
2728
libdd-common = { git = "https://github.com/DataDog/libdatadog", tag = "v25.0.0" }

profiling/build.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ fn main() {
3737
let post_startup_cb = cfg_post_startup_cb(vernum);
3838
let preload = cfg_preload(vernum);
3939
let fibers = cfg_fibers(vernum);
40+
let frameless = cfg_frameless(vernum);
4041
let run_time_cache = cfg_run_time_cache(vernum);
4142
let trigger_time_sample = cfg_trigger_time_sample();
4243
let zend_error_observer = cfg_zend_error_observer(vernum);
@@ -48,6 +49,7 @@ fn main() {
4849
preload,
4950
run_time_cache,
5051
fibers,
52+
frameless,
5153
trigger_time_sample,
5254
zend_error_observer,
5355
);
@@ -103,6 +105,7 @@ fn build_zend_php_ffis(
103105
preload: bool,
104106
run_time_cache: bool,
105107
fibers: bool,
108+
frameless: bool,
106109
trigger_time_sample: bool,
107110
zend_error_observer: bool,
108111
) {
@@ -143,6 +146,7 @@ fn build_zend_php_ffis(
143146
let post_startup_cb = if post_startup_cb { "1" } else { "0" };
144147
let preload = if preload { "1" } else { "0" };
145148
let fibers = if fibers { "1" } else { "0" };
149+
let frameless = if frameless { "1" } else { "0" };
146150
let run_time_cache = if run_time_cache { "1" } else { "0" };
147151
let trigger_time_sample = if trigger_time_sample { "1" } else { "0" };
148152
let zend_error_observer = if zend_error_observer { "1" } else { "0" };
@@ -159,6 +163,7 @@ fn build_zend_php_ffis(
159163
.define("CFG_POST_STARTUP_CB", post_startup_cb)
160164
.define("CFG_PRELOAD", preload)
161165
.define("CFG_FIBERS", fibers)
166+
.define("CFG_FRAMELESS", frameless)
162167
.define("CFG_RUN_TIME_CACHE", run_time_cache)
163168
.define("CFG_STACK_WALKING_TESTS", stack_walking_tests)
164169
.define("CFG_TRIGGER_TIME_SAMPLE", trigger_time_sample)
@@ -394,6 +399,18 @@ fn cfg_fibers(vernum: u64) -> bool {
394399
}
395400
}
396401

402+
fn cfg_frameless(vernum: u64) -> bool {
403+
if has_check_cfg() {
404+
println!("cargo::rustc-check-cfg=cfg(php_frameless)");
405+
}
406+
if vernum >= 80400 {
407+
println!("cargo:rustc-cfg=php_frameless");
408+
true
409+
} else {
410+
false
411+
}
412+
}
413+
397414
fn cfg_php_feature_flags(vernum: u64) {
398415
if has_check_cfg() {
399416
println!("cargo::rustc-check-cfg=cfg(php_gc_status, php_zend_compile_string_has_position, php_gc_status_extended, php_frameless, php_opcache_restart_hook, php_zend_mm_set_custom_handlers_ex)");
@@ -409,7 +426,6 @@ fn cfg_php_feature_flags(vernum: u64) {
409426
println!("cargo:rustc-cfg=php_gc_status_extended");
410427
}
411428
if vernum >= 80400 {
412-
println!("cargo:rustc-cfg=php_frameless");
413429
println!("cargo:rustc-cfg=php_opcache_restart_hook");
414430
println!("cargo:rustc-cfg=php_zend_mm_set_custom_handlers_ex");
415431
}

profiling/src/php_ffi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ static post_startup_cb_result ddog_php_prof_post_startup_cb(void) {
117117
return FAILURE;
118118
}
119119
}
120+
121+
#if CFG_FRAMELESS
122+
ddog_php_prof_post_startup();
123+
#endif
120124

121125
_is_post_startup = true;
122126

profiling/src/php_ffi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ void ddog_php_prof_zend_mm_set_custom_handlers(zend_mm_heap *heap,
147147

148148
zend_execute_data* ddog_php_prof_get_current_execute_data();
149149

150+
#if CFG_FRAMELESS
151+
void ddog_php_prof_post_startup();
152+
#endif
153+
150154
#if CFG_FIBERS
151155
zend_fiber* ddog_php_prof_get_active_fiber();
152156
zend_fiber* ddog_php_prof_get_active_fiber_test();

profiling/src/wall_time.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,88 @@ pub extern "C" fn ddog_php_prof_interrupt_function(execute_data: *mut zend_execu
137137
}
138138
}
139139

140+
#[cfg(php_frameless)]
141+
mod frameless {
142+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
143+
use crate::bindings::{zend_flf_functions, zend_flf_handlers};
144+
145+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
146+
mod trampoline {
147+
use crate::wall_time::ddog_php_prof_interrupt_function;
148+
#[cfg(target_arch = "aarch64")]
149+
use dynasmrt::aarch64::Assembler;
150+
#[cfg(target_arch = "x86_64")]
151+
use dynasmrt::x64::Assembler;
152+
use dynasmrt::{dynasm, DynasmApi};
153+
use std::ffi::c_void;
154+
155+
pub unsafe fn generate_wrapper(original: *mut c_void) -> *mut c_void {
156+
let mut assembler = Assembler::new().unwrap();
157+
let interrupt_addr = ddog_php_prof_interrupt_function as *const () as i64;
158+
#[cfg(target_arch = "aarch64")]
159+
dynasm!(assembler
160+
; mov x16, original as i64
161+
; blr x16
162+
; mov x0, 0
163+
; mov x16, interrupt_addr
164+
; blr x16
165+
; ret
166+
);
167+
#[cfg(target_arch = "x86_64")]
168+
dynasm!(assembler
169+
; mov rax, QWORD original as i64
170+
; call rax
171+
; mov rdi, 0
172+
; mov rax, QWORD interrupt_addr
173+
; call rax
174+
; ret
175+
);
176+
let buffer = assembler.finalize().unwrap();
177+
let ptr = buffer.as_ptr() as *mut c_void;
178+
std::mem::forget(buffer); // TODO: leaks memory
179+
ptr
180+
}
181+
}
182+
183+
#[no_mangle]
184+
pub unsafe extern "C" fn ddog_php_prof_post_startup() {
185+
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
186+
{
187+
let mut i = 0;
188+
loop {
189+
let original = *zend_flf_handlers.add(i);
190+
if original.is_null() {
191+
break;
192+
}
193+
let wrapper = trampoline::generate_wrapper(original);
194+
*zend_flf_handlers.add(i) = wrapper;
195+
let func = &mut **zend_flf_functions.add(i);
196+
let original_info = (*func).internal_function.frameless_function_infos;
197+
let mut infos = Vec::new();
198+
let mut ptr = original_info;
199+
loop {
200+
let info = *ptr;
201+
if info.handler.is_null() {
202+
break;
203+
}
204+
infos.push(info);
205+
ptr = ptr.add(1);
206+
}
207+
for info in infos.iter_mut() {
208+
if info.handler == original {
209+
info.handler = wrapper;
210+
}
211+
}
212+
infos.push(crate::bindings::zend_frameless_function_info { handler: std::ptr::null_mut(), num_args: 0 });
213+
let new_infos = infos.into_boxed_slice();
214+
(*func).internal_function.frameless_function_infos = new_infos.as_ptr() as *mut _;
215+
std::mem::forget(new_infos); // TODO: leaks memory
216+
i += 1;
217+
}
218+
}
219+
}
220+
}
221+
140222
/// A wrapper for the `ddog_php_prof_interrupt_function` to call the
141223
/// previous interrupt handler, if there was one.
142224
#[no_mangle]

0 commit comments

Comments
 (0)