1macro_rules! ruby_version_v_1_9_1(
12 ($ruby_version:ident) => (
13 pub mod $ruby_version {
14 use std;
15 use anyhow::{Context, format_err, Result};
16 use bindings::$ruby_version::*;
17 use crate::core::process::ProcessMemory;
18
19 get_stack_trace!(rb_thread_struct);
20 get_execution_context_from_thread!(rb_thread_struct);
21 rstring_as_array_1_9_1!();
22 get_ruby_string_1_9_1!();
23 get_cfps!();
24 get_pos!(rb_iseq_struct);
25 get_lineno_1_9_0!();
26 get_stack_frame_1_9_1!();
27 stack_field_1_9_0!();
28 get_thread_status_1_9_0!();
29 get_thread_id_1_9_0!();
30 get_cfunc_name_unsupported!();
31 }
32 )
33);
34
35macro_rules! ruby_version_v_1_9_2_to_3(
36 ($ruby_version:ident) => (
38 pub mod $ruby_version {
39 use std;
40 use anyhow::{Context, format_err, Result};
41 use bindings::$ruby_version::*;
42 use crate::core::process::ProcessMemory;
43
44 get_stack_trace!(rb_thread_struct);
45 get_execution_context_from_thread!(rb_thread_struct);
46 rstring_as_array_1_9_1!();
47 get_ruby_string_1_9_1!();
48 get_cfps!();
49 get_pos!(rb_iseq_struct);
50 get_lineno_1_9_0!();
51 get_stack_frame_1_9_2!();
52 stack_field_1_9_0!();
53 get_thread_status_1_9_0!();
54 get_thread_id_1_9_0!();
55 get_cfunc_name_unsupported!();
56 }
57 )
58);
59
60macro_rules! ruby_version_v_2_0_to_2_2(
61 ($ruby_version:ident) => (
62 pub mod $ruby_version {
63 use std;
64 use anyhow::{Context, format_err, Result};
65 use bindings::$ruby_version::*;
66 use crate::core::process::ProcessMemory;
67
68 get_stack_trace!(rb_thread_struct);
81 get_execution_context_from_thread!(rb_thread_struct);
82 rstring_as_array_1_9_1!();
83 get_ruby_string_1_9_1!();
84 get_cfps!();
85 get_pos!(rb_iseq_struct);
86 get_lineno_2_0_0!();
87 get_stack_frame_2_0_0!();
88 stack_field_1_9_0!();
89 get_thread_status_1_9_0!();
90 get_thread_id_1_9_0!();
91 get_cfunc_name_unsupported!();
92 }
93 )
94);
95
96macro_rules! ruby_version_v_2_3_to_2_4(
97 ($ruby_version:ident) => (
98 pub mod $ruby_version {
99 use std;
100 use anyhow::{Context, format_err, Result};
101 use bindings::$ruby_version::*;
102 use crate::core::process::ProcessMemory;
103
104 get_stack_trace!(rb_thread_struct);
105 get_execution_context_from_thread!(rb_thread_struct);
106 rstring_as_array_1_9_1!();
107 get_ruby_string_1_9_1!();
108 get_cfps!();
109 get_pos!(rb_iseq_constant_body);
110 get_lineno_2_3_0!();
111 get_stack_frame_2_3_0!();
112 stack_field_1_9_0!();
113 get_thread_status_1_9_0!();
114 get_thread_id_1_9_0!();
115 get_cfunc_name_unsupported!();
116 }
117 )
118);
119
120macro_rules! ruby_version_v2_5_x(
121 ($ruby_version:ident) => (
122 pub mod $ruby_version {
123 use std;
124 use anyhow::{Context, format_err, Result};
125 use bindings::$ruby_version::*;
126 use crate::core::process::ProcessMemory;
127
128 get_stack_trace!(rb_execution_context_struct);
129 get_execution_context_from_thread!(rb_execution_context_struct);
130 rstring_as_array_1_9_1!();
131 get_ruby_string_1_9_1!();
132 get_cfps!();
133 get_pos!(rb_iseq_constant_body);
134 get_lineno_2_5_0!();
135 get_stack_frame_2_5_0!();
136 stack_field_2_5_0!();
137 get_ruby_string_array_2_5_0!();
138 get_thread_status_2_5_0!();
139 get_thread_id_2_5_0!();
140 #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "windows"))]
141 get_cfunc_name_unsupported!();
142 #[cfg(target_os = "linux")]
143 get_cfunc_name!();
144 #[cfg(target_os = "linux")]
145 get_classpath_unsupported!();
146 }
147 )
148);
149
150macro_rules! ruby_version_v2_6_x(
151 ($ruby_version:ident) => (
152 pub mod $ruby_version {
153 use std;
154 use anyhow::{Context, format_err, Result};
155 use bindings::$ruby_version::*;
156 use crate::core::process::ProcessMemory;
157
158 get_stack_trace!(rb_execution_context_struct);
159 get_execution_context_from_thread!(rb_execution_context_struct);
160 rstring_as_array_1_9_1!();
161 get_ruby_string_1_9_1!();
162 get_ruby_string_array_2_5_0!();
163 get_cfps!();
164 get_pos!(rb_iseq_constant_body);
165 get_lineno_2_6_0!();
166 get_stack_frame_2_5_0!();
167 stack_field_2_5_0!();
168 get_thread_status_2_6_0!();
169 get_thread_id_2_5_0!();
170 #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "windows"))]
171 get_cfunc_name_unsupported!();
172 #[cfg(target_os = "linux")]
173 get_cfunc_name!();
174 #[cfg(target_os = "linux")]
175 get_classpath_unsupported!();
176 }
177 )
178);
179
180macro_rules! ruby_version_v2_7_x(
181 ($ruby_version:ident) => (
182 pub mod $ruby_version {
183 use std;
184 use anyhow::{Context, format_err, Result};
185 use bindings::$ruby_version::*;
186 use crate::core::process::ProcessMemory;
187
188 get_stack_trace!(rb_execution_context_struct);
189 get_execution_context_from_thread!(rb_execution_context_struct);
190 rstring_as_array_1_9_1!();
191 get_ruby_string_1_9_1!();
192 get_ruby_string_array_2_5_0!();
193 get_cfps!();
194 get_pos!(rb_iseq_constant_body);
195 get_lineno_2_6_0!();
196 get_stack_frame_2_5_0!();
197 stack_field_2_5_0!();
198 get_thread_status_2_6_0!();
199 get_thread_id_2_5_0!();
200 get_cfunc_name!();
201 get_classpath_unsupported!();
202 }
203 )
204);
205
206macro_rules! ruby_version_v3_0_x(
207 ($ruby_version:ident) => (
208 pub mod $ruby_version {
209 use std;
210 use anyhow::{Context, format_err, Result};
211 use bindings::$ruby_version::*;
212 use crate::core::process::ProcessMemory;
213
214 get_stack_trace!(rb_execution_context_struct);
215 ec_search_start_offset_3_0_0!();
216 get_execution_context_from_vm!();
217 rstring_as_array_1_9_1!();
218 get_ruby_string_1_9_1!();
219 get_ruby_string_array_2_5_0!();
220 get_cfps!();
221 get_pos!(rb_iseq_constant_body);
222 get_lineno_2_6_0!();
223 get_stack_frame_2_5_0!();
224 stack_field_2_5_0!();
225 get_thread_status_2_6_0!();
226 get_thread_id_2_5_0!();
227 get_cfunc_name!();
228
229 #[allow(non_upper_case_globals)]
230 const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
231 get_classpath_unsupported!();
232 }
233 )
234);
235
236macro_rules! ruby_version_v3_1_x(
237 ($ruby_version:ident) => (
238 pub mod $ruby_version {
239 use std;
240 use anyhow::{Context, format_err, Result};
241 use bindings::$ruby_version::*;
242 use crate::core::process::ProcessMemory;
243
244 get_stack_trace!(rb_execution_context_struct);
245 ec_search_start_offset_3_0_0!();
246 get_execution_context_from_vm!();
247 rstring_as_array_3_1_0!();
248 get_ruby_string_1_9_1!();
249 get_ruby_string_array_2_5_0!();
250 get_cfps!();
251 get_pos!(rb_iseq_constant_body);
252 get_lineno_2_6_0!();
253 get_stack_frame_2_5_0!();
254 stack_field_2_5_0!();
255 get_thread_status_2_6_0!();
256 get_thread_id_2_5_0!();
257 get_cfunc_name!();
258
259 #[allow(non_upper_case_globals)]
260 const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
261 get_classpath_unsupported!();
262 }
263 )
264);
265
266macro_rules! ruby_version_v3_2_x(
267 ($ruby_version:ident) => (
268 pub mod $ruby_version {
269 use std;
270 use anyhow::{Context, format_err, Result};
271 use bindings::$ruby_version::*;
272 use crate::core::process::ProcessMemory;
273
274 get_stack_trace!(rb_execution_context_struct);
275 ec_search_start_offset_3_0_0!();
276 get_execution_context_from_vm!();
277 get_ruby_string_3_2_0!();
278 get_ruby_string_array_3_2_0!();
279 get_cfps!();
280 get_pos!(rb_iseq_constant_body);
281 get_lineno_2_6_0!();
282 get_stack_frame_2_5_0!();
283 stack_field_2_5_0!();
284 get_thread_status_2_6_0!();
285 get_thread_id_3_2_0!();
286 get_cfunc_name!();
287
288 #[allow(non_upper_case_globals)]
289 const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
290 get_classpath_unsupported!();
291 }
292 )
293);
294
295macro_rules! ruby_version_v3_3_x(
296 ($ruby_version:ident) => (
297 pub mod $ruby_version {
298 use std;
299 use anyhow::{Context, format_err, Result};
300 use bindings::$ruby_version::*;
301 use crate::core::process::ProcessMemory;
302
303 get_stack_trace!(rb_execution_context_struct);
304 ec_search_start_offset_3_0_0!();
305 get_execution_context_from_vm!();
306 get_ruby_string_3_3_0!();
307 get_ruby_string_array_3_2_0!();
308 get_cfps!();
309 get_pos!(rb_iseq_constant_body);
310 get_lineno_2_6_0!();
311 get_stack_frame_3_3_0!();
312 stack_field_2_5_0!();
313 get_thread_status_2_6_0!();
314 get_thread_id_3_2_0!();
315 get_cfunc_name!();
316
317 #[allow(non_upper_case_globals)]
318 const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
319 get_classpath!();
320 rb_class_real_3_0_0!();
321 }
322 )
323);
324
325macro_rules! ruby_version_v4_0_x(
326 ($ruby_version:ident) => (
327 pub mod $ruby_version {
328 use std;
329 use anyhow::{Context, format_err, Result};
330 use bindings::$ruby_version::*;
331 use crate::core::process::ProcessMemory;
332
333 get_stack_trace!(rb_execution_context_struct);
334 ec_search_start_offset_4_0_0!();
335 get_execution_context_from_vm!();
336 get_ruby_string_3_3_0!();
337 get_ruby_string_array_3_2_0!();
338 get_cfps!();
339 get_pos!(rb_iseq_constant_body);
340 get_lineno_2_6_0!();
341 get_stack_frame_3_3_0!();
342 stack_field_2_5_0!();
343 get_thread_status_2_6_0!();
344 get_thread_id_3_2_0!();
345 get_cfunc_name!();
346
347 #[allow(non_upper_case_globals)]
348 const ruby_fl_type_RUBY_FL_USHIFT: ruby_fl_type = ruby_fl_ushift_RUBY_FL_USHIFT as i32;
349 get_classpath!();
350 rb_class_real_4_0_0!();
351 }
352 )
353);
354
355macro_rules! get_execution_context_from_thread(
356 ($thread_type:ident) => (
357 pub fn get_execution_context<T: ProcessMemory>(
358 current_thread_address_ptr: usize,
359 _ruby_vm_address_ptr: usize,
360 source: &T
361 ) -> Result<usize> {
362 source.copy_struct(current_thread_address_ptr)
363 .context("couldn't read current thread pointer")
364 }
365 )
366);
367
368macro_rules! ec_search_start_offset_3_0_0(
369 () => (
370 pub fn ec_search_start_offset() -> usize {
371 return
373 if cfg!(target_os = "windows") {
374 32
375 } else {
376 48
377 };
378 }
379 )
380);
381
382macro_rules! ec_search_start_offset_4_0_0(
383 () => (
384 pub fn ec_search_start_offset() -> usize {
385 return
387 if cfg!(target_os = "windows") {
388 30
389 } else {
390 38
391 };
392 }
393 )
394);
395
396macro_rules! get_execution_context_from_vm(
397 () => (
398 pub fn get_execution_context<T: ProcessMemory>(
399 _current_thread_address_ptr: usize,
400 ruby_vm_address_ptr: usize,
401 source: &T
402 ) -> Result<usize> {
403 let vm_addr: usize = source.copy_struct(ruby_vm_address_ptr)
408 .context("couldn't read Ruby VM pointer")?;
409 let vm: rb_vm_struct = source.copy_struct(vm_addr as usize)
410 .context("couldn't read Ruby VM struct")?;
411
412 const ADDRESSES_TO_CHECK: usize = 32;
420 let offset = ec_search_start_offset() * std::mem::size_of::<usize>();
421 let main_ractor_address = vm.ractor.main_ractor as usize;
422 let candidate_addresses: [usize; ADDRESSES_TO_CHECK] =
423 source.copy_struct(main_ractor_address + offset)
424 .context("couldn't read main ractor struct")?;
425
426 candidate_addresses
427 .iter()
428 .enumerate()
429 .filter(|(idx, &addr)| *idx > 0 && addr == vm.ractor.main_thread as usize)
430 .map(|(idx, _)| candidate_addresses[idx - 1])
431 .filter(|&addr| addr != 0)
432 .filter(|&addr| source.copy_struct::<rb_execution_context_struct>(addr as usize).is_ok())
433 .collect::<Vec<usize>>()
434 .first()
435 .map(|&addr| addr as usize)
436 .ok_or_else(|| format_err!("couldn't find execution context"))
437 }
438 )
439);
440
441macro_rules! get_stack_trace(
442 ($thread_type:ident) => (
443 use crate::core::process::Pid;
444 use crate::core::types::{StackFrame, StackTrace};
445
446 pub fn get_stack_trace<T: ProcessMemory>(
447 ruby_current_thread_address_location: usize,
448 ruby_vm_address_location: usize,
449 ruby_global_symbols_address_location: Option<usize>,
450 source: &T,
451 pid: Pid,
452 on_cpu: bool,
453 ) -> Result<Option<StackTrace>, anyhow::Error> {
454 let current_thread_addr: usize = get_execution_context(ruby_current_thread_address_location, ruby_vm_address_location, source)
455 .context("couldn't get execution context")?;
456 let thread: $thread_type = source.copy_struct(current_thread_addr)
457 .context("couldn't get current thread")?;
458
459 if on_cpu && get_thread_status(&thread, source)? != 0 {
460 return Ok(None);
464 }
465
466 let thread_id = match get_thread_id(&thread, source) {
467 Ok(tid) => Some(tid),
468 Err(e) => {
469 debug!("Couldn't get thread ID: {}", e);
470 None
471 },
472 };
473 if stack_field(&thread) as usize == 0 {
474 return Ok(Some(StackTrace {
475 pid: Some(pid),
476 trace: vec!(StackFrame::unknown_c_function()),
477 thread_id: thread_id,
478 time: Some(SystemTime::now()),
479 on_cpu: None,
480 }));
481 }
482 let mut trace = Vec::new();
483 let cfps = get_cfps(thread.cfp as usize, stack_base(&thread) as usize, source)?;
484 for cfp in cfps.iter() {
485 let cfunc = ruby_frame_cfunc(&cfp, source)?;
486
487 if !cfunc && cfp.pc as usize != 0 {
488 let iseq_struct: rb_iseq_struct = source.copy_struct(cfp.iseq as usize)
489 .context("couldn't copy iseq struct")?;
490
491 let label_path = get_stack_frame(&iseq_struct, &cfp, source);
492 match label_path {
493 Ok(call) => trace.push(call),
494 Err(x) => {
495 debug!("Error: {:#?}", x);
496 debug!("cfp: {:?}", cfp);
497 debug!("thread: {:?}", thread);
498 debug!("iseq struct: {:?}", iseq_struct);
499 if trace.len() > 0 {
501 debug!("Skipping function call, possibly into C extension");
502 } else {
503 return Err(x);
504 }
505 }
506 }
507 } else {
508 let mut frame = StackFrame::unknown_c_function();
509 if let Some(global_symbols_addr) = ruby_global_symbols_address_location {
510 match get_cfunc_name(cfp, global_symbols_addr, source, pid) {
511 Ok(name) => {
512 frame = StackFrame{
513 name: format!("{} [c function]", name),
514 relative_path: "(unknown)".to_string(),
515 absolute_path: None,
516 lineno: None,
517 };
518 },
519 Err(e) => {
520 debug!("Unknown C function: {:?}", e);
521 }
522 }
523 }
524 trace.push(frame);
525 continue;
526 }
527 }
528 let thread_id = match get_thread_id(&thread, source) {
529 Ok(tid) => Some(tid),
530 Err(e) => {
531 debug!("Couldn't get thread ID: {}", e);
532 None
533 },
534 };
535 Ok(Some(StackTrace{trace, pid: Some(pid), thread_id, time: Some(SystemTime::now()), on_cpu: Some(on_cpu)}))
536 }
537
538 use proc_maps::{maps_contain_addr, MapRange};
539 use std::time::SystemTime;
540
541 fn could_be_thread(thread: &$thread_type, all_maps: &[MapRange]) -> bool {
544 maps_contain_addr(thread.tag as usize, all_maps) &&
545 maps_contain_addr(thread.cfp as usize, all_maps) &&
546 maps_contain_addr(stack_field(thread) as usize, all_maps) &&
547 stack_size_field(thread) < 3_000_000
548 }
549
550 fn stack_base(thread: &$thread_type) -> i64 {
551 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)
560 }
561
562 pub fn is_maybe_thread<T>(candidate_thread_addr: usize, candidate_thread_addr_ptr: usize, source: &T, all_maps: &[MapRange]) -> bool where T: ProcessMemory {
563 if !maps_contain_addr(candidate_thread_addr, all_maps) {
564 return false;
565 }
566
567 let thread: $thread_type = match source.copy_struct(candidate_thread_addr) {
568 Ok(x) => x,
569 _ => { return false; },
570 };
571
572 if !could_be_thread(&thread, &all_maps) {
573 return false;
574 }
575
576 get_stack_trace(candidate_thread_addr_ptr, 0, None, source, 0, false).is_ok()
578 }
579 )
580);
581
582macro_rules! stack_field_1_9_0(
583 () => (
584 fn stack_field(thread: &rb_thread_struct) -> i64 {
585 thread.stack as i64
586 }
587
588 fn stack_size_field(thread: &rb_thread_struct) -> i64 {
589 thread.stack_size as i64
590 }
591 )
592);
593
594macro_rules! stack_field_2_5_0(
595 () => (
596 fn stack_field(thread: &rb_execution_context_struct) -> i64 {
597 thread.vm_stack as i64
598 }
599
600 fn stack_size_field(thread: &rb_execution_context_struct) -> i64 {
601 thread.vm_stack_size as i64
602 }
603 )
604);
605
606macro_rules! get_thread_status_1_9_0(
607 () => (
608 fn get_thread_status<T>(thread_struct: &rb_thread_struct, _source: &T) -> Result<u32> {
609 Ok(thread_struct.status as u32)
610 }
611 )
612);
613
614macro_rules! get_thread_status_2_5_0(
615 () => (
616 fn get_thread_status<T>(thread_struct: &rb_execution_context_struct, source: &T)
617 -> Result<u32> where T: ProcessMemory {
618 let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
619 .context(thread_struct.thread_ptr as usize)?;
620 Ok(thread.status as u32)
621 }
622 )
623);
624
625macro_rules! get_thread_status_2_6_0(
627 () => (
628 fn get_thread_status<T>(thread_struct: &rb_execution_context_struct, source: &T)
629 -> Result<u32> where T: ProcessMemory {
630 let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
631 .context(thread_struct.thread_ptr as usize)?;
632 Ok(thread.status() as u32)
633 }
634 )
635);
636
637macro_rules! get_thread_id_1_9_0(
638 () => (
639 fn get_thread_id<T>(thread_struct: &rb_thread_struct, _source: &T) -> Result<usize> {
640 Ok(thread_struct.thread_id as usize)
641 }
642 )
643);
644
645macro_rules! get_thread_id_2_5_0(
646 () => (
647 fn get_thread_id<T>(thread_struct: &rb_execution_context_struct, source: &T)
648 -> Result<usize> where T: ProcessMemory {
649 let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
650 .context("couldn't copy thread struct")?;
651 Ok(thread.thread_id as usize)
652 }
653 )
654);
655
656macro_rules! get_thread_id_3_2_0(
657 () => (
658 fn get_thread_id<T>(thread_struct: &rb_execution_context_struct, source: &T)
659 -> Result<usize> where T: ProcessMemory {
660 let thread: rb_thread_struct = source.copy_struct(thread_struct.thread_ptr as usize)
661 .context("couldn't copy thread struct")?;
662 if thread.nt.is_null() {
663 return Err(format_err!("native thread pointer is NULL"));
664 }
665 let native_thread: rb_native_thread = source.copy_struct(thread.nt as usize)
666 .context("couldn't copy native thread struct")?;
667 Ok(native_thread.thread_id as usize)
668 }
669 )
670);
671
672macro_rules! get_ruby_string_array_2_5_0(
673 () => (
674 fn get_ruby_string_array<T>(addr: usize, string_class: usize, source: &T) -> Result<(String, String)> where T: ProcessMemory {
676 let rstring: RString = source.copy_struct(addr).context("couldn't copy RString")?;
678 if rstring.basic.klass as usize == string_class {
679 let s = get_ruby_string(addr, source)?;
680 return Ok((s.clone(), s))
681 }
682 let rarray: RArray = source.copy_struct(addr).context("couldn't copy RArray")?;
684 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)?;
690 let abs_path = get_ruby_string(abs_path_addr, source)
693 .unwrap_or(String::from("unknown"));
694 Ok((rel_path, abs_path))
695 }
696 )
697);
698
699macro_rules! get_ruby_string_array_3_2_0(
700 () => (
701 fn get_ruby_string_array<T>(addr: usize, string_class: usize, source: &T) -> Result<(String, String)> where T: ProcessMemory {
703 let rstring: RString = source.copy_struct(addr).context("couldn't copy RString")?;
704 if rstring.basic.klass as usize == string_class {
705 let s = get_ruby_string(addr, source)?;
706 return Ok((s.clone(), s))
707 }
708
709 #[repr(C)]
713 #[derive(Copy, Clone)]
714 struct PaddedRArray {
715 pub basic: RBasic,
716 pub as_: PaddedRArray__bindgen_ty_1,
717 }
718 #[repr(C)]
719 #[derive(Copy, Clone)]
720 union PaddedRArray__bindgen_ty_1 {
721 pub heap: RArray__bindgen_ty_1__bindgen_ty_1,
722 pub ary: [VALUE; 2usize],
723 }
724
725 let rarray: PaddedRArray = source.copy_struct(addr).context("couldn't copy RArray")?;
727 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)?;
734 let abs_path = get_ruby_string(abs_path_addr, source)
737 .unwrap_or(String::from("unknown"));
738
739 Ok((rel_path, abs_path))
740 }
741 )
742);
743
744macro_rules! rstring_as_array_1_9_1(
745 () => (
746 unsafe fn rstring_as_array(rstring: RString) -> [::std::os::raw::c_char; 24usize] {
747 rstring.as_.ary
748 }
749 )
750);
751
752macro_rules! rstring_as_array_3_1_0(
753 () => (
754 unsafe fn rstring_as_array(rstring: RString) -> [::std::os::raw::c_char; 24usize] {
755 rstring.as_.embed.ary
756 }
757 )
758);
759
760macro_rules! get_ruby_string_1_9_1(
761 () => (
762 fn get_ruby_string<T>(
763 addr: usize,
764 source: &T
765 ) -> Result<String> where T: ProcessMemory {
766 let vec = {
767 let rstring: RString = source.copy_struct(addr).context("couldn't copy rstring")?;
768 let is_embedded_string = rstring.basic.flags & 1 << 13 == 0;
770 if is_embedded_string {
771 unsafe { std::ffi::CStr::from_ptr(rstring_as_array(rstring).as_ref().as_ptr()) }
772 .to_bytes()
773 .to_vec()
774 } else {
775 unsafe {
776 let addr = rstring.as_.heap.ptr as usize;
777 let len = rstring.as_.heap.len as usize;
778 source.copy(addr as usize, len).context("couldn't copy ruby string from heap")?
779 }
780 }
781 };
782
783 String::from_utf8(vec).context("couldn't convert ruby string bytes to string")
784 }
785 )
786);
787
788macro_rules! get_ruby_string_3_2_0(
789 () => (
790 fn get_ruby_string<T>(
791 addr: usize,
792 source: &T
793 ) -> Result<String> where T: ProcessMemory {
794 let rstring: RString = source.copy_struct(addr).context("couldn't copy rstring")?;
795 let is_embedded_string = rstring.basic.flags & 1 << 13 == 0;
797 if is_embedded_string {
798 #[cfg(target_os = "windows")]
800 let addr = addr + 4;
801
802 let embedded_str_bytes = source.copy(
808 addr + std::mem::size_of::<RBasic>() + std::mem::size_of::<std::os::raw::c_long>(),
809 unsafe { rstring.as_.embed.len } as usize
810 ).context("couldn't copy rstring")?;
811 return String::from_utf8(embedded_str_bytes).context("couldn't convert ruby string bytes to string")
812 } else {
813 unsafe {
814 let addr = rstring.as_.heap.ptr as usize;
815 let len = rstring.as_.heap.len as usize;
816 let heap_str_bytes = source.copy(addr as usize, len).context("couldn't copy ruby string from heap")?;
817 return String::from_utf8(heap_str_bytes).context("couldn't convert ruby string bytes to string");
818 }
819 }
820 }
821 )
822);
823
824macro_rules! get_ruby_string_3_3_0(
825 () => (
826 fn get_ruby_string<T>(
827 addr: usize,
828 source: &T
829 ) -> Result<String> where T: ProcessMemory {
830 let rstring: RString = source.copy_struct(addr).context("couldn't copy rstring")?;
831 if rstring.len > 1_000_000 {
832 return Err(anyhow::anyhow!("string length {} for string at {:X} appears invalid", rstring.len, addr));
833 }
834 let is_embedded_string = rstring.basic.flags & 1 << 13 == 0;
836 if is_embedded_string {
837 #[cfg(target_os = "windows")]
839 let addr = addr + 4;
840
841 let embedded_str_bytes = source.copy(
847 addr + std::mem::size_of::<RBasic>() + std::mem::size_of::<std::os::raw::c_long>(),
848 rstring.len as usize
849 ).context("couldn't copy rstring")?;
850 return String::from_utf8(embedded_str_bytes).context("couldn't convert ruby string bytes to string")
851 } else {
852 unsafe {
853 let addr = rstring.as_.heap.ptr as usize;
854 let len = rstring.len as usize;
855 let heap_str_bytes = source.copy(addr as usize, len).context("couldn't copy ruby string from heap")?;
856 return String::from_utf8(heap_str_bytes).context("couldn't convert ruby string bytes to string");
857 }
858 }
859 }
860 )
861);
862
863macro_rules! get_stack_frame_1_9_1(
864 () => (
865 fn get_stack_frame<T>(
866 iseq_struct: &rb_iseq_struct,
867 cfp: &rb_control_frame_t,
868 source: &T,
869 ) -> Result<StackFrame> where T: ProcessMemory {
870 Ok(StackFrame{
871 name: get_ruby_string(iseq_struct.name as usize, source)?,
872 relative_path: get_ruby_string(iseq_struct.filename as usize, source)?,
873 absolute_path: None,
874 lineno: match get_lineno(iseq_struct, cfp, source) {
875 Ok(lineno) => Some(lineno),
876 Err(e) => {
877 warn!("couldn't get lineno: {}", e);
878 None
879 },
880 }
881 })
882 }
883 )
884);
885
886macro_rules! get_stack_frame_1_9_2(
887 () => (
888 fn get_stack_frame<T>(
889 iseq_struct: &rb_iseq_struct,
890 cfp: &rb_control_frame_t,
891 source: &T,
892 ) -> Result<StackFrame> where T: ProcessMemory {
893 Ok(StackFrame{
894 name: get_ruby_string(iseq_struct.name as usize, source)?,
895 relative_path: get_ruby_string(iseq_struct.filename as usize, source)?,
896 absolute_path: Some(get_ruby_string(iseq_struct.filepath as usize, source)?),
897 lineno: match get_lineno(iseq_struct, cfp, source) {
898 Ok(lineno) => Some(lineno),
899 Err(e) => {
900 warn!("couldn't get lineno: {}", e);
901 None
902 },
903 }
904 })
905 }
906 )
907);
908
909macro_rules! get_stack_frame_2_0_0(
910 () => (
911 fn get_stack_frame<T>(
912 iseq_struct: &rb_iseq_struct,
913 cfp: &rb_control_frame_t,
914 source: &T,
915 ) -> Result<StackFrame> where T: ProcessMemory {
916 Ok(StackFrame{
917 name: get_ruby_string(iseq_struct.location.label as usize, source)?,
918 relative_path: get_ruby_string(iseq_struct.location.path as usize, source)?,
919 absolute_path: Some(get_ruby_string(iseq_struct.location.absolute_path as usize, source)?),
920 lineno: match get_lineno(iseq_struct, cfp, source) {
921 Ok(lineno) => Some(lineno),
922 Err(e) => {
923 warn!("couldn't get lineno: {}", e);
924 None
925 },
926 }
927 })
928 }
929 )
930);
931
932macro_rules! get_stack_frame_2_3_0(
933 () => (
934 fn get_stack_frame<T>(
935 iseq_struct: &rb_iseq_struct,
936 cfp: &rb_control_frame_t,
937 source: &T,
938 ) -> Result<StackFrame> where T: ProcessMemory {
939 let body: rb_iseq_constant_body = source.copy_struct(iseq_struct.body as usize)
940 .context(iseq_struct.body as usize)?;
941 Ok(StackFrame{
942 name: get_ruby_string(body.location.label as usize, source)?,
943 relative_path: get_ruby_string(body.location.path as usize, source)?,
944 absolute_path: Some(get_ruby_string(body.location.absolute_path as usize, source)?),
945 lineno: match get_lineno(&body, cfp, source) {
946 Ok(lineno) => Some(lineno),
947 Err(e) => {
948 warn!("couldn't get lineno: {}", e);
949 None
950 },
951 }
952 })
953 }
954 )
955);
956
957macro_rules! get_stack_frame_2_5_0(
958 () => (
959 fn get_stack_frame<T>(
960 iseq_struct: &rb_iseq_struct,
961 cfp: &rb_control_frame_t,
962 source: &T,
963 ) -> Result<StackFrame> where T: ProcessMemory {
964 if iseq_struct.body == std::ptr::null_mut() {
965 return Err(format_err!("iseq body is null"));
966 }
967 let body: rb_iseq_constant_body = source.copy_struct(iseq_struct.body as usize)
968 .context("couldn't copy rb_iseq_constant_body")?;
969 let rstring: RString = source.copy_struct(body.location.label as usize)
970 .context("couldn't copy RString")?;
971 let (path, absolute_path) = get_ruby_string_array(
972 body.location.pathobj as usize,
973 rstring.basic.klass as usize,
974 source
975 ).context("couldn't get ruby string from iseq body")?;
976 Ok(StackFrame{
977 name: get_ruby_string(body.location.label as usize, source)?,
978 relative_path: path,
979 absolute_path: Some(absolute_path),
980 lineno: match get_lineno(&body, cfp, source) {
981 Ok(lineno) => Some(lineno),
982 Err(e) => {
983 warn!("couldn't get lineno: {}", e);
984 None
985 },
986 }
987 })
988 }
989 )
990);
991
992macro_rules! get_classpath_unsupported(
993 () => (
994 fn get_classpath<T>(
995 _cme: usize,
996 _cfunc: bool,
997 _source: &T,
998 ) -> Result<(String, bool)> where T: ProcessMemory {
999 return Err(format_err!("classpath resolution is not supported for this version of Ruby").into());
1000 }
1001 )
1002);
1003
1004macro_rules! rb_class_real_3_0_0(
1005 () => (
1006 fn rb_class_real<T>(
1007 klass: usize,
1008 source: &T,
1009 ) -> Result<usize> where T: ProcessMemory {
1010 const RUBY_T_ICLASS: usize = 0x1c;
1011 const RUBY_FL_SINGLETON: usize = ruby_fl_type_RUBY_FL_USER1 as usize;
1012
1013 let mut klass = klass;
1015 let mut rbasic: RBasic = source.copy_struct(klass).context(klass)?;
1016 while (rbasic.flags & (RUBY_T_ICLASS | RUBY_FL_SINGLETON) != 0) {
1017 let rclass: RClass = source.copy_struct(klass).context(klass)?;
1018 klass = rclass.super_;
1019 rbasic = source.copy_struct(klass).context(klass)?;
1020 }
1021 Ok(klass)
1022 }
1023 )
1024);
1025
1026macro_rules! rb_class_real_4_0_0(
1032 () => (
1033 fn rb_class_real<T>(
1034 klass: usize,
1035 source: &T,
1036 ) -> Result<usize> where T: ProcessMemory {
1037 const RUBY_T_ICLASS: usize = 0x1c;
1038 const RUBY_FL_SINGLETON: usize = ruby_fl_type_RUBY_FL_USER1 as usize;
1039
1040 let mut klass = klass;
1042 let mut rbasic: RBasic = source.copy_struct(klass).context(klass)?;
1043 while (rbasic.flags & (RUBY_T_ICLASS | RUBY_FL_SINGLETON) != 0) {
1044 let rclass_ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
1045 klass = rclass_ext.classext.super_;
1046 rbasic = source.copy_struct(klass).context(klass)?;
1047 }
1048 Ok(klass)
1049 }
1050 )
1051);
1052
1053macro_rules! get_classpath(
1054 () => (
1055 fn rb_tmp_class_path<T>(
1057 klass: usize,
1058 source: &T,
1059 ) -> Result<usize> where T: ProcessMemory {
1060 const RUBY_T_MODULE: usize = 0x3;
1061 const RUBY_T_MASK: usize = 0x1f;
1063
1064 let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
1065 let mut path_addr = if ext.classext.classpath == 0 {
1066 0x0f } else {
1068 ext.classext.classpath
1069 };
1070
1071 let rbasic: RBasic = source.copy_struct(klass).context(klass)?;
1072 if rbasic.flags & RUBY_T_MASK == RUBY_T_MODULE {
1073 let real_klass = rb_class_real(rbasic.klass, source)?;
1074 let ext: RClass_and_rb_classext_t = source.copy_struct(real_klass).context(real_klass)?;
1076 path_addr = if ext.classext.classpath != 0 {
1077 let modstr = get_ruby_string(ext.classext.classpath as usize, source)?;
1078 if modstr == "Module".to_string() {
1081 0x00 } else {
1083 rb_tmp_class_path(rbasic.klass, source)?
1084 }
1085 } else {
1086 rb_tmp_class_path(rbasic.klass, source)?
1087 }
1088 }
1089 return Ok(path_addr);
1090 }
1091
1092 fn rb_class_path<T>(
1097 klass: usize,
1098 source: &T,
1099 ) -> Result<String> where T: ProcessMemory {
1100
1101 let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
1102 if ext.classext.classpath != 0 {
1103 return get_ruby_string(ext.classext.classpath as usize, source);
1104 };
1105
1106 let path = rb_tmp_class_path(klass, source)?;
1107 let path_fallback = match path {
1108 0x0f => {
1110 format!("#<Class:{:#08x}>", klass)
1111 }
1112 0x00 => {
1114 format!("#<Module:{:#08x}>", klass)
1115 }
1116 _ => {
1117 let path_str = get_ruby_string(path, source)?;
1118 format!("#<{}:{:#08x}>", path_str, klass)
1119 }
1120 };
1121
1122 return Ok(path_fallback)
1123 }
1124
1125 fn get_classpath<T>(
1127 cme: usize,
1128 cfunc: bool,
1129 source: &T,
1130 ) -> Result<(String, bool)> where T: ProcessMemory {
1131 const RUBY_T_CLASS: usize = 0x2;
1133 const RUBY_T_MODULE: usize = 0x3;
1135 const RUBY_T_ICLASS: usize = 0x1c;
1137 const RUBY_T_MASK: usize = 0x1f;
1139
1140 const RUBY_FL_SINGLETON: usize = ruby_fl_type_RUBY_FL_USER1 as usize;
1141
1142 const RUBY_IMMEDIATE_MASK: usize = 0x07;
1144
1145 const RUBY_QNIL: usize = 0x04;
1146
1147 let mut singleton = false;
1148
1149 let imemo: rb_method_entry_struct = source.copy_struct(cme).context(cme)?;
1150 let mut klass = if cfunc {
1152 imemo.owner
1153 } else {
1154 imemo.defined_class
1155 };
1156 if klass == RUBY_QNIL {
1157 return Ok(("".to_string(), false))
1158 }
1159 let rbasic: RBasic = source.copy_struct(klass).context(klass)?;
1160
1161 let class_flags = rbasic.flags;
1162 let class_mask = class_flags & RUBY_T_MASK;
1163
1164 match class_mask {
1165 RUBY_T_ICLASS => {
1166 klass = rbasic.klass as usize;
1168 }
1169 _ => {
1170 if class_flags & RUBY_FL_SINGLETON != 0 {
1172 log::debug!("Got singleton class");
1173 singleton = true;
1174
1175 let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
1176 klass = unsafe {
1177 ext.classext.as_.singleton_class.attached_object as usize
1178 };
1179
1180 let rbasic: RBasic = source.copy_struct(klass).context(klass)?;
1181 let class_flags = rbasic.flags;
1182 let class_mask = class_flags & RUBY_T_MASK;
1183 if class_mask != RUBY_T_CLASS && class_mask != RUBY_T_MODULE {
1184 if (klass & RUBY_IMMEDIATE_MASK == 0) {
1185 klass = rb_class_real(rbasic.klass, source)?;
1186 let ext: RClass_and_rb_classext_t = source.copy_struct(klass).context(klass)?;
1187 let class_path = get_ruby_string(ext.classext.classpath as usize, source)?;
1188 return Ok((format!("#<{}:{:#08x}>", class_path, klass), singleton));
1189 } else {
1190 log::debug!("TODO: Immediate object case is unhandled!");
1191 }
1192 }
1193 }
1194 }
1195 }
1196
1197 if klass == 0 {
1198 return Err(anyhow::anyhow!("klass was empty"));
1199 }
1200
1201 let class_path = rb_class_path(klass, source)?;
1202 Ok((class_path, singleton))
1203 }
1204
1205 pub fn profile_frame_full_label(
1207 class_path: &str,
1208 label: &str,
1209 base_label: &str,
1210 method_name: &str,
1211 singleton: bool,
1212 ) -> String {
1213 let qualified = qualified_method_name(class_path, method_name, singleton);
1214
1215 if qualified.is_empty() || qualified == base_label.to_string() {
1216 return label.to_string();
1217 }
1218
1219 let label_length = label.len();
1220 let base_label_length = base_label.len();
1221 let mut prefix_len = label_length.saturating_sub(base_label_length);
1222
1223 if prefix_len > label_length {
1226 prefix_len = label_length;
1227 }
1228
1229 let profile_label = format!("{}{}", &label[..prefix_len], qualified);
1230
1231 if profile_label.is_empty() {
1232 return String::new();
1233 }
1234
1235 profile_label
1237 }
1238 )
1239);
1240
1241macro_rules! get_stack_frame_3_3_0(
1242 () => (
1243 fn get_stack_frame<T>(
1244 iseq_struct: &rb_iseq_struct,
1245 cfp: &rb_control_frame_t,
1246 source: &T,
1247 ) -> Result<StackFrame> where T: ProcessMemory {
1248 let cme = locate_method_entry(&cfp.ep, source)?;
1249 let mut class_path = "".to_string();
1250 let mut singleton = false;
1251 let iseq = if cme != 0 {
1252 let imemo: rb_method_entry_struct = source.copy_struct(cme).context(cme)?;
1253 let method_type = source.copy(imemo.def as usize, 1).context(imemo.def as usize)?;
1254 let method_type = method_type[0] & 0xf;
1256 if method_type == 0 {
1258 (class_path, singleton) = get_classpath(cme, false, source)?;
1259 let method_def: rb_method_definition_struct = source.copy_struct(imemo.def as usize).context(imemo.def as usize)?;
1260 let iseq: rb_iseq_struct = unsafe {
1261 source.copy_struct(method_def.body.iseq.iseqptr as usize).context("")?
1262 };
1263 iseq
1264 } else {
1265 *iseq_struct
1266 }
1267 } else {
1268 *iseq_struct
1269 };
1270 if iseq_struct.body == std::ptr::null_mut() {
1271 return Err(format_err!("iseq body is null"));
1272 }
1273 let body: rb_iseq_constant_body =
1274 source.copy_struct(iseq.body as usize)
1275 .context("couldn't copy rb_iseq_constant_body")?;
1276 let frame_flag: usize = unsafe {
1277 source.copy_struct(cfp.ep.offset(0) as usize).context(cfp.ep.offset(0) as usize)?
1278 };
1279 let rstring: RString = source.copy_struct(body.location.label as usize)
1280 .context("couldn't copy RString")?;
1281
1282 let mut method_name = "".to_string();
1283 if body.local_iseq != std::ptr::null_mut() {
1284 let local_iseq: rb_iseq_t = source.copy_struct(body.local_iseq as usize)
1287 .context("couldn't read local iseq")?;
1288 if local_iseq.body != std::ptr::null_mut() {
1289 let local_body: rb_iseq_constant_body = source.copy_struct(iseq_struct.body as usize)
1290 .context("couldn't copy rb_iseq_constant_body")?;
1291 method_name = get_ruby_string(local_body.location.base_label as usize, source)?;
1292 }
1293
1294 }
1295 let (path, absolute_path) = get_ruby_string_array(
1296 body.location.pathobj as usize,
1297 rstring.basic.klass as usize,
1298 source
1299 ).context(format!("couldn't get ruby path string array from iseq body: {:X}", frame_flag)).unwrap_or(("FAILED".to_string(), "FAILED".to_string()));
1300
1301 let label = get_ruby_string(body.location.label as usize, source)?;
1302 let base_label = get_ruby_string(body.location.base_label as usize, source)?;
1303 let full_label = profile_frame_full_label(&class_path, &label, &base_label, &method_name, singleton);
1304
1305 Ok(StackFrame{
1306 name: full_label,
1307 relative_path: path,
1308 absolute_path: Some(absolute_path),
1309 lineno: match get_lineno(&body, cfp, source) {
1310 Ok(lineno) => Some(lineno),
1311 Err(e) => {
1312 warn!("couldn't get lineno: {}", e);
1313 None
1314 },
1315 }
1316 })
1317 }
1318 )
1319);
1320
1321macro_rules! get_pos(
1322 ($iseq_type:ident) => (
1323 #[allow(unused)] fn get_pos(iseq_struct: &$iseq_type, cfp: &rb_control_frame_t) -> Result<usize> {
1325 if (cfp.pc as usize) < (iseq_struct.iseq_encoded as usize) {
1326 return Err(crate::core::types::MemoryCopyError::Message(format!("program counter and iseq are out of sync")).into());
1327 }
1328 let mut pos = cfp.pc as usize - iseq_struct.iseq_encoded as usize;
1329 if pos != 0 {
1330 pos -= 1;
1331 }
1332 Ok(pos)
1333 }
1334 )
1335);
1336
1337macro_rules! get_lineno_1_9_0(
1338 () => (
1339 fn get_lineno<T>(
1340 iseq_struct: &rb_iseq_struct,
1341 cfp: &rb_control_frame_t,
1342 source: &T,
1343 ) -> Result<usize> where T: ProcessMemory {
1344 let pos = get_pos(iseq_struct, cfp)?;
1345 let t_size = iseq_struct.insn_info_size as usize;
1346 if t_size == 0 {
1347 Err(format_err!("line number is not available"))
1348 } else if t_size == 1 {
1349 let table: [iseq_insn_info_entry; 1] = source.copy_struct(iseq_struct.insn_info_table as usize)
1350 .context("couldn't copy instruction table")?;
1351 Ok(table[0].line_no as usize)
1352 } else {
1353 let table: Vec<iseq_insn_info_entry> = source.copy_vec(iseq_struct.insn_info_table as usize, t_size as usize)
1354 .context("couldn't copy instruction table")?;
1355 for i in 0..t_size {
1356 if pos == table[i].position as usize {
1357 return Ok(table[i].line_no as usize)
1358 } else if table[i].position as usize > pos {
1359 return Ok(table[i-1].line_no as usize)
1360 }
1361 }
1362 Ok(table[t_size-1].line_no as usize)
1363 }
1364 }
1365 )
1366);
1367
1368macro_rules! get_lineno_2_0_0(
1369 () => (
1370 fn get_lineno<T>(
1371 iseq_struct: &rb_iseq_struct,
1372 cfp: &rb_control_frame_t,
1373 source: &T,
1374 ) -> Result<usize> where T: ProcessMemory {
1375 let pos = get_pos(iseq_struct, cfp)?;
1376 let t_size = iseq_struct.line_info_size as usize;
1377 if t_size == 0 {
1378 Err(format_err!("line number is not available"))
1379 } else if t_size == 1 {
1380 let table: [iseq_line_info_entry; 1] = source.copy_struct(iseq_struct.line_info_table as usize)
1381 .context("couldn't copy instruction table")?;
1382 Ok(table[0].line_no as usize)
1383 } else {
1384 let table: Vec<iseq_line_info_entry> = source.copy_vec(iseq_struct.line_info_table as usize, t_size as usize)
1385 .context("couldn't copy instruction table")?;
1386 for i in 0..t_size {
1387 if pos == table[i].position as usize {
1388 return Ok(table[i].line_no as usize)
1389 } else if table[i].position as usize > pos {
1390 return Ok(table[i-1].line_no as usize)
1391 }
1392 }
1393 Ok(table[t_size-1].line_no as usize)
1394 }
1395 }
1396 )
1397);
1398
1399macro_rules! get_lineno_2_3_0(
1400 () => (
1401 fn get_lineno<T>(
1402 iseq_struct: &rb_iseq_constant_body,
1403 cfp: &rb_control_frame_t,
1404 source: &T,
1405 ) -> Result<usize> where T: ProcessMemory {
1406 let pos = get_pos(iseq_struct, cfp)?;
1407 let t_size = iseq_struct.line_info_size as usize;
1408 if t_size == 0 {
1409 Err(format_err!("line number is not available"))
1410 } else if t_size == 1 {
1411 let table: [iseq_line_info_entry; 1] = source.copy_struct(iseq_struct.line_info_table as usize)
1412 .context("couldn't copy instruction table")?;
1413 Ok(table[0].line_no as usize)
1414 } else {
1415 let table: Vec<iseq_line_info_entry> = source.copy_vec(iseq_struct.line_info_table as usize, t_size as usize)
1416 .context("couldn't copy instruction table")?;
1417 for i in 0..t_size {
1418 if pos == table[i].position as usize {
1419 return Ok(table[i].line_no as usize)
1420 } else if table[i].position as usize > pos {
1421 return Ok(table[i-1].line_no as usize)
1422 }
1423 }
1424 Ok(table[t_size-1].line_no as usize)
1425 }
1426 }
1427 )
1428);
1429
1430macro_rules! get_lineno_2_5_0(
1431 () => (
1432 fn get_lineno<T>(
1433 iseq_struct: &rb_iseq_constant_body,
1434 cfp: &rb_control_frame_t,
1435 source: &T,
1436 ) -> Result<usize> where T: ProcessMemory {
1437 let pos = get_pos(iseq_struct, cfp)?;
1438 let t_size = iseq_struct.insns_info_size as usize;
1439 if t_size == 0 {
1440 Err(format_err!("line number is not available"))
1441 } else if t_size == 1 {
1442 let table: [iseq_insn_info_entry; 1] = source.copy_struct(iseq_struct.insns_info as usize)
1443 .context("couldn't copy instruction table")?;
1444 Ok(table[0].line_no as usize)
1445 } else {
1446 let table: Vec<iseq_insn_info_entry> = source.copy_vec(iseq_struct.insns_info as usize, t_size as usize)
1447 .context("couldn't copy instruction table")?;
1448 for i in 0..t_size {
1449 if pos == table[i].position as usize {
1450 return Ok(table[i].line_no as usize)
1451 } else if table[i].position as usize > pos {
1452 return Ok(table[i-1].line_no as usize)
1453 }
1454 }
1455 Ok(table[t_size-1].line_no as usize)
1456 }
1457 }
1458 )
1459);
1460
1461macro_rules! get_lineno_2_6_0(
1462 () => (
1463 fn get_lineno<T>(
1464 iseq_struct: &rb_iseq_constant_body,
1465 _cfp: &rb_control_frame_t,
1466 source: &T,
1467 ) -> Result<usize> where T: ProcessMemory {
1468 let t_size = iseq_struct.insns_info.size as usize;
1469 if t_size == 0 {
1470 Err(format_err!("line number is not available"))
1471 } else if t_size == 1 {
1472 let table: [iseq_insn_info_entry; 1] = source.copy_struct(iseq_struct.insns_info.body as usize)
1473 .context("couldn't copy instruction table")?;
1474 Ok(table[0].line_no as usize)
1475 } else {
1476 let table: Vec<iseq_insn_info_entry> = source.copy_vec(iseq_struct.insns_info.body as usize, t_size as usize)
1479 .context(iseq_struct.insns_info.body as usize)?;
1480 Ok(table[t_size-1].line_no as usize)
1481 }
1482 }
1483 )
1484);
1485
1486macro_rules! get_cfps(
1487 () => (
1488 fn get_cfps<T>(
1489 cfp_address: usize,
1490 stack_base: usize,
1491 source: &T
1492 ) -> Result<Vec<rb_control_frame_t>> where T: ProcessMemory {
1493 if (stack_base as usize) <= cfp_address {
1496 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());
1497 }
1498 let cfp_size = (stack_base as usize - cfp_address) as usize / std::mem::size_of::<rb_control_frame_t>();
1499 if cfp_size > 1_000_000 {
1500 return Err(crate::core::types::MemoryCopyError::Message(format!("invalid cfp vector length: {}", cfp_size)).into());
1501 }
1502
1503 source.copy_vec(cfp_address, cfp_size).context("couldn't copy cfp vector")
1504 }
1505 )
1506);
1507
1508macro_rules! get_cfunc_name_unsupported(
1509 () => (
1510 fn ruby_frame_cfunc<T>(
1511 _cfp: &rb_control_frame_t,
1512 _source: &T
1513 ) -> Result<bool> where T: ProcessMemory {
1514 Ok(false)
1515 }
1516
1517 fn get_cfunc_name<T: ProcessMemory>(_cfp: &rb_control_frame_t, _global_symbols_address: usize, _source: &T, _pid: Pid) -> Result<String> {
1518 return Err(format_err!("C function resolution is not supported for this version of Ruby").into());
1519 }
1520 )
1521);
1522
1523macro_rules! get_cfunc_name(
1524 () => (
1525
1526 fn ruby_frame_cfunc<T>(
1527 cfp: &rb_control_frame_t,
1528 source: &T
1529 ) -> Result<bool> where T: ProcessMemory {
1530 let frame_flag: usize = unsafe {
1531 source.copy_struct(cfp.ep.offset(0) as usize).context(cfp.ep.offset(0) as usize)?
1532 };
1533 const VM_FRAME_MAGIC_CFUNC: usize = 0x55550001;
1534 const VM_FRAME_MAGIC_MASK: usize = 0x7fff0001;
1535
1536 Ok((frame_flag & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_CFUNC)
1537 }
1538
1539 pub fn qualified_method_name(class_path: &str, method_name: &str, singleton: bool) -> String {
1541 if method_name.is_empty() {
1542 return method_name.to_string();
1543 }
1544
1545 if !class_path.is_empty() {
1546 let join_char = if singleton { "." } else { "#" };
1547 return format!("{}{}{}", class_path, join_char, method_name);
1548 }
1549
1550 method_name.to_string()
1551 }
1552
1553 fn locate_method_entry<T>(
1556 ep: &*const usize,
1557 source: &T,
1558 ) -> Result<usize> where T: ProcessMemory {
1559 const VM_ENV_FLAG_LOCAL: usize = 0x2;
1560 let mut ep = ep.clone() as *mut usize;
1561 let mut env_flags: usize = source.copy_struct(ep as usize).context(ep as usize)?;
1562 let mut env_specval: usize = unsafe {
1563 source.copy_struct(ep.offset(-1) as usize).context(ep.offset(-1) as usize)?
1564 };
1565 let mut env_me_cref: usize = unsafe {
1566 source.copy_struct(ep.offset(-2) as usize).context(ep.offset(-2) as usize)?
1567 };
1568
1569 while env_flags & VM_ENV_FLAG_LOCAL != 0 {
1570 let me = check_method_entry(env_me_cref, false, source)?;
1571 if me != 0{
1572 return Ok(me);
1573 }
1574 unsafe {
1575 ep = (env_specval.clone() & !0x03) as *mut usize;
1579 env_flags = source.copy_struct(ep as usize).context(ep as usize)?;
1580 env_specval = source.copy_struct(ep.offset(-1) as usize).context(ep.offset(-1) as usize)?;
1581 env_me_cref = source.copy_struct(ep.offset(-2) as usize).context(ep.offset(-2) as usize)?;
1582 }
1583 }
1584
1585 let me = check_method_entry(env_me_cref, true, source)?;
1586 Ok(me)
1587 }
1588
1589 fn check_method_entry<T: ProcessMemory>(
1591 raw_imemo: usize,
1592 can_be_svar: bool,
1593 source: &T
1594 ) -> Result<usize> {
1595 const IMEMO_MASK: usize = 0x0f;
1597 if raw_imemo == 0 {
1598 return Ok(0);
1599 }
1600 let imemo: rb_method_entry_struct = source.copy_struct(raw_imemo).context(raw_imemo)?;
1601
1602 #[allow(non_upper_case_globals)]
1604 match ((imemo.flags >> ruby_fl_type_RUBY_FL_USHIFT) & IMEMO_MASK) as u32 {
1605 imemo_type_imemo_ment => Ok(raw_imemo),
1606 imemo_type_imemo_svar => {
1607 if can_be_svar {
1608 let svar: vm_svar = source.copy_struct(raw_imemo).context(raw_imemo)?;
1609 check_method_entry(svar.cref_or_me as usize, false, source)
1610 } else {
1611 Ok(0)
1612 }
1613 },
1614 _ => Ok(0)
1615 }
1616 }
1617
1618 fn get_cfunc_name<T: ProcessMemory>(
1620 cfp: &rb_control_frame_t,
1621 global_symbols_address: usize,
1622 source: &T,
1623 _pid: Pid
1624 ) -> Result<String> {
1625 const IMEMO_MASK: usize = 0x0f;
1626
1627 let cme = locate_method_entry(&cfp.ep, source)?;
1628 let (class_path, singleton) = get_classpath(cme, true, source).unwrap_or(("".to_string(), false));
1629
1630 let imemo: rb_method_entry_struct = source.copy_struct(cme).context(cme)?;
1631 if imemo.def.is_null() {
1632 return Err(format_err!("No method definition").into());
1633 }
1634
1635
1636 let ttype = ((imemo.flags >> ruby_fl_type_RUBY_FL_USHIFT) & IMEMO_MASK) as usize;
1637 if ttype != imemo_type_imemo_ment as usize {
1638 return Err(format_err!("Not a method entry").into());
1639 }
1640
1641 #[allow(non_camel_case_types)]
1642 type rb_id_serial_t = u32;
1643
1644 #[allow(non_camel_case_types)]
1646 #[repr(C)]
1647 #[derive(Debug, Copy, Clone)]
1648 struct rb_symbols_t {
1649 last_id: rb_id_serial_t,
1650 str_sym: *mut st_table,
1651 ids: VALUE,
1652 dsymbol_fstr_hash: VALUE,
1653 }
1654
1655 let global_symbols: rb_symbols_t = source.copy_struct(global_symbols_address as usize).context(global_symbols_address as usize)?;
1656 let def: rb_method_definition_struct = source.copy_struct(imemo.def as usize).context(imemo.def as usize)?;
1657 let method_id = def.original_id as usize;
1658
1659 let mut serial = method_id;
1661 if method_id > ruby_method_ids_tLAST_OP_ID as usize {
1662 serial = method_id >> ruby_id_types_RUBY_ID_SCOPE_SHIFT;
1663 }
1664
1665 if serial > global_symbols.last_id as usize {
1666 return Err(format_err!("Invalid method ID").into());
1667 }
1668
1669 let id_entry_unit = 512;
1671 let idx = serial / id_entry_unit;
1672 let ids: RArray = source.copy_struct(global_symbols.ids as usize).context(global_symbols.ids as usize)?;
1673 let flags = ids.basic.flags as usize;
1674
1675 let mut ids_ptr = unsafe { ids.as_.heap.ptr as usize };
1677 let mut ids_len = unsafe { ids.as_.heap.len as usize };
1678 if (flags & ruby_fl_type_RUBY_FL_USER1 as usize) > 0 {
1679 ids_ptr = unsafe { ids.as_.ary[0] as usize };
1680 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);
1681 }
1682 if idx >= ids_len {
1683 return Err(format_err!("Invalid index in IDs array").into());
1684 }
1685
1686 let array_remote_ptr = (ids_ptr as usize) + (idx as usize) * std::mem::size_of::<usize>();
1690 let array_ptr: usize = source.copy_struct(array_remote_ptr).context(array_remote_ptr)?;
1691 let array: RArray = source.copy_struct(array_ptr).context(array_ptr)?;
1692
1693 let mut array_ptr = unsafe { array.as_.heap.ptr };
1694 let flags = array.basic.flags as usize;
1695 if (flags & ruby_fl_type_RUBY_FL_USER1 as usize) > 0 {
1696 array_ptr = unsafe { &ids.as_.ary[0] };
1697 }
1698
1699 let offset = (serial % 512) * 2;
1700 let rstring_remote_ptr = (array_ptr as usize) + offset * std::mem::size_of::<usize>();
1701 let rstring_ptr: usize = source.copy_struct(rstring_remote_ptr as usize).context(rstring_remote_ptr as usize)?;
1702 let method_name = get_ruby_string(rstring_ptr as usize, source)?;
1703 Ok(qualified_method_name(&class_path, &method_name, singleton))
1704 }
1705 )
1706);
1707
1708ruby_version_v_1_9_1!(ruby_1_9_1_0);
1709ruby_version_v_1_9_2_to_3!(ruby_1_9_2_0);
1710ruby_version_v_1_9_2_to_3!(ruby_1_9_3_0);
1711ruby_version_v_2_0_to_2_2!(ruby_2_0_0_0);
1712ruby_version_v_2_0_to_2_2!(ruby_2_1_0);
1713ruby_version_v_2_0_to_2_2!(ruby_2_1_1);
1714ruby_version_v_2_0_to_2_2!(ruby_2_1_2);
1715ruby_version_v_2_0_to_2_2!(ruby_2_1_3);
1716ruby_version_v_2_0_to_2_2!(ruby_2_1_4);
1717ruby_version_v_2_0_to_2_2!(ruby_2_1_5);
1718ruby_version_v_2_0_to_2_2!(ruby_2_1_6);
1719ruby_version_v_2_0_to_2_2!(ruby_2_1_7);
1720ruby_version_v_2_0_to_2_2!(ruby_2_1_8);
1721ruby_version_v_2_0_to_2_2!(ruby_2_1_9);
1722ruby_version_v_2_0_to_2_2!(ruby_2_1_10);
1723ruby_version_v_2_0_to_2_2!(ruby_2_2_0);
1724ruby_version_v_2_0_to_2_2!(ruby_2_2_1);
1725ruby_version_v_2_0_to_2_2!(ruby_2_2_2);
1726ruby_version_v_2_0_to_2_2!(ruby_2_2_3);
1727ruby_version_v_2_0_to_2_2!(ruby_2_2_4);
1728ruby_version_v_2_0_to_2_2!(ruby_2_2_5);
1729ruby_version_v_2_0_to_2_2!(ruby_2_2_6);
1730ruby_version_v_2_0_to_2_2!(ruby_2_2_7);
1731ruby_version_v_2_0_to_2_2!(ruby_2_2_8);
1732ruby_version_v_2_0_to_2_2!(ruby_2_2_9);
1733ruby_version_v_2_0_to_2_2!(ruby_2_2_10);
1734ruby_version_v_2_3_to_2_4!(ruby_2_3_0);
1735ruby_version_v_2_3_to_2_4!(ruby_2_3_1);
1736ruby_version_v_2_3_to_2_4!(ruby_2_3_2);
1737ruby_version_v_2_3_to_2_4!(ruby_2_3_3);
1738ruby_version_v_2_3_to_2_4!(ruby_2_3_4);
1739ruby_version_v_2_3_to_2_4!(ruby_2_3_5);
1740ruby_version_v_2_3_to_2_4!(ruby_2_3_6);
1741ruby_version_v_2_3_to_2_4!(ruby_2_3_7);
1742ruby_version_v_2_3_to_2_4!(ruby_2_3_8);
1743ruby_version_v_2_3_to_2_4!(ruby_2_4_0);
1744ruby_version_v_2_3_to_2_4!(ruby_2_4_1);
1745ruby_version_v_2_3_to_2_4!(ruby_2_4_2);
1746ruby_version_v_2_3_to_2_4!(ruby_2_4_3);
1747ruby_version_v_2_3_to_2_4!(ruby_2_4_4);
1748ruby_version_v_2_3_to_2_4!(ruby_2_4_5);
1749ruby_version_v_2_3_to_2_4!(ruby_2_4_6);
1750ruby_version_v_2_3_to_2_4!(ruby_2_4_7);
1751ruby_version_v_2_3_to_2_4!(ruby_2_4_8);
1752ruby_version_v_2_3_to_2_4!(ruby_2_4_9);
1753ruby_version_v_2_3_to_2_4!(ruby_2_4_10);
1754ruby_version_v2_5_x!(ruby_2_5_0);
1755ruby_version_v2_5_x!(ruby_2_5_1);
1756ruby_version_v2_5_x!(ruby_2_5_2);
1757ruby_version_v2_5_x!(ruby_2_5_3);
1758ruby_version_v2_5_x!(ruby_2_5_4);
1759ruby_version_v2_5_x!(ruby_2_5_5);
1760ruby_version_v2_5_x!(ruby_2_5_6);
1761ruby_version_v2_5_x!(ruby_2_5_7);
1762ruby_version_v2_5_x!(ruby_2_5_8);
1763ruby_version_v2_5_x!(ruby_2_5_9);
1764ruby_version_v2_6_x!(ruby_2_6_0);
1765ruby_version_v2_6_x!(ruby_2_6_1);
1766ruby_version_v2_6_x!(ruby_2_6_2);
1767ruby_version_v2_6_x!(ruby_2_6_3);
1768ruby_version_v2_6_x!(ruby_2_6_4);
1769ruby_version_v2_6_x!(ruby_2_6_5);
1770ruby_version_v2_6_x!(ruby_2_6_6);
1771ruby_version_v2_6_x!(ruby_2_6_7);
1772ruby_version_v2_6_x!(ruby_2_6_8);
1773ruby_version_v2_6_x!(ruby_2_6_9);
1774ruby_version_v2_6_x!(ruby_2_6_10);
1775ruby_version_v2_7_x!(ruby_2_7_0);
1776ruby_version_v2_7_x!(ruby_2_7_1);
1777ruby_version_v2_7_x!(ruby_2_7_2);
1778ruby_version_v2_7_x!(ruby_2_7_3);
1779ruby_version_v2_7_x!(ruby_2_7_4);
1780ruby_version_v2_7_x!(ruby_2_7_5);
1781ruby_version_v2_7_x!(ruby_2_7_6);
1782ruby_version_v2_7_x!(ruby_2_7_7);
1783ruby_version_v2_7_x!(ruby_2_7_8);
1784ruby_version_v3_0_x!(ruby_3_0_0);
1785ruby_version_v3_0_x!(ruby_3_0_1);
1786ruby_version_v3_0_x!(ruby_3_0_2);
1787ruby_version_v3_0_x!(ruby_3_0_3);
1788ruby_version_v3_0_x!(ruby_3_0_4);
1789ruby_version_v3_0_x!(ruby_3_0_5);
1790ruby_version_v3_0_x!(ruby_3_0_6);
1791ruby_version_v3_0_x!(ruby_3_0_7);
1792ruby_version_v3_1_x!(ruby_3_1_0);
1793ruby_version_v3_1_x!(ruby_3_1_1);
1794ruby_version_v3_1_x!(ruby_3_1_2);
1795ruby_version_v3_1_x!(ruby_3_1_3);
1796ruby_version_v3_1_x!(ruby_3_1_4);
1797ruby_version_v3_1_x!(ruby_3_1_5);
1798ruby_version_v3_1_x!(ruby_3_1_6);
1799ruby_version_v3_1_x!(ruby_3_1_7);
1800ruby_version_v3_2_x!(ruby_3_2_0);
1801ruby_version_v3_2_x!(ruby_3_2_1);
1802ruby_version_v3_2_x!(ruby_3_2_2);
1803ruby_version_v3_2_x!(ruby_3_2_3);
1804ruby_version_v3_2_x!(ruby_3_2_4);
1805ruby_version_v3_2_x!(ruby_3_2_5);
1806ruby_version_v3_2_x!(ruby_3_2_6);
1807ruby_version_v3_2_x!(ruby_3_2_7);
1808ruby_version_v3_2_x!(ruby_3_2_8);
1809ruby_version_v3_2_x!(ruby_3_2_9);
1810ruby_version_v3_2_x!(ruby_3_2_10);
1811ruby_version_v3_2_x!(ruby_3_2_11);
1812ruby_version_v3_3_x!(ruby_3_3_0);
1813ruby_version_v3_3_x!(ruby_3_3_1);
1814ruby_version_v3_3_x!(ruby_3_3_2);
1815ruby_version_v3_3_x!(ruby_3_3_3);
1816ruby_version_v3_3_x!(ruby_3_3_4);
1817ruby_version_v3_3_x!(ruby_3_3_5);
1818ruby_version_v3_3_x!(ruby_3_3_6);
1819ruby_version_v3_3_x!(ruby_3_3_7);
1820ruby_version_v3_3_x!(ruby_3_3_8);
1821ruby_version_v3_3_x!(ruby_3_3_9);
1822ruby_version_v3_3_x!(ruby_3_3_10);
1823ruby_version_v3_3_x!(ruby_3_3_11);
1824ruby_version_v3_3_x!(ruby_3_4_0);
1825ruby_version_v3_3_x!(ruby_3_4_1);
1826ruby_version_v3_3_x!(ruby_3_4_2);
1827ruby_version_v3_3_x!(ruby_3_4_3);
1828ruby_version_v3_3_x!(ruby_3_4_4);
1829ruby_version_v3_3_x!(ruby_3_4_5);
1830ruby_version_v3_3_x!(ruby_3_4_6);
1831ruby_version_v3_3_x!(ruby_3_4_7);
1832ruby_version_v3_3_x!(ruby_3_4_8);
1833ruby_version_v3_3_x!(ruby_3_4_9);
1834ruby_version_v4_0_x!(ruby_4_0_0);
1835ruby_version_v4_0_x!(ruby_4_0_1);
1836ruby_version_v4_0_x!(ruby_4_0_2);
1837
1838#[cfg(not(debug_assertions))]
1839#[cfg(test)]
1840mod tests {
1841 use rbspy_testdata::*;
1842 use rstest::rstest;
1843
1844 use crate::core::ruby_version;
1845 use crate::core::types::StackFrame;
1846
1847 fn real_stack_trace_1_9_3() -> Vec<StackFrame> {
1848 vec![
1849 StackFrame::unknown_c_function(),
1850 StackFrame {
1851 name: "aaa".to_string(),
1852 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1853 absolute_path: Some(
1854 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1855 ),
1856 lineno: Some(2),
1857 },
1858 StackFrame {
1859 name: "bbb".to_string(),
1860 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1861 absolute_path: Some(
1862 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1863 ),
1864 lineno: Some(6),
1865 },
1866 StackFrame {
1867 name: "ccc".to_string(),
1868 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1869 absolute_path: Some(
1870 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1871 ),
1872 lineno: Some(10),
1873 },
1874 StackFrame {
1875 name: "block in <main>".to_string(),
1876 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1877 absolute_path: Some(
1878 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1879 ),
1880 lineno: Some(14),
1881 },
1882 StackFrame::unknown_c_function(),
1883 StackFrame {
1884 name: "<main>".to_string(),
1885 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1886 absolute_path: Some(
1887 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1888 ),
1889 lineno: Some(13),
1890 },
1891 ]
1892 }
1893
1894 fn real_stack_trace_2_7_2() -> Vec<StackFrame> {
1895 vec![
1896 StackFrame {
1897 name: "sleep [c function]".to_string(),
1898 relative_path: "(unknown)".to_string(),
1899 absolute_path: None,
1900 lineno: None,
1901 },
1902 StackFrame {
1903 name: "aaa".to_string(),
1904 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1905 absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
1906 lineno: Some(3),
1907 },
1908 StackFrame {
1909 name: "bbb".to_string(),
1910 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1911 absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
1912 lineno: Some(7),
1913 },
1914 StackFrame {
1915 name: "ccc".to_string(),
1916 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1917 absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
1918 lineno: Some(11),
1919 },
1920 StackFrame {
1921 name: "block in <main>".to_string(),
1922 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1923 absolute_path: Some("/vagrant/ci/ruby-programs/infinite.rb".to_string()),
1924 lineno: Some(15),
1925 },
1926 StackFrame {
1927 name: "loop [c function]".to_string(),
1928 relative_path: "(unknown)".to_string(),
1929 absolute_path: None,
1930 lineno: None,
1931 },
1932 ]
1933 }
1934
1935 fn real_stack_trace_3_1_0() -> Vec<StackFrame> {
1936 vec![
1937 StackFrame {
1938 name: "sleep [c function]".to_string(),
1939 relative_path: "(unknown)".to_string(),
1940 absolute_path: None,
1941 lineno: None,
1942 },
1943 StackFrame {
1944 name: "aaa".to_string(),
1945 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1946 absolute_path: Some(
1947 "/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1948 ),
1949 lineno: Some(3),
1950 },
1951 StackFrame {
1952 name: "bbb".to_string(),
1953 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1954 absolute_path: Some(
1955 "/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1956 ),
1957 lineno: Some(7),
1958 },
1959 StackFrame {
1960 name: "ccc".to_string(),
1961 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1962 absolute_path: Some(
1963 "/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1964 ),
1965 lineno: Some(11),
1966 },
1967 StackFrame {
1968 name: "block in <main>".to_string(),
1969 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1970 absolute_path: Some(
1971 "/home/acj/workspace/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1972 ),
1973 lineno: Some(15),
1974 },
1975 StackFrame {
1976 name: "loop [c function]".to_string(),
1977 relative_path: "(unknown)".to_string(),
1978 absolute_path: None,
1979 lineno: None,
1980 },
1981 ]
1982 }
1983
1984 fn real_stack_trace_3_2_0() -> Vec<StackFrame> {
1985 vec![
1986 StackFrame {
1987 name: "sleep [c function]".to_string(),
1988 relative_path: "(unknown)".to_string(),
1989 absolute_path: None,
1990 lineno: None,
1991 },
1992 StackFrame {
1993 name: "aaa".to_string(),
1994 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
1995 absolute_path: Some(
1996 "/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
1997 ),
1998 lineno: Some(3),
1999 },
2000 StackFrame {
2001 name: "bbb".to_string(),
2002 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2003 absolute_path: Some(
2004 "/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2005 ),
2006 lineno: Some(7),
2007 },
2008 StackFrame {
2009 name: "ccc".to_string(),
2010 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2011 absolute_path: Some(
2012 "/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2013 ),
2014 lineno: Some(11),
2015 },
2016 StackFrame {
2017 name: "block in <main>".to_string(),
2018 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2019 absolute_path: Some(
2020 "/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2021 ),
2022 lineno: Some(15),
2023 },
2024 StackFrame {
2025 name: "loop [c function]".to_string(),
2026 relative_path: "(unknown)".to_string(),
2027 absolute_path: None,
2028 lineno: None,
2029 },
2030 StackFrame {
2031 name: "<main>".to_string(),
2032 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2033 absolute_path: Some(
2034 "/home/parallels/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2035 ),
2036 lineno: Some(13),
2037 },
2038 ]
2039 }
2040
2041 fn real_stack_trace_3_3_0() -> Vec<StackFrame> {
2042 vec![
2043 StackFrame {
2044 name: "Kernel#sleep [c function]".to_string(),
2045 relative_path: "(unknown)".to_string(),
2046 absolute_path: None,
2047 lineno: None,
2048 },
2049 StackFrame {
2050 name: "Object#aaa".to_string(),
2051 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2052 absolute_path: Some(
2053 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2054 ),
2055 lineno: Some(9),
2056 },
2057 StackFrame {
2058 name: "Object#bbb".to_string(),
2059 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2060 absolute_path: Some(
2061 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2062 ),
2063 lineno: Some(13),
2064 },
2065 StackFrame {
2066 name: "Object#ccc".to_string(),
2067 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2068 absolute_path: Some(
2069 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2070 ),
2071 lineno: Some(17),
2072 },
2073 StackFrame {
2074 name: "block in <main>".to_string(),
2075 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2076 absolute_path: Some(
2077 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2078 ),
2079 lineno: Some(21),
2080 },
2081 StackFrame {
2082 name: "Kernel#loop".to_string(),
2083 relative_path: "<internal:kernel>".to_string(),
2084 absolute_path: Some("unknown".to_string()),
2085 lineno: Some(192),
2086 },
2087 StackFrame {
2088 name: "<main>".to_string(),
2089 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2090 absolute_path: Some(
2091 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2092 ),
2093 lineno: Some(19),
2094 },
2095 ]
2096 }
2097
2098 fn real_stack_trace_with_classes_3_3_0() -> Vec<StackFrame> {
2099 vec![
2100 StackFrame {
2101 name: "Kernel#sleep [c function]".to_string(),
2102 relative_path: "(unknown)".to_string(),
2103 absolute_path: None,
2104 lineno: None,
2105 },
2106 StackFrame {
2107 name: "A#aaa".to_string(),
2108 relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
2109 absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
2110 lineno: Some(10)
2111 },
2112 StackFrame {
2113 name: "B::Ab#bbb".to_string(),
2114 relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
2115 absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
2116 lineno: Some(17)
2117 },
2118 StackFrame {
2119 name: "C::Cb#ccc".to_string(),
2120 relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
2121 absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
2122 lineno: Some(25)
2123 },
2124 StackFrame {
2125 name: "block in looper".to_string(),
2126 relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
2127 absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
2128 lineno: Some(32)
2129 },
2130 StackFrame {
2131 name: "Kernel#loop".to_string(),
2132 relative_path: "<internal:kernel>".to_string(),
2133 absolute_path: Some("unknown".to_string()),
2134 lineno: Some(192)
2135 },
2136 StackFrame {
2137 name: "Object#looper".to_string(),
2138 relative_path: "ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string(),
2139 absolute_path: Some("/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu_with_classes.rb".to_string()),
2140 lineno: Some(33)
2141 },
2142 ]
2143 }
2144
2145 fn real_complex_trace_with_classes_3_4_5() -> Vec<StackFrame> {
2146 vec![
2147 StackFrame { name: "Kernel#sleep [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
2148 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) },
2149 StackFrame { name: "Kernel#loop".to_string(), relative_path: "<internal:kernel>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(173) },
2150 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) },
2151 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) },
2152 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) },
2153 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) },
2154 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) },
2155 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) },
2156 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) },
2157 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) },
2158 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) },
2159 StackFrame { name: "UnboundMethod#bind_call [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
2160 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) },
2161 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) },
2162 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) },
2163 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) },
2164 StackFrame { name: "Integer#times".to_string(), relative_path: "<internal:numeric>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(261) },
2165 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) },
2166 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) },
2167 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) },
2168 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) },
2169 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) },
2170 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) },
2171 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) },
2172 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) },
2173 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) },
2174 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) },
2175 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) },
2176 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) },
2177 StackFrame { name: "Kernel#eval [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
2178 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) },
2179 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) },
2180 StackFrame { name: "BasicObject#instance_eval [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
2181 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) },
2182 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) },
2183 StackFrame { name: "Kernel#eval [c function]".to_string(), relative_path: "(unknown)".to_string(), absolute_path: None, lineno: None },
2184 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) },
2185 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) },
2186 StackFrame { name: "Integer#times".to_string(), relative_path: "<internal:numeric>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(261) },
2187 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) },
2188 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) },
2189 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) },
2190 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) },
2191 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) },
2192 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) },
2193 StackFrame { name: "Kernel#loop".to_string(), relative_path: "<internal:kernel>".to_string(), absolute_path: Some("unknown".to_string()), lineno: Some(173) },
2194 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) },
2195 ]
2196 }
2197
2198 fn real_stack_trace_4_0_0() -> Vec<StackFrame> {
2199 vec![
2200 StackFrame {
2201 name: "Kernel#sleep [c function]".to_string(),
2202 relative_path: "(unknown)".to_string(),
2203 absolute_path: None,
2204 lineno: None,
2205 },
2206 StackFrame {
2207 name: "Object#aaa".to_string(),
2208 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2209 absolute_path: Some(
2210 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2211 ),
2212 lineno: Some(9),
2213 },
2214 StackFrame {
2215 name: "Object#bbb".to_string(),
2216 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2217 absolute_path: Some(
2218 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2219 ),
2220 lineno: Some(13),
2221 },
2222 StackFrame {
2223 name: "Object#ccc".to_string(),
2224 relative_path: "ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2225 absolute_path: Some(
2226 "/home/runner/work/rbspy/rbspy/ci/ruby-programs/infinite_on_cpu.rb".to_string(),
2227 ),
2228 lineno: Some(17),
2229 },
2230 StackFrame {
2231 name: "Kernel#loop".to_string(),
2232 relative_path: "<internal:kernel>".to_string(),
2233 absolute_path: Some("unknown".to_string()),
2234 lineno: Some(174),
2235 },
2236 ]
2237 }
2238
2239 fn real_stack_trace_main() -> Vec<StackFrame> {
2240 vec![
2241 StackFrame::unknown_c_function(),
2242 StackFrame {
2243 name: "aaa".to_string(),
2244 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2245 absolute_path: Some(
2246 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2247 ),
2248 lineno: Some(2),
2249 },
2250 StackFrame {
2251 name: "bbb".to_string(),
2252 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2253 absolute_path: Some(
2254 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2255 ),
2256 lineno: Some(6),
2257 },
2258 StackFrame {
2259 name: "ccc".to_string(),
2260 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2261 absolute_path: Some(
2262 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2263 ),
2264 lineno: Some(10),
2265 },
2266 StackFrame {
2267 name: "block in <main>".to_string(),
2268 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2269 absolute_path: Some(
2270 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2271 ),
2272 lineno: Some(14),
2273 },
2274 StackFrame::unknown_c_function(),
2275 StackFrame {
2276 name: "<main>".to_string(),
2277 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2278 absolute_path: Some(
2279 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2280 ),
2281 lineno: Some(13),
2282 },
2283 ]
2284 }
2285
2286 fn real_stack_trace() -> Vec<StackFrame> {
2287 vec![
2288 StackFrame::unknown_c_function(),
2289 StackFrame {
2290 name: "aaa".to_string(),
2291 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2292 absolute_path: Some(
2293 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2294 ),
2295 lineno: Some(2),
2296 },
2297 StackFrame {
2298 name: "bbb".to_string(),
2299 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2300 absolute_path: Some(
2301 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2302 ),
2303 lineno: Some(6),
2304 },
2305 StackFrame {
2306 name: "ccc".to_string(),
2307 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2308 absolute_path: Some(
2309 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2310 ),
2311 lineno: Some(10),
2312 },
2313 StackFrame {
2314 name: "block in <main>".to_string(),
2315 relative_path: "ci/ruby-programs/infinite.rb".to_string(),
2316 absolute_path: Some(
2317 "/home/bork/work/rbspy/ci/ruby-programs/infinite.rb".to_string(),
2318 ),
2319 lineno: Some(14),
2320 },
2321 StackFrame::unknown_c_function(),
2322 ]
2323 }
2324
2325 #[cfg(target_pointer_width = "64")]
2329 #[test]
2330 fn test_get_ruby_stack_trace_1_9_3() {
2331 let current_thread_addr = 0x823930;
2332 let stack_trace = ruby_version::ruby_1_9_3_0::get_stack_trace::<CoreDump>(
2333 current_thread_addr,
2334 0,
2335 None,
2336 &coredump_1_9_3(),
2337 0,
2338 false,
2339 )
2340 .unwrap()
2341 .unwrap();
2342 assert_eq!(real_stack_trace_1_9_3(), stack_trace.trace);
2343 }
2344
2345 #[cfg(target_pointer_width = "64")]
2346 #[test]
2347 fn test_get_ruby_stack_trace_2_1_6() {
2348 let current_thread_addr = 0x562658abd7f0;
2349 let stack_trace = ruby_version::ruby_2_1_6::get_stack_trace::<CoreDump>(
2350 current_thread_addr,
2351 0,
2352 None,
2353 &coredump_2_1_6(),
2354 0,
2355 false,
2356 )
2357 .unwrap()
2358 .unwrap();
2359 assert_eq!(real_stack_trace_main(), stack_trace.trace);
2360 }
2361
2362 #[cfg(target_pointer_width = "64")]
2363 #[test]
2364 fn test_get_ruby_stack_trace_2_1_6_2() {
2365 let current_thread_addr = 0x562efcd577f0;
2367 let stack_trace = ruby_version::ruby_2_1_6::get_stack_trace(
2368 current_thread_addr,
2369 0,
2370 None,
2371 &coredump_2_1_6_c_function(),
2372 0,
2373 false,
2374 )
2375 .unwrap()
2376 .unwrap();
2377 assert_eq!(vec!(StackFrame::unknown_c_function()), stack_trace.trace);
2378 }
2379
2380 #[cfg(target_pointer_width = "64")]
2381 #[test]
2382 fn test_get_ruby_stack_trace_2_4_0() {
2383 let current_thread_addr = 0x55df44959920;
2384 let stack_trace = ruby_version::ruby_2_4_0::get_stack_trace::<CoreDump>(
2385 current_thread_addr,
2386 0,
2387 None,
2388 &coredump_2_4_0(),
2389 0,
2390 false,
2391 )
2392 .unwrap()
2393 .unwrap();
2394 assert_eq!(real_stack_trace(), stack_trace.trace);
2395 }
2396
2397 #[cfg(target_pointer_width = "64")]
2398 #[test]
2399 fn test_get_ruby_stack_trace_2_5_0() {
2400 let current_thread_addr = 0x55dd8c3b7758;
2401 let stack_trace = ruby_version::ruby_2_5_0::get_stack_trace::<CoreDump>(
2402 current_thread_addr,
2403 0,
2404 None,
2405 &coredump_2_5_0(),
2406 0,
2407 false,
2408 )
2409 .unwrap()
2410 .unwrap();
2411 assert_eq!(real_stack_trace(), stack_trace.trace);
2412 }
2413
2414 #[cfg(target_pointer_width = "64")]
2415 #[test]
2416 fn test_get_ruby_stack_trace_2_7_2() {
2417 let current_thread_addr = 0x7fdd8d626070;
2418 let global_symbols_addr = Some(0x7fdd8d60eb80);
2419 let stack_trace = ruby_version::ruby_2_7_2::get_stack_trace::<CoreDump>(
2420 current_thread_addr,
2421 0,
2422 global_symbols_addr,
2423 &coredump_2_7_2(),
2424 0,
2425 false,
2426 )
2427 .unwrap()
2428 .unwrap();
2429 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2430 }
2431
2432 #[cfg(target_pointer_width = "64")]
2433 #[test]
2434 fn test_get_ruby_stack_trace_2_7_3() {
2435 let current_thread_addr = 0x7fdd8d626070;
2436 let global_symbols_addr = Some(0x7fdd8d60eb80);
2437 let stack_trace = ruby_version::ruby_2_7_3::get_stack_trace::<CoreDump>(
2438 current_thread_addr,
2439 0,
2440 global_symbols_addr,
2441 &coredump_2_7_2(),
2442 0,
2443 false,
2444 )
2445 .unwrap()
2446 .unwrap();
2447 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2448 }
2449
2450 #[cfg(target_pointer_width = "64")]
2451 #[test]
2452 fn test_get_ruby_stack_trace_2_7_4() {
2453 let current_thread_addr = 0x7fdd8d626070;
2454 let global_symbols_addr = Some(0x7fdd8d60eb80);
2455 let stack_trace = ruby_version::ruby_2_7_4::get_stack_trace::<CoreDump>(
2456 current_thread_addr,
2457 0,
2458 global_symbols_addr,
2459 &coredump_2_7_2(),
2460 0,
2461 false,
2462 )
2463 .unwrap()
2464 .unwrap();
2465 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2466 }
2467
2468 #[cfg(target_pointer_width = "64")]
2469 #[test]
2470 fn test_get_ruby_stack_trace_2_7_5() {
2471 let current_thread_addr = 0x7fdd8d626070;
2472 let global_symbols_addr = Some(0x7fdd8d60eb80);
2473 let stack_trace = ruby_version::ruby_2_7_5::get_stack_trace::<CoreDump>(
2474 current_thread_addr,
2475 0,
2476 global_symbols_addr,
2477 &coredump_2_7_2(),
2478 0,
2479 false,
2480 )
2481 .unwrap()
2482 .unwrap();
2483 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2484 }
2485
2486 #[cfg(target_pointer_width = "64")]
2487 #[test]
2488 fn test_get_ruby_stack_trace_2_7_6() {
2489 let current_thread_addr = 0x7fdd8d626070;
2490 let global_symbols_addr = Some(0x7fdd8d60eb80);
2491 let stack_trace = ruby_version::ruby_2_7_6::get_stack_trace::<CoreDump>(
2492 current_thread_addr,
2493 0,
2494 global_symbols_addr,
2495 &coredump_2_7_2(),
2496 0,
2497 false,
2498 )
2499 .unwrap()
2500 .unwrap();
2501 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2502 }
2503
2504 #[cfg(target_pointer_width = "64")]
2505 #[test]
2506 fn test_get_ruby_stack_trace_2_7_7() {
2507 let current_thread_addr = 0x7fdd8d626070;
2508 let global_symbols_addr = Some(0x7fdd8d60eb80);
2509 let stack_trace = ruby_version::ruby_2_7_7::get_stack_trace::<CoreDump>(
2510 current_thread_addr,
2511 0,
2512 global_symbols_addr,
2513 &coredump_2_7_2(),
2514 0,
2515 false,
2516 )
2517 .unwrap()
2518 .unwrap();
2519 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2520 }
2521
2522 #[cfg(target_pointer_width = "64")]
2523 #[test]
2524 fn test_get_ruby_stack_trace_2_7_8() {
2525 let current_thread_addr = 0x7fdd8d626070;
2526 let global_symbols_addr = Some(0x7fdd8d60eb80);
2527 let stack_trace = ruby_version::ruby_2_7_8::get_stack_trace::<CoreDump>(
2528 current_thread_addr,
2529 0,
2530 global_symbols_addr,
2531 &coredump_2_7_2(),
2532 0,
2533 false,
2534 )
2535 .unwrap()
2536 .unwrap();
2537 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2538 }
2539
2540 #[cfg(target_pointer_width = "64")]
2541 #[test]
2542 fn test_get_ruby_stack_trace_3_0_0() {
2543 let source = coredump_3_0_0();
2544 let vm_addr = 0x7fdacdab7470;
2545 let global_symbols_addr = Some(0x7fdacdaa9d80);
2546 let stack_trace = ruby_version::ruby_3_0_0::get_stack_trace::<CoreDump>(
2547 0,
2548 vm_addr,
2549 global_symbols_addr,
2550 &source,
2551 0,
2552 false,
2553 )
2554 .unwrap()
2555 .unwrap();
2556 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2557 }
2558
2559 #[cfg(target_pointer_width = "64")]
2560 #[test]
2561 fn test_get_ruby_stack_trace_3_0_1() {
2562 let source = coredump_3_0_0();
2563 let vm_addr = 0x7fdacdab7470;
2564 let global_symbols_addr = Some(0x7fdacdaa9d80);
2565 let stack_trace = ruby_version::ruby_3_0_1::get_stack_trace::<CoreDump>(
2566 0,
2567 vm_addr,
2568 global_symbols_addr,
2569 &source,
2570 0,
2571 false,
2572 )
2573 .unwrap()
2574 .unwrap();
2575 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2576 }
2577
2578 #[cfg(target_pointer_width = "64")]
2579 #[test]
2580 fn test_get_ruby_stack_trace_3_0_2() {
2581 let source = coredump_3_0_0();
2582 let vm_addr = 0x7fdacdab7470;
2583 let global_symbols_addr = Some(0x7fdacdaa9d80);
2584 let stack_trace = ruby_version::ruby_3_0_2::get_stack_trace::<CoreDump>(
2585 0,
2586 vm_addr,
2587 global_symbols_addr,
2588 &source,
2589 0,
2590 false,
2591 )
2592 .unwrap()
2593 .unwrap();
2594 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2595 }
2596
2597 #[cfg(target_pointer_width = "64")]
2598 #[test]
2599 fn test_get_ruby_stack_trace_3_0_3() {
2600 let source = coredump_3_0_0();
2601 let vm_addr = 0x7fdacdab7470;
2602 let global_symbols_addr = Some(0x7fdacdaa9d80);
2603 let stack_trace = ruby_version::ruby_3_0_3::get_stack_trace::<CoreDump>(
2604 0,
2605 vm_addr,
2606 global_symbols_addr,
2607 &source,
2608 0,
2609 false,
2610 )
2611 .unwrap()
2612 .unwrap();
2613 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2614 }
2615
2616 #[cfg(target_pointer_width = "64")]
2617 #[test]
2618 fn test_get_ruby_stack_trace_3_0_4() {
2619 let source = coredump_3_0_0();
2620 let vm_addr = 0x7fdacdab7470;
2621 let global_symbols_addr = Some(0x7fdacdaa9d80);
2622 let stack_trace = ruby_version::ruby_3_0_4::get_stack_trace::<CoreDump>(
2623 0,
2624 vm_addr,
2625 global_symbols_addr,
2626 &source,
2627 0,
2628 false,
2629 )
2630 .unwrap()
2631 .unwrap();
2632 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2633 }
2634
2635 #[cfg(target_pointer_width = "64")]
2636 #[test]
2637 fn test_get_ruby_stack_trace_3_0_5() {
2638 let source = coredump_3_0_0();
2639 let vm_addr = 0x7fdacdab7470;
2640 let global_symbols_addr = Some(0x7fdacdaa9d80);
2641 let stack_trace = ruby_version::ruby_3_0_5::get_stack_trace::<CoreDump>(
2642 0,
2643 vm_addr,
2644 global_symbols_addr,
2645 &source,
2646 0,
2647 false,
2648 )
2649 .unwrap()
2650 .unwrap();
2651 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2652 }
2653
2654 #[cfg(target_pointer_width = "64")]
2655 #[test]
2656 fn test_get_ruby_stack_trace_3_0_6() {
2657 let source = coredump_3_0_0();
2658 let vm_addr = 0x7fdacdab7470;
2659 let global_symbols_addr = Some(0x7fdacdaa9d80);
2660 let stack_trace = ruby_version::ruby_3_0_6::get_stack_trace::<CoreDump>(
2661 0,
2662 vm_addr,
2663 global_symbols_addr,
2664 &source,
2665 0,
2666 false,
2667 )
2668 .unwrap()
2669 .unwrap();
2670 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2671 }
2672
2673 #[cfg(target_pointer_width = "64")]
2674 #[test]
2675 fn test_get_ruby_stack_trace_3_0_7() {
2676 let source = coredump_3_0_0();
2677 let vm_addr = 0x7fdacdab7470;
2678 let global_symbols_addr = Some(0x7fdacdaa9d80);
2679 let stack_trace = ruby_version::ruby_3_0_7::get_stack_trace::<CoreDump>(
2680 0,
2681 vm_addr,
2682 global_symbols_addr,
2683 &source,
2684 0,
2685 false,
2686 )
2687 .unwrap()
2688 .unwrap();
2689 assert_eq!(real_stack_trace_2_7_2(), stack_trace.trace);
2690 }
2691
2692 #[cfg(target_pointer_width = "64")]
2693 #[test]
2694 fn test_get_ruby_stack_trace_3_1_0() {
2695 let source = coredump_3_1_0();
2696 let vm_addr = 0x7f0dc0c83c58;
2697 let global_symbols_addr = Some(0x7f0dc0c75e80);
2698 let stack_trace = ruby_version::ruby_3_1_0::get_stack_trace::<CoreDump>(
2699 0,
2700 vm_addr,
2701 global_symbols_addr,
2702 &source,
2703 0,
2704 false,
2705 )
2706 .unwrap()
2707 .unwrap();
2708 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2709 }
2710
2711 #[cfg(target_pointer_width = "64")]
2712 #[test]
2713 fn test_get_ruby_stack_trace_3_1_1() {
2714 let source = coredump_3_1_0();
2715 let vm_addr = 0x7f0dc0c83c58;
2716 let global_symbols_addr = Some(0x7f0dc0c75e80);
2717 let stack_trace = ruby_version::ruby_3_1_1::get_stack_trace::<CoreDump>(
2718 0,
2719 vm_addr,
2720 global_symbols_addr,
2721 &source,
2722 0,
2723 false,
2724 )
2725 .unwrap()
2726 .unwrap();
2727 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2728 }
2729
2730 #[cfg(target_pointer_width = "64")]
2731 #[test]
2732 fn test_get_ruby_stack_trace_3_1_2() {
2733 let source = coredump_3_1_0();
2734 let vm_addr = 0x7f0dc0c83c58;
2735 let global_symbols_addr = Some(0x7f0dc0c75e80);
2736 let stack_trace = ruby_version::ruby_3_1_2::get_stack_trace::<CoreDump>(
2737 0,
2738 vm_addr,
2739 global_symbols_addr,
2740 &source,
2741 0,
2742 false,
2743 )
2744 .unwrap()
2745 .unwrap();
2746 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2747 }
2748
2749 #[cfg(target_pointer_width = "64")]
2750 #[test]
2751 fn test_get_ruby_stack_trace_3_1_3() {
2752 let source = coredump_3_1_0();
2753 let vm_addr = 0x7f0dc0c83c58;
2754 let global_symbols_addr = Some(0x7f0dc0c75e80);
2755 let stack_trace = ruby_version::ruby_3_1_3::get_stack_trace::<CoreDump>(
2756 0,
2757 vm_addr,
2758 global_symbols_addr,
2759 &source,
2760 0,
2761 false,
2762 )
2763 .unwrap()
2764 .unwrap();
2765 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2766 }
2767
2768 #[cfg(target_pointer_width = "64")]
2769 #[test]
2770 fn test_get_ruby_stack_trace_3_1_4() {
2771 let source = coredump_3_1_0();
2772 let vm_addr = 0x7f0dc0c83c58;
2773 let global_symbols_addr = Some(0x7f0dc0c75e80);
2774 let stack_trace = ruby_version::ruby_3_1_4::get_stack_trace::<CoreDump>(
2775 0,
2776 vm_addr,
2777 global_symbols_addr,
2778 &source,
2779 0,
2780 false,
2781 )
2782 .unwrap()
2783 .unwrap();
2784 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2785 }
2786
2787 #[cfg(target_pointer_width = "64")]
2788 #[test]
2789 fn test_get_ruby_stack_trace_3_1_5() {
2790 let source = coredump_3_1_0();
2791 let vm_addr = 0x7f0dc0c83c58;
2792 let global_symbols_addr = Some(0x7f0dc0c75e80);
2793 let stack_trace = ruby_version::ruby_3_1_5::get_stack_trace::<CoreDump>(
2794 0,
2795 vm_addr,
2796 global_symbols_addr,
2797 &source,
2798 0,
2799 false,
2800 )
2801 .unwrap()
2802 .unwrap();
2803 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2804 }
2805
2806 #[cfg(target_pointer_width = "64")]
2807 #[test]
2808 fn test_get_ruby_stack_trace_3_1_6() {
2809 let source = coredump_3_1_0();
2810 let vm_addr = 0x7f0dc0c83c58;
2811 let global_symbols_addr = Some(0x7f0dc0c75e80);
2812 let stack_trace = ruby_version::ruby_3_1_6::get_stack_trace::<CoreDump>(
2813 0,
2814 vm_addr,
2815 global_symbols_addr,
2816 &source,
2817 0,
2818 false,
2819 )
2820 .unwrap()
2821 .unwrap();
2822 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2823 }
2824
2825 #[cfg(target_pointer_width = "64")]
2826 #[test]
2827 fn test_get_ruby_stack_trace_3_1_7() {
2828 let source = coredump_3_1_0();
2829 let vm_addr = 0x7f0dc0c83c58;
2830 let global_symbols_addr = Some(0x7f0dc0c75e80);
2831 let stack_trace = ruby_version::ruby_3_1_7::get_stack_trace::<CoreDump>(
2832 0,
2833 vm_addr,
2834 global_symbols_addr,
2835 &source,
2836 0,
2837 false,
2838 )
2839 .unwrap()
2840 .unwrap();
2841 assert_eq!(real_stack_trace_3_1_0(), stack_trace.trace);
2842 }
2843
2844 #[cfg(target_pointer_width = "64")]
2845 #[test]
2846 fn test_get_ruby_stack_trace_3_2_0() {
2847 let source = coredump_3_2_0();
2848 let vm_addr = 0xffffb8034578;
2849 let global_symbols_addr = Some(0xffffb8025340);
2850 let stack_trace = ruby_version::ruby_3_2_0::get_stack_trace::<CoreDump>(
2851 0,
2852 vm_addr,
2853 global_symbols_addr,
2854 &source,
2855 0,
2856 false,
2857 )
2858 .unwrap()
2859 .unwrap();
2860 assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
2861 }
2862
2863 #[cfg(target_pointer_width = "64")]
2864 #[test]
2865 fn test_get_ruby_stack_trace_3_2_1() {
2866 let source = coredump_3_2_0();
2867 let vm_addr = 0xffffb8034578;
2868 let global_symbols_addr = Some(0xffffb8025340);
2869 let stack_trace = ruby_version::ruby_3_2_1::get_stack_trace::<CoreDump>(
2870 0,
2871 vm_addr,
2872 global_symbols_addr,
2873 &source,
2874 0,
2875 false,
2876 )
2877 .unwrap()
2878 .unwrap();
2879 assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
2880 }
2881
2882 #[cfg(target_pointer_width = "64")]
2883 #[test]
2884 fn test_get_ruby_stack_trace_3_2_2() {
2885 let source = coredump_3_2_0();
2886 let vm_addr = 0xffffb8034578;
2887 let global_symbols_addr = Some(0xffffb8025340);
2888 let stack_trace = ruby_version::ruby_3_2_2::get_stack_trace::<CoreDump>(
2889 0,
2890 vm_addr,
2891 global_symbols_addr,
2892 &source,
2893 0,
2894 false,
2895 )
2896 .unwrap()
2897 .unwrap();
2898 assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
2899 }
2900
2901 #[cfg(target_pointer_width = "64")]
2902 #[test]
2903 fn test_get_ruby_stack_trace_3_2_3() {
2904 let source = coredump_3_2_0();
2905 let vm_addr = 0xffffb8034578;
2906 let global_symbols_addr = Some(0xffffb8025340);
2907 let stack_trace = ruby_version::ruby_3_2_3::get_stack_trace::<CoreDump>(
2908 0,
2909 vm_addr,
2910 global_symbols_addr,
2911 &source,
2912 0,
2913 false,
2914 )
2915 .unwrap()
2916 .unwrap();
2917 assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
2918 }
2919
2920 #[cfg(target_pointer_width = "64")]
2921 #[test]
2922 fn test_get_ruby_stack_trace_3_2_4() {
2923 let source = coredump_3_2_0();
2924 let vm_addr = 0xffffb8034578;
2925 let global_symbols_addr = Some(0xffffb8025340);
2926 let stack_trace = ruby_version::ruby_3_2_4::get_stack_trace::<CoreDump>(
2927 0,
2928 vm_addr,
2929 global_symbols_addr,
2930 &source,
2931 0,
2932 false,
2933 )
2934 .unwrap()
2935 .unwrap();
2936 assert_eq!(real_stack_trace_3_2_0(), stack_trace.trace);
2937 }
2938
2939 #[cfg(target_pointer_width = "64")]
2940 #[test]
2941 fn test_get_ruby_stack_trace_3_2_5() {
2942 let source = coredump_3_2_0();
2943 let vm_addr = 0xffffb8034578;
2944 let global_symbols_addr = Some(0xffffb8025340);
2945 let stack_trace = ruby_version::ruby_3_2_5::get_stack_trace::<CoreDump>(
2946 0,
2947 vm_addr,
2948 global_symbols_addr,
2949 &source,
2950 0,
2951 false,
2952 )
2953 .unwrap();
2954 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
2955 }
2956
2957 #[cfg(target_pointer_width = "64")]
2958 #[test]
2959 fn test_get_ruby_stack_trace_3_2_6() {
2960 let source = coredump_3_2_0();
2961 let vm_addr = 0xffffb8034578;
2962 let global_symbols_addr = Some(0xffffb8025340);
2963 let stack_trace = ruby_version::ruby_3_2_6::get_stack_trace::<CoreDump>(
2964 0,
2965 vm_addr,
2966 global_symbols_addr,
2967 &source,
2968 0,
2969 false,
2970 )
2971 .unwrap();
2972 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
2973 }
2974
2975 #[cfg(target_pointer_width = "64")]
2976 #[test]
2977 fn test_get_ruby_stack_trace_3_2_7() {
2978 let source = coredump_3_2_0();
2979 let vm_addr = 0xffffb8034578;
2980 let global_symbols_addr = Some(0xffffb8025340);
2981 let stack_trace = ruby_version::ruby_3_2_7::get_stack_trace::<CoreDump>(
2982 0,
2983 vm_addr,
2984 global_symbols_addr,
2985 &source,
2986 0,
2987 false,
2988 )
2989 .unwrap();
2990 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
2991 }
2992
2993 #[cfg(target_pointer_width = "64")]
2994 #[test]
2995 fn test_get_ruby_stack_trace_3_2_8() {
2996 let source = coredump_3_2_0();
2997 let vm_addr = 0xffffb8034578;
2998 let global_symbols_addr = Some(0xffffb8025340);
2999 let stack_trace = ruby_version::ruby_3_2_8::get_stack_trace::<CoreDump>(
3000 0,
3001 vm_addr,
3002 global_symbols_addr,
3003 &source,
3004 0,
3005 false,
3006 )
3007 .unwrap();
3008 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
3009 }
3010
3011 #[cfg(target_pointer_width = "64")]
3012 #[test]
3013 fn test_get_ruby_stack_trace_3_2_9() {
3014 let source = coredump_3_2_0();
3015 let vm_addr = 0xffffb8034578;
3016 let global_symbols_addr = Some(0xffffb8025340);
3017 let stack_trace = ruby_version::ruby_3_2_9::get_stack_trace::<CoreDump>(
3018 0,
3019 vm_addr,
3020 global_symbols_addr,
3021 &source,
3022 0,
3023 false,
3024 )
3025 .unwrap();
3026 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
3027 }
3028
3029 #[cfg(target_pointer_width = "64")]
3030 #[test]
3031 fn test_get_ruby_stack_trace_3_2_10() {
3032 let source = coredump_3_2_0();
3033 let vm_addr = 0xffffb8034578;
3034 let global_symbols_addr = Some(0xffffb8025340);
3035 let stack_trace = ruby_version::ruby_3_2_10::get_stack_trace::<CoreDump>(
3036 0,
3037 vm_addr,
3038 global_symbols_addr,
3039 &source,
3040 0,
3041 false,
3042 )
3043 .unwrap();
3044 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
3045 }
3046
3047 #[cfg(target_pointer_width = "64")]
3048 #[test]
3049 fn test_get_ruby_stack_trace_3_2_11() {
3050 let source = coredump_3_2_0();
3051 let vm_addr = 0xffffb8034578;
3052 let global_symbols_addr = Some(0xffffb8025340);
3053 let stack_trace = ruby_version::ruby_3_2_11::get_stack_trace::<CoreDump>(
3054 0,
3055 vm_addr,
3056 global_symbols_addr,
3057 &source,
3058 0,
3059 false,
3060 )
3061 .unwrap();
3062 assert_eq!(real_stack_trace_3_2_0(), stack_trace.unwrap().trace);
3063 }
3064
3065 #[cfg(target_pointer_width = "64")]
3066 #[test]
3067 fn test_get_ruby_stack_trace_3_3_0() {
3068 let source = coredump_3_3_0();
3069 let vm_addr = 0x7f43435f4988;
3070 let global_symbols_addr = Some(0x7f43435e3c60);
3071 let stack_trace = ruby_version::ruby_3_3_0::get_stack_trace::<CoreDump>(
3072 0,
3073 vm_addr,
3074 global_symbols_addr,
3075 &source,
3076 0,
3077 false,
3078 )
3079 .unwrap()
3080 .unwrap();
3081 assert_eq!(real_stack_trace_3_3_0(), stack_trace.trace);
3082 }
3083
3084 #[cfg(target_pointer_width = "64")]
3085 #[test]
3086 fn test_get_ruby_stack_trace_with_classes_3_3_0() {
3087 let source = coredump_with_classes_3_3_0();
3088 let vm_addr = 0x7f58cb7f4988;
3089 let global_symbols_addr = Some(0x7f58cb7e3c60);
3090 let stack_trace = ruby_version::ruby_3_3_0::get_stack_trace::<CoreDump>(
3091 0,
3092 vm_addr,
3093 global_symbols_addr,
3094 &source,
3095 0,
3096 false,
3097 )
3098 .unwrap();
3099 assert_eq!(
3100 real_stack_trace_with_classes_3_3_0(),
3101 stack_trace.unwrap().trace
3102 );
3103 }
3104
3105 #[cfg(target_pointer_width = "64")]
3106 #[test]
3107 fn test_get_ruby_stack_trace_3_3_1() {
3108 let source = coredump_3_3_0();
3109 let vm_addr = 0x7f43435f4988;
3110 let global_symbols_addr = Some(0x7f43435e3c60);
3111 let stack_trace = ruby_version::ruby_3_3_1::get_stack_trace::<CoreDump>(
3112 0,
3113 vm_addr,
3114 global_symbols_addr,
3115 &source,
3116 0,
3117 false,
3118 )
3119 .unwrap()
3120 .unwrap();
3121 assert_eq!(real_stack_trace_3_3_0(), stack_trace.trace);
3122 }
3123
3124 #[cfg(target_pointer_width = "64")]
3125 #[test]
3126 fn test_get_ruby_stack_trace_3_3_2() {
3127 let source = coredump_3_3_0();
3128 let vm_addr = 0x7f43435f4988;
3129 let global_symbols_addr = Some(0x7f43435e3c60);
3130 let stack_trace = ruby_version::ruby_3_3_2::get_stack_trace::<CoreDump>(
3131 0,
3132 vm_addr,
3133 global_symbols_addr,
3134 &source,
3135 0,
3136 false,
3137 )
3138 .unwrap()
3139 .unwrap();
3140 assert_eq!(real_stack_trace_3_3_0(), stack_trace.trace);
3141 }
3142
3143 #[cfg(target_pointer_width = "64")]
3144 #[test]
3145 fn test_get_ruby_stack_trace_3_3_3() {
3146 let source = coredump_3_3_0();
3147 let vm_addr = 0x7f43435f4988;
3148 let global_symbols_addr = Some(0x7f43435e3c60);
3149 let stack_trace = ruby_version::ruby_3_3_3::get_stack_trace::<CoreDump>(
3150 0,
3151 vm_addr,
3152 global_symbols_addr,
3153 &source,
3154 0,
3155 false,
3156 )
3157 .unwrap();
3158 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3159 }
3160
3161 #[cfg(target_pointer_width = "64")]
3162 #[test]
3163 fn test_get_ruby_stack_trace_3_3_4() {
3164 let source = coredump_3_3_0();
3165 let vm_addr = 0x7f43435f4988;
3166 let global_symbols_addr = Some(0x7f43435e3c60);
3167 let stack_trace = ruby_version::ruby_3_3_4::get_stack_trace::<CoreDump>(
3168 0,
3169 vm_addr,
3170 global_symbols_addr,
3171 &source,
3172 0,
3173 false,
3174 )
3175 .unwrap();
3176 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3177 }
3178
3179 #[cfg(target_pointer_width = "64")]
3180 #[test]
3181 fn test_get_ruby_stack_trace_3_3_5() {
3182 let source = coredump_3_3_0();
3183 let vm_addr = 0x7f43435f4988;
3184 let global_symbols_addr = Some(0x7f43435e3c60);
3185 let stack_trace = ruby_version::ruby_3_3_5::get_stack_trace::<CoreDump>(
3186 0,
3187 vm_addr,
3188 global_symbols_addr,
3189 &source,
3190 0,
3191 false,
3192 )
3193 .unwrap();
3194 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3195 }
3196
3197 #[cfg(target_pointer_width = "64")]
3198 #[test]
3199 fn test_get_ruby_stack_trace_3_3_6() {
3200 let source = coredump_3_3_0();
3201 let vm_addr = 0x7f43435f4988;
3202 let global_symbols_addr = Some(0x7f43435e3c60);
3203 let stack_trace = ruby_version::ruby_3_3_6::get_stack_trace::<CoreDump>(
3204 0,
3205 vm_addr,
3206 global_symbols_addr,
3207 &source,
3208 0,
3209 false,
3210 )
3211 .unwrap();
3212 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3213 }
3214
3215 #[cfg(target_pointer_width = "64")]
3216 #[test]
3217 fn test_get_ruby_stack_trace_3_3_7() {
3218 let source = coredump_3_3_0();
3219 let vm_addr = 0x7f43435f4988;
3220 let global_symbols_addr = Some(0x7f43435e3c60);
3221 let stack_trace = ruby_version::ruby_3_3_7::get_stack_trace::<CoreDump>(
3222 0,
3223 vm_addr,
3224 global_symbols_addr,
3225 &source,
3226 0,
3227 false,
3228 )
3229 .unwrap();
3230 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3231 }
3232
3233 #[cfg(target_pointer_width = "64")]
3234 #[test]
3235 fn test_get_ruby_stack_trace_3_3_8() {
3236 let source = coredump_3_3_0();
3237 let vm_addr = 0x7f43435f4988;
3238 let global_symbols_addr = Some(0x7f43435e3c60);
3239 let stack_trace = ruby_version::ruby_3_3_8::get_stack_trace::<CoreDump>(
3240 0,
3241 vm_addr,
3242 global_symbols_addr,
3243 &source,
3244 0,
3245 false,
3246 )
3247 .unwrap();
3248 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3249 }
3250
3251 #[cfg(target_pointer_width = "64")]
3252 #[test]
3253 fn test_get_ruby_stack_trace_3_3_9() {
3254 let source = coredump_3_3_0();
3255 let vm_addr = 0x7f43435f4988;
3256 let global_symbols_addr = Some(0x7f43435e3c60);
3257 let stack_trace = ruby_version::ruby_3_3_9::get_stack_trace::<CoreDump>(
3258 0,
3259 vm_addr,
3260 global_symbols_addr,
3261 &source,
3262 0,
3263 false,
3264 )
3265 .unwrap();
3266 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3267 }
3268
3269 #[cfg(target_pointer_width = "64")]
3270 #[test]
3271 fn test_get_ruby_stack_trace_3_3_10() {
3272 let source = coredump_3_3_0();
3273 let vm_addr = 0x7f43435f4988;
3274 let global_symbols_addr = Some(0x7f43435e3c60);
3275 let stack_trace = ruby_version::ruby_3_3_10::get_stack_trace::<CoreDump>(
3276 0,
3277 vm_addr,
3278 global_symbols_addr,
3279 &source,
3280 0,
3281 false,
3282 )
3283 .unwrap();
3284 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3285 }
3286
3287 #[cfg(target_pointer_width = "64")]
3288 #[test]
3289 fn test_get_ruby_stack_trace_3_3_11() {
3290 let source = coredump_3_3_0();
3291 let vm_addr = 0x7f43435f4988;
3292 let global_symbols_addr = Some(0x7f43435e3c60);
3293 let stack_trace = ruby_version::ruby_3_3_11::get_stack_trace::<CoreDump>(
3294 0,
3295 vm_addr,
3296 global_symbols_addr,
3297 &source,
3298 0,
3299 false,
3300 )
3301 .unwrap();
3302 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3303 }
3304
3305 #[cfg(target_pointer_width = "64")]
3306 #[test]
3307 fn test_get_ruby_stack_trace_3_4_0() {
3308 let source = coredump_3_3_0();
3309 let vm_addr = 0x7f43435f4988;
3310 let global_symbols_addr = Some(0x7f43435e3c60);
3311 let stack_trace = ruby_version::ruby_3_4_0::get_stack_trace::<CoreDump>(
3312 0,
3313 vm_addr,
3314 global_symbols_addr,
3315 &source,
3316 0,
3317 false,
3318 )
3319 .unwrap();
3320 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3321 }
3322
3323 #[cfg(target_pointer_width = "64")]
3324 #[test]
3325 fn test_get_ruby_stack_trace_3_4_1() {
3326 let source = coredump_3_3_0();
3327 let vm_addr = 0x7f43435f4988;
3328 let global_symbols_addr = Some(0x7f43435e3c60);
3329 let stack_trace = ruby_version::ruby_3_4_1::get_stack_trace::<CoreDump>(
3330 0,
3331 vm_addr,
3332 global_symbols_addr,
3333 &source,
3334 0,
3335 false,
3336 )
3337 .unwrap();
3338 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3339 }
3340
3341 #[cfg(target_pointer_width = "64")]
3342 #[test]
3343 fn test_get_ruby_stack_trace_3_4_2() {
3344 let source = coredump_3_3_0();
3345 let vm_addr = 0x7f43435f4988;
3346 let global_symbols_addr = Some(0x7f43435e3c60);
3347 let stack_trace = ruby_version::ruby_3_4_2::get_stack_trace::<CoreDump>(
3348 0,
3349 vm_addr,
3350 global_symbols_addr,
3351 &source,
3352 0,
3353 false,
3354 )
3355 .unwrap();
3356 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3357 }
3358
3359 #[cfg(target_pointer_width = "64")]
3360 #[test]
3361 fn test_get_ruby_stack_trace_3_4_3() {
3362 let source = coredump_3_3_0();
3363 let vm_addr = 0x7f43435f4988;
3364 let global_symbols_addr = Some(0x7f43435e3c60);
3365 let stack_trace = ruby_version::ruby_3_4_3::get_stack_trace::<CoreDump>(
3366 0,
3367 vm_addr,
3368 global_symbols_addr,
3369 &source,
3370 0,
3371 false,
3372 )
3373 .unwrap();
3374 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3375 }
3376
3377 #[cfg(target_pointer_width = "64")]
3378 #[test]
3379 fn test_get_ruby_stack_trace_3_4_4() {
3380 let source = coredump_3_3_0();
3381 let vm_addr = 0x7f43435f4988;
3382 let global_symbols_addr = Some(0x7f43435e3c60);
3383 let stack_trace = ruby_version::ruby_3_4_4::get_stack_trace::<CoreDump>(
3384 0,
3385 vm_addr,
3386 global_symbols_addr,
3387 &source,
3388 0,
3389 false,
3390 )
3391 .unwrap();
3392 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3393 }
3394
3395 #[cfg(target_pointer_width = "64")]
3396 #[test]
3397 fn test_get_ruby_stack_trace_3_4_5() {
3398 let source = coredump_3_3_0();
3399 let vm_addr = 0x7f43435f4988;
3400 let global_symbols_addr = Some(0x7f43435e3c60);
3401 let stack_trace = ruby_version::ruby_3_4_5::get_stack_trace::<CoreDump>(
3402 0,
3403 vm_addr,
3404 global_symbols_addr,
3405 &source,
3406 0,
3407 false,
3408 )
3409 .unwrap();
3410 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3411 }
3412
3413 #[cfg(target_pointer_width = "64")]
3414 #[test]
3415 fn test_get_ruby_stack_trace_complex_3_4_5() {
3416 let source = coredump_complex_3_4_5();
3417 let vm_addr = 0x7f271feb5390;
3418 let global_symbols_addr = Some(0x7f271fea3dc0);
3419 let stack_trace = ruby_version::ruby_3_3_0::get_stack_trace::<CoreDump>(
3420 0,
3421 vm_addr,
3422 global_symbols_addr,
3423 &source,
3424 0,
3425 false,
3426 )
3427 .unwrap();
3428 assert_eq!(
3429 real_complex_trace_with_classes_3_4_5(),
3430 stack_trace.unwrap().trace
3431 );
3432 }
3433
3434 #[cfg(target_pointer_width = "64")]
3435 #[test]
3436 fn test_get_ruby_stack_trace_3_4_6() {
3437 let source = coredump_3_3_0();
3438 let vm_addr = 0x7f43435f4988;
3439 let global_symbols_addr = Some(0x7f43435e3c60);
3440 let stack_trace = ruby_version::ruby_3_4_6::get_stack_trace::<CoreDump>(
3441 0,
3442 vm_addr,
3443 global_symbols_addr,
3444 &source,
3445 0,
3446 false,
3447 )
3448 .unwrap();
3449 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3450 }
3451
3452 #[cfg(target_pointer_width = "64")]
3453 #[test]
3454 fn test_get_ruby_stack_trace_3_4_7() {
3455 let source = coredump_3_3_0();
3456 let vm_addr = 0x7f43435f4988;
3457 let global_symbols_addr = Some(0x7f43435e3c60);
3458 let stack_trace = ruby_version::ruby_3_4_7::get_stack_trace::<CoreDump>(
3459 0,
3460 vm_addr,
3461 global_symbols_addr,
3462 &source,
3463 0,
3464 false,
3465 )
3466 .unwrap();
3467 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3468 }
3469
3470 #[cfg(target_pointer_width = "64")]
3471 #[test]
3472 fn test_get_ruby_stack_trace_3_4_8() {
3473 let source = coredump_3_3_0();
3474 let vm_addr = 0x7f43435f4988;
3475 let global_symbols_addr = Some(0x7f43435e3c60);
3476 let stack_trace = ruby_version::ruby_3_4_8::get_stack_trace::<CoreDump>(
3477 0,
3478 vm_addr,
3479 global_symbols_addr,
3480 &source,
3481 0,
3482 false,
3483 )
3484 .unwrap();
3485 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3486 }
3487
3488 #[cfg(target_pointer_width = "64")]
3489 #[test]
3490 fn test_get_ruby_stack_trace_3_4_9() {
3491 let source = coredump_3_3_0();
3492 let vm_addr = 0x7f43435f4988;
3493 let global_symbols_addr = Some(0x7f43435e3c60);
3494 let stack_trace = ruby_version::ruby_3_4_9::get_stack_trace::<CoreDump>(
3495 0,
3496 vm_addr,
3497 global_symbols_addr,
3498 &source,
3499 0,
3500 false,
3501 )
3502 .unwrap();
3503 assert_eq!(real_stack_trace_3_3_0(), stack_trace.unwrap().trace);
3504 }
3505
3506 #[cfg(target_pointer_width = "64")]
3507 #[test]
3508 fn test_get_ruby_stack_trace_4_0_0() {
3509 let source = coredump_4_0_0();
3510 let vm_addr = 0x7fa56b875738;
3511 let global_symbols_addr = Some(0x7fa56b862b50);
3512 let stack_trace = ruby_version::ruby_4_0_0::get_stack_trace::<CoreDump>(
3513 0,
3514 vm_addr,
3515 global_symbols_addr,
3516 &source,
3517 0,
3518 false,
3519 )
3520 .unwrap()
3521 .unwrap();
3522 assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
3523 }
3524
3525 #[cfg(target_pointer_width = "64")]
3526 #[test]
3527 fn test_get_ruby_stack_trace_4_0_1() {
3528 let source = coredump_4_0_0();
3529 let vm_addr = 0x7fa56b875738;
3530 let global_symbols_addr = Some(0x7fa56b862b50);
3531 let stack_trace = ruby_version::ruby_4_0_1::get_stack_trace::<CoreDump>(
3532 0,
3533 vm_addr,
3534 global_symbols_addr,
3535 &source,
3536 0,
3537 false,
3538 )
3539 .unwrap()
3540 .unwrap();
3541 assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
3542 }
3543
3544 #[cfg(target_pointer_width = "64")]
3545 #[test]
3546 fn test_get_ruby_stack_trace_4_0_2() {
3547 let source = coredump_4_0_0();
3548 let vm_addr = 0x7fa56b875738;
3549 let global_symbols_addr = Some(0x7fa56b862b50);
3550 let stack_trace = ruby_version::ruby_4_0_2::get_stack_trace::<CoreDump>(
3551 0,
3552 vm_addr,
3553 global_symbols_addr,
3554 &source,
3555 0,
3556 false,
3557 )
3558 .unwrap()
3559 .unwrap();
3560 assert_eq!(real_stack_trace_4_0_0(), stack_trace.trace);
3561 }
3562
3563 #[rstest]
3564 #[case::no_class_not_singleton("", "foo", false, "foo")]
3565 #[case::class_not_singleton("ClassA", "foo", false, "ClassA#foo")]
3566 #[case::class_with_singleton("ClassA", "foo", true, "ClassA.foo")]
3567 #[case::empty_returns_empty("", "", false, "")]
3568 fn test_qualified_method_name(
3569 #[case] class_path: &str,
3570 #[case] method_name: &str,
3571 #[case] singleton: bool,
3572 #[case] expected: &str,
3573 ) {
3574 let qualified =
3575 ruby_version::ruby_3_3_0::qualified_method_name(class_path, method_name, singleton);
3576 assert_eq!(expected.to_string(), qualified);
3577 }
3578 #[rstest]
3579 #[case::no_class_uses_label("", "block in foo", "foo", "foo", false, "block in foo")]
3580 #[case::no_method_uses_label("", "block in foo", "foo", "", false, "block in foo")]
3581 #[case::no_class_no_base_label_no_method_uses_label(
3582 "",
3583 "block in foo",
3584 "",
3585 "",
3586 false,
3587 "block in foo"
3588 )]
3589 #[case::class_uses_label_prefix(
3590 "ClassA",
3591 "block in foo",
3592 "foo",
3593 "foo",
3594 false,
3595 "block in ClassA#foo"
3596 )]
3597 #[case::class_uses_label_prefix_singleton(
3598 "ClassA",
3599 "block in foo",
3600 "foo",
3601 "foo",
3602 true,
3603 "block in ClassA.foo"
3604 )]
3605 fn test_profile_frame_full_label(
3606 #[case] class_path: &str,
3607 #[case] label: &str,
3608 #[case] base_label: &str,
3609 #[case] method_name: &str,
3610 #[case] singleton: bool,
3611 #[case] expected: &str,
3612 ) {
3613 let full_label = ruby_version::ruby_3_3_0::profile_frame_full_label(
3614 class_path,
3615 label,
3616 base_label,
3617 method_name,
3618 singleton,
3619 );
3620 assert_eq!(expected.to_string(), full_label);
3621 }
3622}