macro_rules! ruby_version_v_1_9_1(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_thread_struct);
get_execution_context_from_thread!(rb_thread_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_cfps!();
get_pos!(rb_iseq_struct);
get_lineno_1_9_0!();
get_stack_frame_1_9_1!();
stack_field_1_9_0!();
get_thread_status_1_9_0!();
get_thread_id_1_9_0!();
get_cfunc_name_unsupported!();
}
)
);
macro_rules! ruby_version_v_1_9_2_to_3(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_thread_struct);
get_execution_context_from_thread!(rb_thread_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_cfps!();
get_pos!(rb_iseq_struct);
get_lineno_1_9_0!();
get_stack_frame_1_9_2!();
stack_field_1_9_0!();
get_thread_status_1_9_0!();
get_thread_id_1_9_0!();
get_cfunc_name_unsupported!();
}
)
);
macro_rules! ruby_version_v_2_0_to_2_2(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_thread_struct);
get_execution_context_from_thread!(rb_thread_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_cfps!();
get_pos!(rb_iseq_struct);
get_lineno_2_0_0!();
get_stack_frame_2_0_0!();
stack_field_1_9_0!();
get_thread_status_1_9_0!();
get_thread_id_1_9_0!();
get_cfunc_name_unsupported!();
}
)
);
macro_rules! ruby_version_v_2_3_to_2_4(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_thread_struct);
get_execution_context_from_thread!(rb_thread_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_3_0!();
get_stack_frame_2_3_0!();
stack_field_1_9_0!();
get_thread_status_1_9_0!();
get_thread_id_1_9_0!();
get_cfunc_name_unsupported!();
}
)
);
macro_rules! ruby_version_v2_5_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
get_execution_context_from_thread!(rb_execution_context_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_5_0!();
get_stack_frame_2_5_0!();
stack_field_2_5_0!();
get_ruby_string_array_2_5_0!();
get_thread_status_2_5_0!();
get_thread_id_2_5_0!();
#[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "windows"))]
get_cfunc_name_unsupported!();
#[cfg(target_os = "linux")]
get_cfunc_name!();
#[cfg(target_os = "linux")]
get_classpath_unsupported!();
}
)
);
macro_rules! ruby_version_v2_6_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
get_execution_context_from_thread!(rb_execution_context_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_ruby_string_array_2_5_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_2_5_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_2_5_0!();
#[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "windows"))]
get_cfunc_name_unsupported!();
#[cfg(target_os = "linux")]
get_cfunc_name!();
#[cfg(target_os = "linux")]
get_classpath_unsupported!();
}
)
);
macro_rules! ruby_version_v2_7_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
get_execution_context_from_thread!(rb_execution_context_struct);
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_ruby_string_array_2_5_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_2_5_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_2_5_0!();
get_cfunc_name!();
get_classpath_unsupported!();
}
)
);
macro_rules! ruby_version_v3_0_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
ec_search_start_offset_3_0_0!();
get_execution_context_from_vm!();
rstring_as_array_1_9_1!();
get_ruby_string_1_9_1!();
get_ruby_string_array_2_5_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_2_5_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_2_5_0!();
get_cfunc_name!();
#[allow(non_upper_case_globals)]
const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
get_classpath_unsupported!();
}
)
);
macro_rules! ruby_version_v3_1_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
ec_search_start_offset_3_0_0!();
get_execution_context_from_vm!();
rstring_as_array_3_1_0!();
get_ruby_string_1_9_1!();
get_ruby_string_array_2_5_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_2_5_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_2_5_0!();
get_cfunc_name!();
#[allow(non_upper_case_globals)]
const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
get_classpath_unsupported!();
}
)
);
macro_rules! ruby_version_v3_2_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
ec_search_start_offset_3_0_0!();
get_execution_context_from_vm!();
get_ruby_string_3_2_0!();
get_ruby_string_array_3_2_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_2_5_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_3_2_0!();
get_cfunc_name!();
#[allow(non_upper_case_globals)]
const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
get_classpath_unsupported!();
}
)
);
macro_rules! ruby_version_v3_3_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
ec_search_start_offset_3_0_0!();
get_execution_context_from_vm!();
get_ruby_string_3_3_0!();
get_ruby_string_array_3_2_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_3_3_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_3_2_0!();
get_cfunc_name!();
#[allow(non_upper_case_globals)]
const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
get_classpath!();
rb_class_real_3_0_0!();
}
)
);
macro_rules! ruby_version_v4_0_x(
($ruby_version:ident) => (
pub mod $ruby_version {
use std;
use anyhow::{Context, format_err, Result};
use bindings::$ruby_version::*;
use crate::core::process::ProcessMemory;
get_stack_trace!(rb_execution_context_struct);
ec_search_start_offset_4_0_0!();
get_execution_context_from_vm!();
get_ruby_string_3_3_0!();
get_ruby_string_array_3_2_0!();
get_cfps!();
get_pos!(rb_iseq_constant_body);
get_lineno_2_6_0!();
get_stack_frame_3_3_0!();
stack_field_2_5_0!();
get_thread_status_2_6_0!();
get_thread_id_3_2_0!();
get_cfunc_name!();
#[allow(non_upper_case_globals)]
const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
get_classpath!();
rb_class_real_4_0_0!();
}
)
);
macro_rules! get_execution_context_from_thread(
($thread_type:ident) => (
pub fn get_execution_context<T: ProcessMemory>(
current_thread_address_ptr: usize,
_ruby_vm_address_ptr: usize,
source: &T
) -> Result<usize> {
source.copy_struct(current_thread_address_ptr)
.context("couldn't read current thread pointer")
}
)
);
macro_rules! ec_search_start_offset_3_0_0(
() => (
pub fn ec_search_start_offset() -> usize {
return
if cfg!(target_os = "windows") {
32
} else {
48
};
}
)
);
macro_rules! ec_search_start_offset_4_0_0(
() => (
pub fn ec_search_start_offset() -> usize {
return
if cfg!(target_os = "windows") {
30
} else {
38
};
}
)
);
macro_rules! get_execution_context_from_vm(
() => (
pub fn get_execution_context<T: ProcessMemory>(
_current_thread_address_ptr: usize,
ruby_vm_address_ptr: usize,
source: &T
) -> Result<usize> {
let vm_addr: usize = source.copy_struct(ruby_vm_address_ptr)
.context("couldn't read Ruby VM pointer")?;
let vm: rb_vm_struct = source.copy_struct(vm_addr as usize)
.context("couldn't read Ruby VM struct")?;
const ADDRESSES_TO_CHECK: usize = 32;
let offset = ec_search_start_offset() * std::mem::size_of::<usize>();
let main_ractor_address = vm.ractor.main_ractor as usize;
let candidate_addresses: [usize; ADDRESSES_TO_CHECK] =
source.copy_struct(main_ractor_address + offset)
.context("couldn't read main ractor struct")?;
candidate_addresses
.iter()
.enumerate()
.filter(|(idx, &addr)| *idx > 0 && addr == vm.ractor.main_thread as usize)
.map(|(idx, _)| candidate_addresses[idx - 1])
.filter(|&addr| addr != 0)
.filter(|&addr| source.copy_struct::<rb_execution_context_struct>(addr as usize).is_ok())
.collect::<Vec<usize>>()
.first()
.map(|&addr| addr as usize)
.ok_or_else(|| format_err!("couldn't find execution context"))
}
)
);
macro_rules! get_stack_trace(
($thread_type:ident) => (
use crate::core::process::Pid;
use crate::core::types::{StackFrame, StackTrace};
pub fn get_stack_trace<T: ProcessMemory>(
ruby_current_thread_address_location: usize,
ruby_vm_address_location: usize,
ruby_global_symbols_address_location: Option<usize>,
source: &T,
pid: Pid,
on_cpu: bool,
) -> Result<Option<StackTrace>, anyhow::Error> {
let current_thread_addr: usize = get_execution_context(ruby_current_thread_address_location, ruby_vm_address_location, source)
.context("couldn't get execution context")?;
let thread: $thread_type = source.copy_struct(current_thread_addr)
.context("couldn't get current thread")?;
if on_cpu && get_thread_status(&thread, source)? != 0 {
return Ok(None);
}
let thread_id = match get_thread_id(&thread, source) {
Ok(tid) => Some(tid),
Err(e) => {
debug!("Couldn't get thread ID: {}", e);
None
},
};
if stack_field(&thread) as usize == 0 {
return Ok(Some(StackTrace {
pid: Some(pid),
trace: vec!(StackFrame::unknown_c_function()),
thread_id: thread_id,
time: Some(SystemTime::now()),
on_cpu: None,
}));
}
let mut trace = Vec::new();
let cfps = get_cfps(thread.cfp as usize, stack_base(&thread) as usize, source)?;
for cfp in cfps.iter() {
let cfunc = ruby_frame_cfunc(&cfp, source)?;
if !cfunc && cfp.pc as usize != 0 {
let iseq_struct: rb_iseq_struct = source.copy_struct(cfp.iseq as usize)
.context("couldn't copy iseq struct")?;
let label_path = get_stack_frame(&iseq_struct, &cfp, source);
match label_path {
Ok(call) => trace.push(call),
Err(x) => {
debug!("Error: {:#?}", x);
debug!("cfp: {:?}", cfp);
debug!("thread: {:?}", thread);
debug!("iseq struct: {:?}", iseq_struct);
if trace.len() > 0 {
debug!("Skipping function call, possibly into C extension");
} else {
return Err(x);
}
}
}
} else {
let mut frame = StackFrame::unknown_c_function();
if let Some(global_symbols_addr) = ruby_global_symbols_address_location {
match get_cfunc_name(cfp, global_symbols_addr, source, pid) {
Ok(name) => {
frame = StackFrame{
name: format!("{} [c function]", name),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
};
},
Err(e) => {
debug!("Unknown C function: {:?}", e);
}
}
}
trace.push(frame);
continue;
}
}
let thread_id = match get_thread_id(&thread, source) {
Ok(tid) => Some(tid),
Err(e) => {
debug!("Couldn't get thread ID: {}", e);
None
},
};
Ok(Some(StackTrace{trace, pid: Some(pid), thread_id, time: Some(SystemTime::now()), on_cpu: Some(on_cpu)}))
}
use proc_maps::{maps_contain_addr, MapRange};
use std::time::SystemTime;
fn could_be_thread(thread: &$thread_type, all_maps: &[MapRange]) -> bool {
maps_contain_addr(thread.tag as usize, all_maps) &&
maps_contain_addr(thread.cfp as usize, all_maps) &&
maps_contain_addr(stack_field(thread) as usize, all_maps) &&
stack_size_field(thread) < 3_000_000
}
fn stack_base(thread: &$thread_type) -> i64 {
stack_field(thread) + (stack_size_field(thread) * std::mem::size_of::<VALUE>() as i64) - (1 * std::mem::size_of::<rb_control_frame_t>() as i64)
}
pub fn is_maybe_thread<T>(candidate_thread_addr: usize, candidate_thread_addr_ptr: usize, source: &T, all_maps: &[MapRange]) -> bool where T: ProcessMemory {
if !maps_contain_addr(candidate_thread_addr, all_maps) {
return false;
}
let thread: $thread_type = match source.copy_struct(candidate_thread_addr) {
Ok(x) => x,
_ => { return false; },
};
if !could_be_thread(&thread, &all_maps) {
return false;
}
get_stack_trace(candidate_thread_addr_ptr, 0, None, source, 0, false).is_ok()
}
)
);
macro_rules! stack_field_1_9_0(
() => (
fn stack_field(thread: &rb_thread_struct) -> i64 {
thread.stack as i64
}
fn stack_size_field(thread: &rb_thread_struct) -> i64 {
thread.stack_size as i64
}
)
);
macro_rules! stack_field_2_5_0(
() => (
fn stack_field(thread: &rb_execution_context_struct) -> i64 {
thread.vm_stack as i64
}
fn stack_size_field(thread: &rb_execution_context_struct) -> i64 {
thread.vm_stack_size as i64
}
)
);
macro_rules! get_thread_status_1_9_0(
() => (
fn get_thread_status<T>(thread_struct: &rb_thread_struct, _source: &T) -> Result<u32> {
Ok(thread_struct.status as u32)
}
)
);
macro_rules! get_thread_status_2_5_0(
() => (
fn get_thread_status<T>(thread_struct: &rb_execution_context_struct, source: &T)
-> Result<u32> where T: ProcessMemory {
let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
.context(thread_struct.thread_ptr as usize)?;
Ok(thread.status as u32)
}
)
);
macro_rules! get_thread_status_2_6_0(
() => (
fn get_thread_status<T>(thread_struct: &rb_execution_context_struct, source: &T)
-> Result<u32> where T: ProcessMemory {
let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
.context(thread_struct.thread_ptr as usize)?;
Ok(thread.status() as u32)
}
)
);
macro_rules! get_thread_id_1_9_0(
() => (
fn get_thread_id<T>(thread_struct: &rb_thread_struct, _source: &T) -> Result<usize> {
Ok(thread_struct.thread_id as usize)
}
)
);
macro_rules! get_thread_id_2_5_0(
() => (
fn get_thread_id<T>(thread_struct: &rb_execution_context_struct, source: &T)
-> Result<usize> where T: ProcessMemory {
let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
.context("couldn't copy thread struct")?;
Ok(thread.thread_id as usize)
}
)
);
macro_rules! get_thread_id_3_2_0(
() => (
fn get_thread_id<T>(thread_struct: &rb_execution_context_struct, source: &T)
-> Result<usize> where T: ProcessMemory {
let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
.context("couldn't copy thread struct")?;
if thread.nt.is_null() {
return Err(format_err!("native thread pointer is NULL"));
}
let native_thread: rb_native_thread = source.copy_struct(thread.nt as usize)
.context("couldn't copy native thread struct")?;
Ok(native_thread.thread_id as usize)
}
)
);
macro_rules! get_ruby_string_array_2_5_0(
() => (
fn get_ruby_string_array<T>(addr: usize, string_class: usize, source: &T) -> Result<(String, String)> where T: ProcessMemory {
let rstring: RString = source.copy_struct(addr).context("couldn't copy RString")?;
if rstring.basic.klass as usize == string_class {
let s = get_ruby_string(addr, source)?;
return Ok((s.clone(), s))
}
let rarray: RArray = source.copy_struct(addr).context("couldn't copy RArray")?;
let path_addr: usize = unsafe { rarray.as_.ary[0] as usize }; let abs_path_addr: usize = unsafe { rarray.as_.ary[1] as usize }; let rel_path = get_ruby_string(path_addr, source)?;
let abs_path = get_ruby_string(abs_path_addr, source)
.unwrap_or(String::from("unknown"));
Ok((rel_path, abs_path))
}
)
);
macro_rules! get_ruby_string_array_3_2_0(
() => (
fn get_ruby_string_array<T>(addr: usize, string_class: usize, source: &T) -> Result<(String, String)> where T: ProcessMemory {
let rstring: RString = source.copy_struct(addr).context("couldn't copy RString")?;
if rstring.basic.klass as usize == string_class {
let s = get_ruby_string(addr, source)?;
return Ok((s.clone(), s))
}
#[repr(C)]
#[derive(Copy, Clone)]
struct PaddedRArray {
pub basic: RBasic,
pub as_: PaddedRArray__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
union PaddedRArray__bindgen_ty_1 {
pub heap: RArray__bindgen_ty_1__bindgen_ty_1,
pub ary: [VALUE; 2usize],
}
let rarray: PaddedRArray = source.copy_struct(addr).context("couldn't copy RArray")?;
let path_addr: usize = unsafe { rarray.as_.ary[0] as usize }; let abs_path_addr: usize = unsafe { rarray.as_.ary[1] as usize };
let rel_path = get_ruby_string(path_addr, source)?;
let abs_path = get_ruby_string(abs_path_addr, source)
.unwrap_or(String::from("unknown"));
Ok((rel_path, abs_path))
}
)
);
macro_rules! rstring_as_array_1_9_1(
() => (
unsafe fn rstring_as_array(rstring: RString) -> [::std::os::raw::c_char; 24usize] {
rstring.as_.ary
}
)
);
macro_rules! rstring_as_array_3_1_0(
() => (
unsafe fn rstring_as_array(rstring: RString) -> [::std::os::raw::c_char; 24usize] {
rstring.as_.embed.ary
}
)
);
macro_rules! get_ruby_string_1_9_1(
() => (
fn get_ruby_string<T>(
addr: usize,
source: &T
) -> Result<String> where T: ProcessMemory {
let vec = {
let rstring: RString = source.copy_struct(addr).context("couldn't copy rstring")?;
let is_embedded_string = rstring.basic.flags & 1 << 13 == 0;
if is_embedded_string {
unsafe { std::ffi::CStr::from_ptr(rstring_as_array(rstring).as_ref().as_ptr()) }
.to_bytes()
.to_vec()
} else {
unsafe {
let addr = rstring.as_.heap.ptr as usize;
let len = rstring.as_.heap.len as usize;
source.copy(addr as usize, len).context("couldn't copy ruby string from heap")?
}
}
};
String::from_utf8(vec).context("couldn't convert ruby string bytes to string")
}
)
);
macro_rules! get_ruby_string_3_2_0(
() => (
fn get_ruby_string<T>(
addr: usize,
source: &T
) -> Result<String> where T: ProcessMemory {
let rstring: RString = source.copy_struct(addr).context("couldn't copy rstring")?;
let is_embedded_string = rstring.basic.flags & 1 << 13 == 0;
if is_embedded_string {
#[cfg(target_os = "windows")]
let addr = addr + 4;
let embedded_str_bytes = source.copy(
addr + std::mem::size_of::<RBasic>() + std::mem::size_of::<std::os::raw::c_long>(),
unsafe { rstring.as_.embed.len } as usize
).context("couldn't copy rstring")?;
return String::from_utf8(embedded_str_bytes).context("couldn't convert ruby string bytes to string")
} else {
unsafe {
let addr = rstring.as_.heap.ptr as usize;
let len = rstring.as_.heap.len as usize;
let heap_str_bytes = source.copy(addr as usize, len).context("couldn't copy ruby string from heap")?;
return String::from_utf8(heap_str_bytes).context("couldn't convert ruby string bytes to string");
}
}
}
)
);
macro_rules! get_ruby_string_3_3_0(
() => (
fn get_ruby_string<T>(
addr: usize,
source: &T
) -> Result<String> where T: ProcessMemory {
let rstring: RString = source.copy_struct(addr).context("couldn't copy rstring")?;
if rstring.len > 1_000_000 {
return Err(anyhow::anyhow!("string length {} for string at {:X} appears invalid", rstring.len, addr));
}
let is_embedded_string = rstring.basic.flags & 1 << 13 == 0;
if is_embedded_string {
#[cfg(target_os = "windows")]
let addr = addr + 4;
let embedded_str_bytes = source.copy(
addr + std::mem::size_of::<RBasic>() + std::mem::size_of::<std::os::raw::c_long>(),
rstring.len as usize
).context("couldn't copy rstring")?;
return String::from_utf8(embedded_str_bytes).context("couldn't convert ruby string bytes to string")
} else {
unsafe {
let addr = rstring.as_.heap.ptr as usize;
let len = rstring.len as usize;
let heap_str_bytes = source.copy(addr as usize, len).context("couldn't copy ruby string from heap")?;
return String::from_utf8(heap_str_bytes).context("couldn't convert ruby string bytes to string");
}
}
}
)
);
macro_rules! get_stack_frame_1_9_1(
() => (
fn get_stack_frame<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<StackFrame> where T: ProcessMemory {
Ok(StackFrame{
name: get_ruby_string(iseq_struct.name as usize, source)?,
relative_path: get_ruby_string(iseq_struct.filename as usize, source)?,
absolute_path: None,
lineno: match get_lineno(iseq_struct, cfp, source) {
Ok(lineno) => Some(lineno),
Err(e) => {
warn!("couldn't get lineno: {}", e);
None
},
}
})
}
)
);
macro_rules! get_stack_frame_1_9_2(
() => (
fn get_stack_frame<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<StackFrame> where T: ProcessMemory {
Ok(StackFrame{
name: get_ruby_string(iseq_struct.name as usize, source)?,
relative_path: get_ruby_string(iseq_struct.filename as usize, source)?,
absolute_path: Some(get_ruby_string(iseq_struct.filepath as usize, source)?),
lineno: match get_lineno(iseq_struct, cfp, source) {
Ok(lineno) => Some(lineno),
Err(e) => {
warn!("couldn't get lineno: {}", e);
None
},
}
})
}
)
);
macro_rules! get_stack_frame_2_0_0(
() => (
fn get_stack_frame<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<StackFrame> where T: ProcessMemory {
Ok(StackFrame{
name: get_ruby_string(iseq_struct.location.label as usize, source)?,
relative_path: get_ruby_string(iseq_struct.location.path as usize, source)?,
absolute_path: Some(get_ruby_string(iseq_struct.location.absolute_path as usize, source)?),
lineno: match get_lineno(iseq_struct, cfp, source) {
Ok(lineno) => Some(lineno),
Err(e) => {
warn!("couldn't get lineno: {}", e);
None
},
}
})
}
)
);
macro_rules! get_stack_frame_2_3_0(
() => (
fn get_stack_frame<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<StackFrame> where T: ProcessMemory {
let body: rb_iseq_constant_body = source.copy_struct(iseq_struct.body as usize)
.context(iseq_struct.body as usize)?;
Ok(StackFrame{
name: get_ruby_string(body.location.label as usize, source)?,
relative_path: get_ruby_string(body.location.path as usize, source)?,
absolute_path: Some(get_ruby_string(body.location.absolute_path as usize, source)?),
lineno: match get_lineno(&body, cfp, source) {
Ok(lineno) => Some(lineno),
Err(e) => {
warn!("couldn't get lineno: {}", e);
None
},
}
})
}
)
);
macro_rules! get_stack_frame_2_5_0(
() => (
fn get_stack_frame<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<StackFrame> where T: ProcessMemory {
if iseq_struct.body == std::ptr::null_mut() {
return Err(format_err!("iseq body is null"));
}
let body: rb_iseq_constant_body = source.copy_struct(iseq_struct.body as usize)
.context("couldn't copy rb_iseq_constant_body")?;
let rstring: RString = source.copy_struct(body.location.label as usize)
.context("couldn't copy RString")?;
let (path, absolute_path) = get_ruby_string_array(
body.location.pathobj as usize,
rstring.basic.klass as usize,
source
).context("couldn't get ruby string from iseq body")?;
Ok(StackFrame{
name: get_ruby_string(body.location.label as usize, source)?,
relative_path: path,
absolute_path: Some(absolute_path),
lineno: match get_lineno(&body, cfp, source) {
Ok(lineno) => Some(lineno),
Err(e) => {
warn!("couldn't get lineno: {}", e);
None
},
}
})
}
)
);
macro_rules! get_classpath_unsupported(
() => (
fn get_classpath<T>(
_cme: usize,
_cfunc: bool,
_source: &T,
) -> Result<(String, bool)> where T: ProcessMemory {
return Err(format_err!("classpath resolution is not supported for this version of Ruby").into());
}
)
);
macro_rules! rb_class_real_3_0_0(
() => (
fn rb_class_real<T>(
klass: usize,
source: &T,
) -> Result<usize> where T: ProcessMemory {
const RUBY_T_ICLASS: usize = 0x1c;
const RUBY_FL_SINGLETON: usize = ruby_fl_type_RUBY_FL_USER1 as usize;
let mut klass = klass;
let mut rbasic: RBasic = source.copy_struct(klass).context(klass)?;
while (rbasic.flags & (RUBY_T_ICLASS | RUBY_FL_SINGLETON) != 0) {
let rclass: RClass = source.copy_struct(klass).context(klass)?;
klass = rclass.super_;
rbasic = source.copy_struct(klass).context(klass)?;
}
Ok(klass)
}
)
);
macro_rules! rb_class_real_4_0_0(
() => (
fn rb_class_real<T>(
klass: usize,
source: &T,
) -> Result<usize> where T: ProcessMemory {
const RUBY_T_ICLASS: usize = 0x1c;
const RUBY_FL_SINGLETON: usize = ruby_fl_type_RUBY_FL_USER1 as usize;
let mut klass = klass;
let mut rbasic: RBasic = source.copy_struct(klass).context(klass)?;
while (rbasic.flags & (RUBY_T_ICLASS | RUBY_FL_SINGLETON) != 0) {
let rclass_ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
klass = rclass_ext.classext.super_;
rbasic = source.copy_struct(klass).context(klass)?;
}
Ok(klass)
}
)
);
macro_rules! get_classpath(
() => (
fn rb_tmp_class_path<T>(
klass: usize,
source: &T,
) -> Result<usize> where T: ProcessMemory {
const RUBY_T_MODULE: usize = 0x3;
const RUBY_T_MASK: usize = 0x1f;
let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
let mut path_addr = if ext.classext.classpath == 0 {
0x0f } else {
ext.classext.classpath
};
let rbasic: RBasic = source.copy_struct(klass).context(klass)?;
if rbasic.flags & RUBY_T_MASK == RUBY_T_MODULE {
let real_klass = rb_class_real(rbasic.klass, source)?;
let ext: RClass_and_rb_classext_t = source.copy_struct(real_klass).context(real_klass)?;
path_addr = if ext.classext.classpath != 0 {
let modstr = get_ruby_string(ext.classext.classpath as usize, source)?;
if modstr == "Module".to_string() {
0x00 } else {
rb_tmp_class_path(rbasic.klass, source)?
}
} else {
rb_tmp_class_path(rbasic.klass, source)?
}
}
return Ok(path_addr);
}
fn rb_class_path<T>(
klass: usize,
source: &T,
) -> Result<String> where T: ProcessMemory {
let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
if ext.classext.classpath != 0 {
return get_ruby_string(ext.classext.classpath as usize, source);
};
let path = rb_tmp_class_path(klass, source)?;
let path_fallback = match path {
0x0f => {
format!("#<Class:{:#08x}>", klass)
}
0x00 => {
format!("#<Module:{:#08x}>", klass)
}
_ => {
let path_str = get_ruby_string(path, source)?;
format!("#<{}:{:#08x}>", path_str, klass)
}
};
return Ok(path_fallback)
}
fn get_classpath<T>(
cme: usize,
cfunc: bool,
source: &T,
) -> Result<(String, bool)> where T: ProcessMemory {
const RUBY_T_CLASS: usize = 0x2;
const RUBY_T_MODULE: usize = 0x3;
const RUBY_T_ICLASS: usize = 0x1c;
const RUBY_T_MASK: usize = 0x1f;
const RUBY_FL_SINGLETON: usize = ruby_fl_type_RUBY_FL_USER1 as usize;
const RUBY_IMMEDIATE_MASK: usize = 0x07;
const RUBY_QNIL: usize = 0x04;
let mut singleton = false;
let imemo: rb_method_entry_struct = source.copy_struct(cme).context(cme)?;
let mut klass = if cfunc {
imemo.owner
} else {
imemo.defined_class
};
if klass == RUBY_QNIL {
return Ok(("".to_string(), false))
}
let rbasic: RBasic = source.copy_struct(klass).context(klass)?;
let class_flags = rbasic.flags;
let class_mask = class_flags & RUBY_T_MASK;
match class_mask {
RUBY_T_ICLASS => {
klass = rbasic.klass as usize;
}
_ => {
if class_flags & RUBY_FL_SINGLETON != 0 {
log::debug!("Got singleton class");
singleton = true;
let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
klass = unsafe {
ext.classext.as_.singleton_class.attached_object as usize
};
let rbasic: RBasic = source.copy_struct(klass).context(klass)?;
let class_flags = rbasic.flags;
let class_mask = class_flags & RUBY_T_MASK;
if class_mask != RUBY_T_CLASS && class_mask != RUBY_T_MODULE {
if (klass & RUBY_IMMEDIATE_MASK == 0) {
klass = rb_class_real(rbasic.klass, source)?;
let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
let class_path = get_ruby_string(ext.classext.classpath as usize, source)?;
return Ok((format!("#<{}:{:#08x}>", class_path, klass), singleton));
} else {
log::debug!("TODO: Immediate object case is unhandled!");
}
}
}
}
}
if klass == 0 {
return Err(anyhow::anyhow!("klass was empty"));
}
let class_path = rb_class_path(klass, source)?;
Ok((class_path, singleton))
}
pub fn profile_frame_full_label(
class_path: &str,
label: &str,
base_label: &str,
method_name: &str,
singleton: bool,
) -> String {
let qualified = qualified_method_name(class_path, method_name, singleton);
if qualified.is_empty() || qualified == base_label.to_string() {
return label.to_string();
}
let label_length = label.len();
let base_label_length = base_label.len();
let mut prefix_len = label_length.saturating_sub(base_label_length);
if prefix_len > label_length {
prefix_len = label_length;
}
let profile_label = format!("{}{}", &label[..prefix_len], qualified);
if profile_label.is_empty() {
return String::new();
}
profile_label
}
)
);
macro_rules! get_stack_frame_3_3_0(
() => (
fn get_stack_frame<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<StackFrame> where T: ProcessMemory {
let cme = locate_method_entry(&cfp.ep, source)?;
let mut class_path = "".to_string();
let mut singleton = false;
let iseq = if cme != 0 {
let imemo: rb_method_entry_struct = source.copy_struct(cme).context(cme)?;
let method_type = source.copy(imemo.def as usize, 1).context(imemo.def as usize)?;
let method_type = method_type[0] & 0xf;
if method_type == 0 {
(class_path, singleton) = get_classpath(cme, false, source)?;
let method_def: rb_method_definition_struct = source.copy_struct(imemo.def as usize).context(imemo.def as usize)?;
let iseq: rb_iseq_struct = unsafe {
source.copy_struct(method_def.body.iseq.iseqptr as usize).context("")?
};
iseq
} else {
*iseq_struct
}
} else {
*iseq_struct
};
if iseq_struct.body == std::ptr::null_mut() {
return Err(format_err!("iseq body is null"));
}
let body: rb_iseq_constant_body =
source.copy_struct(iseq.body as usize)
.context("couldn't copy rb_iseq_constant_body")?;
let frame_flag: usize = unsafe {
source.copy_struct(cfp.ep.offset(0) as usize).context(cfp.ep.offset(0) as usize)?
};
let rstring: RString = source.copy_struct(body.location.label as usize)
.context("couldn't copy RString")?;
let mut method_name = "".to_string();
if body.local_iseq != std::ptr::null_mut() {
let local_iseq: rb_iseq_t = source.copy_struct(body.local_iseq as usize)
.context("couldn't read local iseq")?;
if local_iseq.body != std::ptr::null_mut() {
let local_body: rb_iseq_constant_body = source.copy_struct(iseq_struct.body as usize)
.context("couldn't copy rb_iseq_constant_body")?;
method_name = get_ruby_string(local_body.location.base_label as usize, source)?;
}
}
let (path, absolute_path) = get_ruby_string_array(
body.location.pathobj as usize,
rstring.basic.klass as usize,
source
).context(format!("couldn't get ruby path string array from iseq body: {:X}", frame_flag)).unwrap_or(("FAILED".to_string(), "FAILED".to_string()));
let label = get_ruby_string(body.location.label as usize, source)?;
let base_label = get_ruby_string(body.location.base_label as usize, source)?;
let full_label = profile_frame_full_label(&class_path, &label, &base_label, &method_name, singleton);
Ok(StackFrame{
name: full_label,
relative_path: path,
absolute_path: Some(absolute_path),
lineno: match get_lineno(&body, cfp, source) {
Ok(lineno) => Some(lineno),
Err(e) => {
warn!("couldn't get lineno: {}", e);
None
},
}
})
}
)
);
macro_rules! get_pos(
($iseq_type:ident) => (
#[allow(unused)] fn get_pos(iseq_struct: &$iseq_type, cfp: &rb_control_frame_t) -> Result<usize> {
if (cfp.pc as usize) < (iseq_struct.iseq_encoded as usize) {
return Err(crate::core::types::MemoryCopyError::Message(format!("program counter and iseq are out of sync")).into());
}
let mut pos = cfp.pc as usize - iseq_struct.iseq_encoded as usize;
if pos != 0 {
pos -= 1;
}
Ok(pos)
}
)
);
macro_rules! get_lineno_1_9_0(
() => (
fn get_lineno<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<usize> where T: ProcessMemory {
let pos = get_pos(iseq_struct, cfp)?;
let t_size = iseq_struct.insn_info_size as usize;
if t_size == 0 {
Err(format_err!("line number is not available"))
} else if t_size == 1 {
let table: [iseq_insn_info_entry; 1] = source.copy_struct(iseq_struct.insn_info_table as usize)
.context("couldn't copy instruction table")?;
Ok(table[0].line_no as usize)
} else {
let table: Vec<iseq_insn_info_entry> = source.copy_vec(iseq_struct.insn_info_table as usize, t_size as usize)
.context("couldn't copy instruction table")?;
for i in 0..t_size {
if pos == table[i].position as usize {
return Ok(table[i].line_no as usize)
} else if table[i].position as usize > pos {
return Ok(table[i-1].line_no as usize)
}
}
Ok(table[t_size-1].line_no as usize)
}
}
)
);
macro_rules! get_lineno_2_0_0(
() => (
fn get_lineno<T>(
iseq_struct: &rb_iseq_struct,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<usize> where T: ProcessMemory {
let pos = get_pos(iseq_struct, cfp)?;
let t_size = iseq_struct.line_info_size as usize;
if t_size == 0 {
Err(format_err!("line number is not available"))
} else if t_size == 1 {
let table: [iseq_line_info_entry; 1] = source.copy_struct(iseq_struct.line_info_table as usize)
.context("couldn't copy instruction table")?;
Ok(table[0].line_no as usize)
} else {
let table: Vec<iseq_line_info_entry> = source.copy_vec(iseq_struct.line_info_table as usize, t_size as usize)
.context("couldn't copy instruction table")?;
for i in 0..t_size {
if pos == table[i].position as usize {
return Ok(table[i].line_no as usize)
} else if table[i].position as usize > pos {
return Ok(table[i-1].line_no as usize)
}
}
Ok(table[t_size-1].line_no as usize)
}
}
)
);
macro_rules! get_lineno_2_3_0(
() => (
fn get_lineno<T>(
iseq_struct: &rb_iseq_constant_body,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<usize> where T: ProcessMemory {
let pos = get_pos(iseq_struct, cfp)?;
let t_size = iseq_struct.line_info_size as usize;
if t_size == 0 {
Err(format_err!("line number is not available"))
} else if t_size == 1 {
let table: [iseq_line_info_entry; 1] = source.copy_struct(iseq_struct.line_info_table as usize)
.context("couldn't copy instruction table")?;
Ok(table[0].line_no as usize)
} else {
let table: Vec<iseq_line_info_entry> = source.copy_vec(iseq_struct.line_info_table as usize, t_size as usize)
.context("couldn't copy instruction table")?;
for i in 0..t_size {
if pos == table[i].position as usize {
return Ok(table[i].line_no as usize)
} else if table[i].position as usize > pos {
return Ok(table[i-1].line_no as usize)
}
}
Ok(table[t_size-1].line_no as usize)
}
}
)
);
macro_rules! get_lineno_2_5_0(
() => (
fn get_lineno<T>(
iseq_struct: &rb_iseq_constant_body,
cfp: &rb_control_frame_t,
source: &T,
) -> Result<usize> where T: ProcessMemory {
let pos = get_pos(iseq_struct, cfp)?;
let t_size = iseq_struct.insns_info_size as usize;
if t_size == 0 {
Err(format_err!("line number is not available"))
} else if t_size == 1 {
let table: [iseq_insn_info_entry; 1] = source.copy_struct(iseq_struct.insns_info as usize)
.context("couldn't copy instruction table")?;
Ok(table[0].line_no as usize)
} else {
let table: Vec<iseq_insn_info_entry> = source.copy_vec(iseq_struct.insns_info as usize, t_size as usize)
.context("couldn't copy instruction table")?;
for i in 0..t_size {
if pos == table[i].position as usize {
return Ok(table[i].line_no as usize)
} else if table[i].position as usize > pos {
return Ok(table[i-1].line_no as usize)
}
}
Ok(table[t_size-1].line_no as usize)
}
}
)
);
macro_rules! get_lineno_2_6_0(
() => (
fn get_lineno<T>(
iseq_struct: &rb_iseq_constant_body,
_cfp: &rb_control_frame_t,
source: &T,
) -> Result<usize> where T: ProcessMemory {
let t_size = iseq_struct.insns_info.size as usize;
if t_size == 0 {
Err(format_err!("line number is not available"))
} else if t_size == 1 {
let table: [iseq_insn_info_entry; 1] = source.copy_struct(iseq_struct.insns_info.body as usize)
.context("couldn't copy instruction table")?;
Ok(table[0].line_no as usize)
} else {
let table: Vec<iseq_insn_info_entry> = source.copy_vec(iseq_struct.insns_info.body as usize, t_size as usize)
.context(iseq_struct.insns_info.body as usize)?;
Ok(table[t_size-1].line_no as usize)
}
}
)
);
macro_rules! get_cfps(
() => (
fn get_cfps<T>(
cfp_address: usize,
stack_base: usize,
source: &T
) -> Result<Vec<rb_control_frame_t>> where T: ProcessMemory {
if (stack_base as usize) <= cfp_address {
return Err(crate::core::types::MemoryCopyError::Message(format!("stack base and cfp address out of sync. stack base: {:x}, cfp address: {:x}", stack_base as usize, cfp_address)).into());
}
let cfp_size = (stack_base as usize - cfp_address) as usize / std::mem::size_of::<rb_control_frame_t>();
if cfp_size > 1_000_000 {
return Err(crate::core::types::MemoryCopyError::Message(format!("invalid cfp vector length: {}", cfp_size)).into());
}
source.copy_vec(cfp_address, cfp_size).context("couldn't copy cfp vector")
}
)
);
macro_rules! get_cfunc_name_unsupported(
() => (
fn ruby_frame_cfunc<T>(
_cfp: &rb_control_frame_t,
_source: &T
) -> Result<bool> where T: ProcessMemory {
Ok(false)
}
fn get_cfunc_name<T: ProcessMemory>(_cfp: &rb_control_frame_t, _global_symbols_address: usize, _source: &T, _pid: Pid) -> Result<String> {
return Err(format_err!("C function resolution is not supported for this version of Ruby").into());
}
)
);
macro_rules! get_cfunc_name(
() => (
fn ruby_frame_cfunc<T>(
cfp: &rb_control_frame_t,
source: &T
) -> Result<bool> where T: ProcessMemory {
let frame_flag: usize = unsafe {
source.copy_struct(cfp.ep.offset(0) as usize).context(cfp.ep.offset(0) as usize)?
};
const VM_FRAME_MAGIC_CFUNC: usize = 0x55550001;
const VM_FRAME_MAGIC_MASK: usize = 0x7fff0001;
Ok((frame_flag & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_CFUNC)
}
pub fn qualified_method_name(class_path: &str, method_name: &str, singleton: bool) -> String {
if method_name.is_empty() {
return method_name.to_string();
}
if !class_path.is_empty() {
let join_char = if singleton { "." } else { "#" };
return format!("{}{}{}", class_path, join_char, method_name);
}
method_name.to_string()
}
fn locate_method_entry<T>(
ep: &*const usize,
source: &T,
) -> Result<usize> where T: ProcessMemory {
const VM_ENV_FLAG_LOCAL: usize = 0x2;
let mut ep = ep.clone() as *mut usize;
let mut env_flags: usize = source.copy_struct(ep as usize).context(ep as usize)?;
let mut env_specval: usize = unsafe {
source.copy_struct(ep.offset(-1) as usize).context(ep.offset(-1) as usize)?
};
let mut env_me_cref: usize = unsafe {
source.copy_struct(ep.offset(-2) as usize).context(ep.offset(-2) as usize)?
};
while env_flags & VM_ENV_FLAG_LOCAL != 0 {
let me = check_method_entry(env_me_cref, false, source)?;
if me != 0{
return Ok(me);
}
unsafe {
ep = (env_specval.clone() & !0x03) as *mut usize;
env_flags = source.copy_struct(ep as usize).context(ep as usize)?;
env_specval = source.copy_struct(ep.offset(-1) as usize).context(ep.offset(-1) as usize)?;
env_me_cref = source.copy_struct(ep.offset(-2) as usize).context(ep.offset(-2) as usize)?;
}
}
let me = check_method_entry(env_me_cref, true, source)?;
Ok(me)
}
fn check_method_entry<T: ProcessMemory>(
raw_imemo: usize,
can_be_svar: bool,
source: &T
) -> Result<usize> {
const IMEMO_MASK: usize = 0x0f;
if raw_imemo == 0 {
return Ok(0);
}
let imemo: rb_method_entry_struct = source.copy_struct(raw_imemo).context(raw_imemo)?;
#[allow(non_upper_case_globals)]
match ((imemo.flags >> ruby_fl_type_RUBY_FL_USHIFT) & IMEMO_MASK) as u32 {
imemo_type_imemo_ment => Ok(raw_imemo),
imemo_type_imemo_svar => {
if can_be_svar {
let svar: vm_svar = source.copy_struct(raw_imemo).context(raw_imemo)?;
check_method_entry(svar.cref_or_me as usize, false, source)
} else {
Ok(0)
}
},
_ => Ok(0)
}
}
fn get_cfunc_name<T: ProcessMemory>(
cfp: &rb_control_frame_t,
global_symbols_address: usize,
source: &T,
_pid: Pid
) -> Result<String> {
const IMEMO_MASK: usize = 0x0f;
let cme = locate_method_entry(&cfp.ep, source)?;
let (class_path, singleton) = get_classpath(cme, true, source).unwrap_or(("".to_string(), false));
let imemo: rb_method_entry_struct = source.copy_struct(cme).context(cme)?;
if imemo.def.is_null() {
return Err(format_err!("No method definition").into());
}
let ttype = ((imemo.flags >> ruby_fl_type_RUBY_FL_USHIFT) & IMEMO_MASK) as usize;
if ttype != imemo_type_imemo_ment as usize {
return Err(format_err!("Not a method entry").into());
}
#[allow(non_camel_case_types)]
type rb_id_serial_t = u32;
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct rb_symbols_t {
last_id: rb_id_serial_t,
str_sym: *mut st_table,
ids: VALUE,
dsymbol_fstr_hash: VALUE,
}
let global_symbols: rb_symbols_t = source.copy_struct(global_symbols_address as usize).context(global_symbols_address as usize)?;
let def: rb_method_definition_struct = source.copy_struct(imemo.def as usize).context(imemo.def as usize)?;
let method_id = def.original_id as usize;
let mut serial = method_id;
if method_id > ruby_method_ids_tLAST_OP_ID as usize {
serial = method_id >> ruby_id_types_RUBY_ID_SCOPE_SHIFT;
}
if serial > global_symbols.last_id as usize {
return Err(format_err!("Invalid method ID").into());
}
let id_entry_unit = 512;
let idx = serial / id_entry_unit;
let ids: RArray = source.copy_struct(global_symbols.ids as usize).context(global_symbols.ids as usize)?;
let flags = ids.basic.flags as usize;
let mut ids_ptr = unsafe { ids.as_.heap.ptr as usize };
let mut ids_len = unsafe { ids.as_.heap.len as usize };
if (flags & ruby_fl_type_RUBY_FL_USER1 as usize) > 0 {
ids_ptr = unsafe { ids.as_.ary[0] as usize };
ids_len = (flags & (ruby_fl_type_RUBY_FL_USER3|ruby_fl_type_RUBY_FL_USER4|ruby_fl_type_RUBY_FL_USER5|ruby_fl_type_RUBY_FL_USER6|ruby_fl_type_RUBY_FL_USER7|ruby_fl_type_RUBY_FL_USER8|ruby_fl_type_RUBY_FL_USER9) as usize) >> (ruby_fl_type_RUBY_FL_USHIFT+3);
}
if idx >= ids_len {
return Err(format_err!("Invalid index in IDs array").into());
}
let array_remote_ptr = (ids_ptr as usize) + (idx as usize) * std::mem::size_of::<usize>();
let array_ptr: usize = source.copy_struct(array_remote_ptr).context(array_remote_ptr)?;
let array: RArray = source.copy_struct(array_ptr).context(array_ptr)?;
let mut array_ptr = unsafe { array.as_.heap.ptr };
let flags = array.basic.flags as usize;
if (flags & ruby_fl_type_RUBY_FL_USER1 as usize) > 0 {
array_ptr = unsafe { &ids.as_.ary[0] };
}
let offset = (serial % 512) * 2;
let rstring_remote_ptr = (array_ptr as usize) + offset * std::mem::size_of::<usize>();
let rstring_ptr: usize = source.copy_struct(rstring_remote_ptr as usize).context(rstring_remote_ptr as usize)?;
let method_name = get_ruby_string(rstring_ptr as usize, source)?;
Ok(qualified_method_name(&class_path, &method_name, singleton))
}
)
);
ruby_version_v_1_9_1!(ruby_1_9_1_0);
ruby_version_v_1_9_2_to_3!(ruby_1_9_2_0);
ruby_version_v_1_9_2_to_3!(ruby_1_9_3_0);
ruby_version_v_2_0_to_2_2!(ruby_2_0_0_0);
ruby_version_v_2_0_to_2_2!(ruby_2_1_0);
ruby_version_v_2_0_to_2_2!(ruby_2_1_1);
ruby_version_v_2_0_to_2_2!(ruby_2_1_2);
ruby_version_v_2_0_to_2_2!(ruby_2_1_3);
ruby_version_v_2_0_to_2_2!(ruby_2_1_4);
ruby_version_v_2_0_to_2_2!(ruby_2_1_5);
ruby_version_v_2_0_to_2_2!(ruby_2_1_6);
ruby_version_v_2_0_to_2_2!(ruby_2_1_7);
ruby_version_v_2_0_to_2_2!(ruby_2_1_8);
ruby_version_v_2_0_to_2_2!(ruby_2_1_9);
ruby_version_v_2_0_to_2_2!(ruby_2_1_10);
ruby_version_v_2_0_to_2_2!(ruby_2_2_0);
ruby_version_v_2_0_to_2_2!(ruby_2_2_1);
ruby_version_v_2_0_to_2_2!(ruby_2_2_2);
ruby_version_v_2_0_to_2_2!(ruby_2_2_3);
ruby_version_v_2_0_to_2_2!(ruby_2_2_4);
ruby_version_v_2_0_to_2_2!(ruby_2_2_5);
ruby_version_v_2_0_to_2_2!(ruby_2_2_6);
ruby_version_v_2_0_to_2_2!(ruby_2_2_7);
ruby_version_v_2_0_to_2_2!(ruby_2_2_8);
ruby_version_v_2_0_to_2_2!(ruby_2_2_9);
ruby_version_v_2_0_to_2_2!(ruby_2_2_10);
ruby_version_v_2_3_to_2_4!(ruby_2_3_0);
ruby_version_v_2_3_to_2_4!(ruby_2_3_1);
ruby_version_v_2_3_to_2_4!(ruby_2_3_2);
ruby_version_v_2_3_to_2_4!(ruby_2_3_3);
ruby_version_v_2_3_to_2_4!(ruby_2_3_4);
ruby_version_v_2_3_to_2_4!(ruby_2_3_5);
ruby_version_v_2_3_to_2_4!(ruby_2_3_6);
ruby_version_v_2_3_to_2_4!(ruby_2_3_7);
ruby_version_v_2_3_to_2_4!(ruby_2_3_8);
ruby_version_v_2_3_to_2_4!(ruby_2_4_0);
ruby_version_v_2_3_to_2_4!(ruby_2_4_1);
ruby_version_v_2_3_to_2_4!(ruby_2_4_2);
ruby_version_v_2_3_to_2_4!(ruby_2_4_3);
ruby_version_v_2_3_to_2_4!(ruby_2_4_4);
ruby_version_v_2_3_to_2_4!(ruby_2_4_5);
ruby_version_v_2_3_to_2_4!(ruby_2_4_6);
ruby_version_v_2_3_to_2_4!(ruby_2_4_7);
ruby_version_v_2_3_to_2_4!(ruby_2_4_8);
ruby_version_v_2_3_to_2_4!(ruby_2_4_9);
ruby_version_v_2_3_to_2_4!(ruby_2_4_10);
ruby_version_v2_5_x!(ruby_2_5_0);
ruby_version_v2_5_x!(ruby_2_5_1);
ruby_version_v2_5_x!(ruby_2_5_2);
ruby_version_v2_5_x!(ruby_2_5_3);
ruby_version_v2_5_x!(ruby_2_5_4);
ruby_version_v2_5_x!(ruby_2_5_5);
ruby_version_v2_5_x!(ruby_2_5_6);
ruby_version_v2_5_x!(ruby_2_5_7);
ruby_version_v2_5_x!(ruby_2_5_8);
ruby_version_v2_5_x!(ruby_2_5_9);
ruby_version_v2_6_x!(ruby_2_6_0);
ruby_version_v2_6_x!(ruby_2_6_1);
ruby_version_v2_6_x!(ruby_2_6_2);
ruby_version_v2_6_x!(ruby_2_6_3);
ruby_version_v2_6_x!(ruby_2_6_4);
ruby_version_v2_6_x!(ruby_2_6_5);
ruby_version_v2_6_x!(ruby_2_6_6);
ruby_version_v2_6_x!(ruby_2_6_7);
ruby_version_v2_6_x!(ruby_2_6_8);
ruby_version_v2_6_x!(ruby_2_6_9);
ruby_version_v2_6_x!(ruby_2_6_10);
ruby_version_v2_7_x!(ruby_2_7_0);
ruby_version_v2_7_x!(ruby_2_7_1);
ruby_version_v2_7_x!(ruby_2_7_2);
ruby_version_v2_7_x!(ruby_2_7_3);
ruby_version_v2_7_x!(ruby_2_7_4);
ruby_version_v2_7_x!(ruby_2_7_5);
ruby_version_v2_7_x!(ruby_2_7_6);
ruby_version_v2_7_x!(ruby_2_7_7);
ruby_version_v2_7_x!(ruby_2_7_8);
ruby_version_v3_0_x!(ruby_3_0_0);
ruby_version_v3_0_x!(ruby_3_0_1);
ruby_version_v3_0_x!(ruby_3_0_2);
ruby_version_v3_0_x!(ruby_3_0_3);
ruby_version_v3_0_x!(ruby_3_0_4);
ruby_version_v3_0_x!(ruby_3_0_5);
ruby_version_v3_0_x!(ruby_3_0_6);
ruby_version_v3_0_x!(ruby_3_0_7);
ruby_version_v3_1_x!(ruby_3_1_0);
ruby_version_v3_1_x!(ruby_3_1_1);
ruby_version_v3_1_x!(ruby_3_1_2);
ruby_version_v3_1_x!(ruby_3_1_3);
ruby_version_v3_1_x!(ruby_3_1_4);
ruby_version_v3_1_x!(ruby_3_1_5);
ruby_version_v3_1_x!(ruby_3_1_6);
ruby_version_v3_1_x!(ruby_3_1_7);
ruby_version_v3_2_x!(ruby_3_2_0);
ruby_version_v3_2_x!(ruby_3_2_1);
ruby_version_v3_2_x!(ruby_3_2_2);
ruby_version_v3_2_x!(ruby_3_2_3);
ruby_version_v3_2_x!(ruby_3_2_4);
ruby_version_v3_2_x!(ruby_3_2_5);
ruby_version_v3_2_x!(ruby_3_2_6);
ruby_version_v3_2_x!(ruby_3_2_7);
ruby_version_v3_2_x!(ruby_3_2_8);
ruby_version_v3_2_x!(ruby_3_2_9);
ruby_version_v3_2_x!(ruby_3_2_10);
ruby_version_v3_2_x!(ruby_3_2_11);
ruby_version_v3_3_x!(ruby_3_3_0);
ruby_version_v3_3_x!(ruby_3_3_1);
ruby_version_v3_3_x!(ruby_3_3_2);
ruby_version_v3_3_x!(ruby_3_3_3);
ruby_version_v3_3_x!(ruby_3_3_4);
ruby_version_v3_3_x!(ruby_3_3_5);
ruby_version_v3_3_x!(ruby_3_3_6);
ruby_version_v3_3_x!(ruby_3_3_7);
ruby_version_v3_3_x!(ruby_3_3_8);
ruby_version_v3_3_x!(ruby_3_3_9);
ruby_version_v3_3_x!(ruby_3_3_10);
ruby_version_v3_3_x!(ruby_3_3_11);
ruby_version_v3_3_x!(ruby_3_3_12);
ruby_version_v3_3_x!(ruby_3_4_0);
ruby_version_v3_3_x!(ruby_3_4_1);
ruby_version_v3_3_x!(ruby_3_4_2);
ruby_version_v3_3_x!(ruby_3_4_3);
ruby_version_v3_3_x!(ruby_3_4_4);
ruby_version_v3_3_x!(ruby_3_4_5);
ruby_version_v3_3_x!(ruby_3_4_6);
ruby_version_v3_3_x!(ruby_3_4_7);
ruby_version_v3_3_x!(ruby_3_4_8);
ruby_version_v3_3_x!(ruby_3_4_9);
ruby_version_v3_3_x!(ruby_3_4_10);
ruby_version_v4_0_x!(ruby_4_0_0);
ruby_version_v4_0_x!(ruby_4_0_1);
ruby_version_v4_0_x!(ruby_4_0_2);
ruby_version_v4_0_x!(ruby_4_0_3);
ruby_version_v4_0_x!(ruby_4_0_4);
ruby_version_v4_0_x!(ruby_4_0_5);
ruby_version_v4_0_x!(ruby_4_0_6);
#[cfg(not(debug_assertions))]
#[cfg(test)]
mod tests {
use rbspy_testdata::*;
use rstest::rstest;
use crate::core::ruby_version;
use crate::core::types::StackFrame;
fn real_stack_trace_1_9_3() -> Vec<StackFrame> {
vec![
StackFrame::unknown_c_function(),
StackFrame {
name: "aaa".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(2),
},
StackFrame {
name: "bbb".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(6),
},
StackFrame {
name: "ccc".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(10),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(14),
},
StackFrame::unknown_c_function(),
StackFrame {
name: "<main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(13),
},
]
}
fn real_stack_trace_2_7_2() -> Vec<StackFrame> {
vec![
StackFrame {
name: "sleep [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "aaa".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
lineno: Some(3),
},
StackFrame {
name: "bbb".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
lineno: Some(7),
},
StackFrame {
name: "ccc".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
lineno: Some(11),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
lineno: Some(15),
},
StackFrame {
name: "loop [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
]
}
fn real_stack_trace_3_1_0() -> Vec<StackFrame> {
vec![
StackFrame {
name: "sleep [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "aaa".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(3),
},
StackFrame {
name: "bbb".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(7),
},
StackFrame {
name: "ccc".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(11),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(15),
},
StackFrame {
name: "loop [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
]
}
fn real_stack_trace_3_2_0() -> Vec<StackFrame> {
vec![
StackFrame {
name: "sleep [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "aaa".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(3),
},
StackFrame {
name: "bbb".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(7),
},
StackFrame {
name: "ccc".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(11),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(15),
},
StackFrame {
name: "loop [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "<main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(13),
},
]
}
fn real_stack_trace_3_3_0() -> Vec<StackFrame> {
vec![
StackFrame {
name: "Kernel#sleep [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "Object#aaa".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(9),
},
StackFrame {
name: "Object#bbb".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(13),
},
StackFrame {
name: "Object#ccc".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(17),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(21),
},
StackFrame {
name: "Kernel#loop".to_string(),
relative_path: "<internal:kernel>".to_string(),
absolute_path: Some("unknown".to_string()),
lineno: Some(192),
},
StackFrame {
name: "<main>".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(19),
},
]
}
fn real_stack_trace_with_classes_3_3_0() -> Vec<StackFrame> {
vec![
StackFrame {
name: "Kernel#sleep [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "A#aaa".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
lineno: Some(10)
},
StackFrame {
name: "B::Ab#bbb".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
lineno: Some(17)
},
StackFrame {
name: "C::Cb#ccc".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
lineno: Some(25)
},
StackFrame {
name: "block in looper".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
lineno: Some(32)
},
StackFrame {
name: "Kernel#loop".to_string(),
relative_path: "<internal:kernel>".to_string(),
absolute_path: Some("unknown".to_string()),
lineno: Some(192)
},
StackFrame {
name: "Object#looper".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
lineno: Some(33)
},
]
}
fn real_complex_trace_with_classes_3_4_5() -> Vec<StackFrame> {
vec![
StackFrame { name: "Kernel#sleep [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
StackFrame { name: "block in hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(41) },
StackFrame { name: "Kernel#loop".to_string(), relative_path: "<internal:kernel>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(173) },
StackFrame { name: "ClassA#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(42) },
StackFrame { name: "ModuleB::ClassB#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(49) },
StackFrame { name: "ModuleC.hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(56) },
StackFrame { name: "ClassWithStaticMethod.hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(62) },
StackFrame { name: "ModuleD#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(68) },
StackFrame { name: "block in <top (required)>".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(75) },
StackFrame { name: "block in <top (required)>".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(77) },
StackFrame { name: "#<ClassD:0x7f27035d2448>.hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(85) },
StackFrame { name: "ClassE#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(90) },
StackFrame { name: "UnboundMethod#bind_call [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
StackFrame { name: "#<Refinement:0x7f27035d1d68>#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(108) },
StackFrame { name: "ModuleE.hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(118) },
StackFrame { name: "ClassH#method_missing".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(126) },
StackFrame { name: "block in hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(133) },
StackFrame { name: "Integer#times".to_string(), relative_path: "<internal:numeric>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(261) },
StackFrame { name: "ClassF#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(134) },
StackFrame { name: "block (2 levels) in <top (required)>".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(140) },
StackFrame { name: "#<Class:0x7f27035df648>.hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(147) },
StackFrame { name: "#<Class:0x7f27035dee28>#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(152) },
StackFrame { name: "#<Module:0x7f27035dece8>.hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(158) },
StackFrame { name: "Object#method_with_complex_parameters".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(163) },
StackFrame { name: "block (2 levels) in hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(174) },
StackFrame { name: "ClassJ#hello_helper".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(168) },
StackFrame { name: "block in hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(175) },
StackFrame { name: "ClassJ#hello_helper".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(168) },
StackFrame { name: "ClassJ#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(176) },
StackFrame { name: "<compiled>".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(181) },
StackFrame { name: "Kernel#eval [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
StackFrame { name: "ClassK#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(182) },
StackFrame { name: "<compiled>".to_string(), relative_path: "(eval at /home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb:187)".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(1) },
StackFrame { name: "BasicObject#instance_eval [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
StackFrame { name: "ClassL#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(188) },
StackFrame { name: "<compiled>".to_string(), relative_path: "(eval at /home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb:193)".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(1) },
StackFrame { name: "Kernel#eval [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
StackFrame { name: "ClassM#hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(194) },
StackFrame { name: "block (3 levels) in <top (required)>".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(201) },
StackFrame { name: "Integer#times".to_string(), relative_path: "<internal:numeric>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(261) },
StackFrame { name: "block (2 levels) in <top (required)>".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(202) },
StackFrame { name: "Object#top_level_hello".to_string(), relative_path: "/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/interesting_backtrace_helper.rb".to_string()), lineno: Some(207) },
StackFrame { name: "InstanceMethod#work".to_string(), relative_path: "ci/ruby-programs/cme_complex_labels.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/cme_complex_labels.rb".to_string()), lineno: Some(6) },
StackFrame { name: "ModuleMethod#call_instance".to_string(), relative_path: "ci/ruby-programs/cme_complex_labels.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/cme_complex_labels.rb".to_string()), lineno: Some(12) },
StackFrame { name: "Object#work_main".to_string(), relative_path: "ci/ruby-programs/cme_complex_labels.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/cme_complex_labels.rb".to_string()), lineno: Some(22) },
StackFrame { name: "block in <main>".to_string(), relative_path: "ci/ruby-programs/cme_complex_labels.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/cme_complex_labels.rb".to_string()), lineno: Some(26) },
StackFrame { name: "Kernel#loop".to_string(), relative_path: "<internal:kernel>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(173) },
StackFrame { name: "<main>".to_string(), relative_path: "ci/ruby-programs/cme_complex_labels.rb".to_string(), absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/cme_complex_labels.rb".to_string()), lineno: Some(24) },
]
}
fn real_stack_trace_4_0_0() -> Vec<StackFrame> {
vec![
StackFrame {
name: "Kernel#sleep [c function]".to_string(),
relative_path: "(unknown)".to_string(),
absolute_path: None,
lineno: None,
},
StackFrame {
name: "Object#aaa".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(9),
},
StackFrame {
name: "Object#bbb".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(13),
},
StackFrame {
name: "Object#ccc".to_string(),
relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
absolute_path: Some(
"/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
),
lineno: Some(17),
},
StackFrame {
name: "Kernel#loop".to_string(),
relative_path: "<internal:kernel>".to_string(),
absolute_path: Some("unknown".to_string()),
lineno: Some(174),
},
]
}
fn real_stack_trace_main() -> Vec<StackFrame> {
vec![
StackFrame::unknown_c_function(),
StackFrame {
name: "aaa".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(2),
},
StackFrame {
name: "bbb".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(6),
},
StackFrame {
name: "ccc".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(10),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(14),
},
StackFrame::unknown_c_function(),
StackFrame {
name: "<main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(13),
},
]
}
fn real_stack_trace() -> Vec<StackFrame> {
vec![
StackFrame::unknown_c_function(),
StackFrame {
name: "aaa".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(2),
},
StackFrame {
name: "bbb".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(6),
},
StackFrame {
name: "ccc".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(10),
},
StackFrame {
name: "block in <main>".to_string(),
relative_path: "ci/ruby-programs/infinite.rb".to_string(),
absolute_path: Some(
"/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
),
lineno: Some(14),
},
StackFrame::unknown_c_function(),
]
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_1_9_3() {
let current_thread_addr = 0x823930;
let stack_trace = ruby_version::ruby_1_9_3_0::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
None,
&coredump_1_9_3(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_1_9_3(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_1_6() {
let current_thread_addr = 0x562658abd7f0;
let stack_trace = ruby_version::ruby_2_1_6::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
None,
&coredump_2_1_6(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_main(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_1_6_2() {
let current_thread_addr = 0x562efcd577f0;
let stack_trace = ruby_version::ruby_2_1_6::get_stack_trace(
current_thread_addr,
0,
None,
&coredump_2_1_6_c_function(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(vec!(StackFrame::unknown_c_function()), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_4_0() {
let current_thread_addr = 0x55df44959920;
let stack_trace = ruby_version::ruby_2_4_0::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
None,
&coredump_2_4_0(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_5_0() {
let current_thread_addr = 0x55dd8c3b7758;
let stack_trace = ruby_version::ruby_2_5_0::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
None,
&coredump_2_5_0(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_2() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_2::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_3() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_3::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_4() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_4::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_5() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_5::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_6() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_6::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_7() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_7::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_2_7_8() {
let current_thread_addr = 0x7fdd8d626070;
let global_symbols_addr = Some(0x7fdd8d60eb80);
let stack_trace = ruby_version::ruby_2_7_8::get_stack_trace::<CoreDump>(
current_thread_addr,
0,
global_symbols_addr,
&coredump_2_7_2(),
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_0() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_1() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_1::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_2() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_2::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_3() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_3::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_4() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_4::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_5() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_5::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_6() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_6::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_0_7() {
let source = coredump_3_0_0();
let vm_addr = 0x7fdacdab7470;
let global_symbols_addr = Some(0x7fdacdaa9d80);
let stack_trace = ruby_version::ruby_3_0_7::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_0() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_1() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_1::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_2() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_2::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_3() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_3::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_4() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_4::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_5() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_5::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_6() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_6::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_1_7() {
let source = coredump_3_1_0();
let vm_addr = 0x7f0dc0c83c58;
let global_symbols_addr = Some(0x7f0dc0c75e80);
let stack_trace = ruby_version::ruby_3_1_7::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_0() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_1() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_1::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_2() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_2::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_3() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_3::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_4() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_4::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_5() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_5::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_6() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_6::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_7() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_7::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_8() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_8::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_9() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_9::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_10() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_10::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_2_11() {
let source = coredump_3_2_0();
let vm_addr = 0xffffb8034578;
let global_symbols_addr = Some(0xffffb8025340);
let stack_trace = ruby_version::ruby_3_2_11::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_0() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_with_classes_3_3_0() {
let source = coredump_with_classes_3_3_0();
let vm_addr = 0x7f58cb7f4988;
let global_symbols_addr = Some(0x7f58cb7e3c60);
let stack_trace = ruby_version::ruby_3_3_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(
real_stack_trace_with_classes_3_3_0(),
stack_trace.unwrap().trace
);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_1() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_1::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_2() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_2::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_3() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_3::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_4() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_4::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_5() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_5::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_6() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_6::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_7() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_7::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_8() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_8::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_9() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_9::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_10() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_10::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_11() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_11::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_3_12() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_3_12::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_0() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_1() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_1::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_2() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_2::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_3() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_3::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_4() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_4::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_5() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_5::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_complex_3_4_5() {
let source = coredump_complex_3_4_5();
let vm_addr = 0x7f271feb5390;
let global_symbols_addr = Some(0x7f271fea3dc0);
let stack_trace = ruby_version::ruby_3_3_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(
real_complex_trace_with_classes_3_4_5(),
stack_trace.unwrap().trace
);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_6() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_6::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_7() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_7::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_8() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_8::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_9() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_9::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_3_4_10() {
let source = coredump_3_3_0();
let vm_addr = 0x7f43435f4988;
let global_symbols_addr = Some(0x7f43435e3c60);
let stack_trace = ruby_version::ruby_3_4_10::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap();
assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_4_0_0() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_0::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_4_0_1() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_1::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_4_0_2() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_2::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_4_0_3() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_3::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_4_0_4() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_4::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[test]
fn test_get_ruby_stack_trace_4_0_5() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_5::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_get_ruby_stack_trace_4_0_6() {
let source = coredump_4_0_0();
let vm_addr = 0x7fa56b875738;
let global_symbols_addr = Some(0x7fa56b862b50);
let stack_trace = ruby_version::ruby_4_0_6::get_stack_trace::<CoreDump>(
0,
vm_addr,
global_symbols_addr,
&source,
0,
false,
)
.unwrap()
.unwrap();
assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
}
#[rstest]
#[case::no_class_not_singleton("", "foo", false, "foo")]
#[case::class_not_singleton("ClassA", "foo", false, "ClassA#foo")]
#[case::class_with_singleton("ClassA", "foo", true, "ClassA.foo")]
#[case::empty_returns_empty("", "", false, "")]
fn test_qualified_method_name(
#[case] class_path: &str,
#[case] method_name: &str,
#[case] singleton: bool,
#[case] expected: &str,
) {
let qualified =
ruby_version::ruby_3_3_0::qualified_method_name(class_path, method_name, singleton);
assert_eq!(expected.to_string(), qualified);
}
#[rstest]
#[case::no_class_uses_label("", "block in foo", "foo", "foo", false, "block in foo")]
#[case::no_method_uses_label("", "block in foo", "foo", "", false, "block in foo")]
#[case::no_class_no_base_label_no_method_uses_label(
"",
"block in foo",
"",
"",
false,
"block in foo"
)]
#[case::class_uses_label_prefix(
"ClassA",
"block in foo",
"foo",
"foo",
false,
"block in ClassA#foo"
)]
#[case::class_uses_label_prefix_singleton(
"ClassA",
"block in foo",
"foo",
"foo",
true,
"block in ClassA.foo"
)]
fn test_profile_frame_full_label(
#[case] class_path: &str,
#[case] label: &str,
#[case] base_label: &str,
#[case] method_name: &str,
#[case] singleton: bool,
#[case] expected: &str,
) {
let full_label = ruby_version::ruby_3_3_0::profile_frame_full_label(
class_path,
label,
base_label,
method_name,
singleton,
);
assert_eq!(expected.to_string(), full_label);
}
}