@@ -162,6 +162,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
162162 }
163163 kprintf ("s:%04" PRIdPTRDIFF " " , cfp -> sp - ec -> vm_stack );
164164 kprintf (ep_in_heap == ' ' ? "e:%06" PRIdPTRDIFF " " : "E:%06" PRIxPTRDIFF " " , ep % 10000 );
165+ kprintf ("l:%s " , VM_ENV_LOCAL_P (cfp -> ep ) ? "y" : "n" );
165166 if (ns ) {
166167 kprintf ("n:%04ld " , ns -> ns_id % 10000 );
167168 }
@@ -220,6 +221,247 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
220221 return false;
221222}
222223
224+ static inline const rb_control_frame_t *
225+ vmdebug_search_cf_from_ep (const rb_execution_context_t * ec , const rb_control_frame_t * cfp , const VALUE * const ep )
226+ {
227+ if (!ep ) {
228+ return NULL ;
229+ }
230+ else {
231+ const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME (ec ); /* end of control frame pointer */
232+
233+ while (cfp < eocfp ) {
234+ if (cfp -> ep == ep ) {
235+ return cfp ;
236+ }
237+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME (cfp );
238+ }
239+
240+ return NULL ;
241+ }
242+ }
243+
244+ static rb_callable_method_entry_t *
245+ vmdebug_env_method_entry_unchecked (VALUE obj , int can_be_svar )
246+ {
247+ if (obj == Qfalse ) return NULL ;
248+
249+ switch (imemo_type (obj )) {
250+ case imemo_ment :
251+ return (rb_callable_method_entry_t * )obj ;
252+ case imemo_cref :
253+ return NULL ;
254+ case imemo_svar :
255+ if (can_be_svar ) {
256+ return vmdebug_env_method_entry_unchecked (((struct vm_svar * )obj )-> cref_or_me , FALSE);
257+ }
258+ default :
259+ return NULL ;
260+ }
261+ }
262+
263+ static const rb_callable_method_entry_t *
264+ vmdebug_frame_method_entry_unchecked (const VALUE * ep )
265+ {
266+ rb_callable_method_entry_t * me ;
267+
268+ while (!VM_ENV_LOCAL_P_UNCHECKED (ep )) {
269+ if ((me = vmdebug_env_method_entry_unchecked (ep [VM_ENV_DATA_INDEX_ME_CREF ], FALSE)) != NULL ) return me ;
270+ ep = VM_ENV_PREV_EP_UNCHECKED (ep );
271+ }
272+
273+ return vmdebug_env_method_entry_unchecked (ep [VM_ENV_DATA_INDEX_ME_CREF ], TRUE);
274+ }
275+
276+ static bool
277+ namespace_env_dump (const rb_execution_context_t * ec , const VALUE * env , const rb_control_frame_t * checkpoint_cfp , FILE * errout )
278+ {
279+ ptrdiff_t pc = -1 ;
280+ ptrdiff_t ep = env - ec -> vm_stack ;
281+ char ep_in_heap = ' ' ;
282+ char posbuf [MAX_POSBUF + 1 ];
283+ int line = 0 ;
284+ const char * magic , * iseq_name = "-" ;
285+ VALUE tmp ;
286+ const rb_iseq_t * iseq = NULL ;
287+ const rb_namespace_t * ns = NULL ;
288+ const rb_control_frame_t * cfp = vmdebug_search_cf_from_ep (ec , checkpoint_cfp , env );
289+ const rb_callable_method_entry_t * me = vmdebug_frame_method_entry_unchecked (env );
290+
291+ if (ep < 0 || (size_t )ep > ec -> vm_stack_size ) {
292+ if (cfp ) {
293+ ep = (ptrdiff_t )cfp -> ep ;
294+ ep_in_heap = 'p' ;
295+ }
296+ }
297+
298+ switch (VM_ENV_FLAGS_UNCHECKED (env , VM_FRAME_MAGIC_MASK )) {
299+ case VM_FRAME_MAGIC_TOP :
300+ magic = "TOP" ;
301+ ns = VM_ENV_NAMESPACE_UNCHECKED (env );
302+ break ;
303+ case VM_FRAME_MAGIC_METHOD :
304+ magic = "METHOD" ;
305+ if (me ) {
306+ ns = me -> def -> ns ;
307+ }
308+ break ;
309+ case VM_FRAME_MAGIC_CLASS :
310+ magic = "CLASS" ;
311+ ns = VM_ENV_NAMESPACE_UNCHECKED (env );
312+ break ;
313+ case VM_FRAME_MAGIC_BLOCK :
314+ magic = "BLOCK" ;
315+ break ;
316+ case VM_FRAME_MAGIC_CFUNC :
317+ magic = "CFUNC" ;
318+ if (me ) {
319+ ns = me -> def -> ns ;
320+ }
321+ break ;
322+ case VM_FRAME_MAGIC_IFUNC :
323+ magic = "IFUNC" ;
324+ break ;
325+ case VM_FRAME_MAGIC_EVAL :
326+ magic = "EVAL" ;
327+ break ;
328+ case VM_FRAME_MAGIC_RESCUE :
329+ magic = "RESCUE" ;
330+ break ;
331+ case VM_FRAME_MAGIC_DUMMY :
332+ magic = "DUMMY" ;
333+ break ;
334+ case 0 :
335+ magic = "------" ;
336+ break ;
337+ default :
338+ magic = "(none)" ;
339+ break ;
340+ }
341+
342+ if (cfp && cfp -> iseq != 0 ) {
343+ #define RUBY_VM_IFUNC_P (ptr ) IMEMO_TYPE_P(ptr, imemo_ifunc)
344+ if (RUBY_VM_IFUNC_P (cfp -> iseq )) {
345+ iseq_name = "<ifunc>" ;
346+ }
347+ else if (SYMBOL_P ((VALUE )cfp -> iseq )) {
348+ tmp = rb_sym2str ((VALUE )cfp -> iseq );
349+ iseq_name = RSTRING_PTR (tmp );
350+ snprintf (posbuf , MAX_POSBUF , ":%s" , iseq_name );
351+ line = -1 ;
352+ }
353+ else {
354+ if (cfp -> pc ) {
355+ iseq = cfp -> iseq ;
356+ pc = cfp -> pc - ISEQ_BODY (iseq )-> iseq_encoded ;
357+ iseq_name = RSTRING_PTR (ISEQ_BODY (iseq )-> location .label );
358+ if (pc >= 0 && pc <= ISEQ_BODY (iseq )-> iseq_size ) {
359+ line = rb_vm_get_sourceline (cfp );
360+ }
361+ if (line ) {
362+ snprintf (posbuf , MAX_POSBUF , "%s:%d" , RSTRING_PTR (rb_iseq_path (iseq )), line );
363+ }
364+ }
365+ else {
366+ iseq_name = "<dummy_frame>" ;
367+ }
368+ }
369+ }
370+ else if (me != NULL && IMEMO_TYPE_P (me , imemo_ment )) {
371+ iseq_name = rb_id2name (me -> def -> original_id );
372+ snprintf (posbuf , MAX_POSBUF , ":%s" , iseq_name );
373+ line = -1 ;
374+ }
375+
376+ if (cfp ) {
377+ kprintf ("c:%04" PRIdPTRDIFF " " ,
378+ ((rb_control_frame_t * )(ec -> vm_stack + ec -> vm_stack_size ) - cfp ));
379+ }
380+ else {
381+ kprintf ("c:---- " );
382+ }
383+ kprintf (ep_in_heap == ' ' ? "e:%06" PRIdPTRDIFF " " : "E:%06" PRIxPTRDIFF " " , ep % 10000 );
384+ kprintf ("l:%s " , VM_ENV_LOCAL_P (env ) ? "y" : "n" );
385+ if (ns ) {
386+ kprintf ("n:%04ld " , ns -> ns_id % 10000 );
387+ }
388+ else {
389+ kprintf ("n:---- " );
390+ }
391+ kprintf ("%-6s" , magic );
392+ if (line ) {
393+ kprintf (" %s" , posbuf );
394+ }
395+ if (VM_ENV_FLAGS_UNCHECKED (env , VM_FRAME_FLAG_FINISH ) != 0 ) {
396+ kprintf (" [FINISH]" );
397+ }
398+ kprintf ("\n" );
399+ return true;
400+ error :
401+ return false;
402+ }
403+
404+ static bool
405+ namespace_env_dump_unchecked (const rb_execution_context_t * ec , const VALUE * env , const rb_control_frame_t * checkpoint_cfp , FILE * errout )
406+ {
407+ if (env == NULL ) {
408+ kprintf ("c:---- e:000000 l:- n:---- (none)\n" );
409+ return true;
410+ }
411+ else {
412+ return namespace_env_dump (ec , env , checkpoint_cfp , errout );
413+ }
414+ error :
415+ return false;
416+ }
417+
418+ bool
419+ rb_vmdebug_namespace_env_dump_raw (const rb_execution_context_t * ec , const rb_control_frame_t * current_cfp , FILE * errout )
420+ {
421+ // See VM_EP_RUBY_LEP for the original logic
422+ const VALUE * ep = current_cfp -> ep ;
423+ const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME (ec ); /* end of control frame pointer */
424+ const rb_control_frame_t * cfp = NULL , * checkpoint_cfp = current_cfp ;
425+
426+ kprintf ("-- Namespace detection information "
427+ "-----------------------------------------\n" );
428+
429+ namespace_env_dump_unchecked (ec , ep , checkpoint_cfp , errout );
430+
431+ while (!VM_ENV_LOCAL_P (ep ) || VM_ENV_FRAME_TYPE_P (ep , VM_FRAME_MAGIC_CFUNC )) {
432+ while (!VM_ENV_LOCAL_P (ep )) {
433+ ep = VM_ENV_PREV_EP (ep );
434+ namespace_env_dump_unchecked (ec , ep , checkpoint_cfp , errout );
435+ }
436+ while (VM_ENV_FLAGS (ep , VM_FRAME_FLAG_CFRAME ) != 0 ) {
437+ if (!cfp ) {
438+ cfp = vmdebug_search_cf_from_ep (ec , checkpoint_cfp , ep );
439+ }
440+ if (!cfp ) {
441+ goto stop ;
442+ }
443+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME (cfp );
444+ if (cfp >= eocfp ) {
445+ kprintf ("[PREVIOUS CONTROL FRAME IS OUT OF BOUND]\n" );
446+ goto stop ;
447+ }
448+ ep = cfp -> ep ;
449+ namespace_env_dump_unchecked (ec , ep , checkpoint_cfp , errout );
450+ if (!ep ) {
451+ goto stop ;
452+ }
453+ }
454+ checkpoint_cfp = cfp ;
455+ cfp = NULL ;
456+ }
457+ stop :
458+ kprintf ("\n" );
459+ return true;
460+
461+ error :
462+ return false;
463+ }
464+
223465bool
224466rb_vmdebug_stack_dump_raw (const rb_execution_context_t * ec , const rb_control_frame_t * cfp , FILE * errout )
225467{
@@ -1132,6 +1374,7 @@ rb_dump_machine_register(FILE *errout, const ucontext_t *ctx)
11321374bool
11331375rb_vm_bugreport (const void * ctx , FILE * errout )
11341376{
1377+ const char * ns_env = getenv ("RUBY_BUGREPORT_NAMESPACE_ENV" );
11351378 const char * cmd = getenv ("RUBY_ON_BUG" );
11361379 if (cmd ) {
11371380 char buf [0x100 ];
@@ -1175,6 +1418,9 @@ rb_vm_bugreport(const void *ctx, FILE *errout)
11751418
11761419 if (vm && ec ) {
11771420 rb_vmdebug_stack_dump_raw (ec , ec -> cfp , errout );
1421+ if (ns_env ) {
1422+ rb_vmdebug_namespace_env_dump_raw (ec , ec -> cfp , errout );
1423+ }
11781424 rb_backtrace_print_as_bugreport (errout );
11791425 kputs ("\n" );
11801426 // If we get here, hopefully things are intact enough that
0 commit comments