debug 1.7.2 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +47 -41
- data/debug.gemspec +3 -3
- data/ext/debug/debug.c +6 -0
- data/ext/debug/extconf.rb +1 -0
- data/ext/debug/iseq_collector.c +2 -0
- data/lib/debug/client.rb +3 -2
- data/lib/debug/config.rb +13 -6
- data/lib/debug/console.rb +8 -29
- data/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/lib/debug/frame_info.rb +9 -0
- data/lib/debug/irb_integration.rb +27 -0
- data/lib/debug/server.rb +5 -3
- data/lib/debug/server_cdp.rb +11 -13
- data/lib/debug/server_dap.rb +191 -160
- data/lib/debug/session.rb +63 -29
- data/lib/debug/source_repository.rb +1 -1
- data/lib/debug/thread_client.rb +42 -24
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +41 -41
- metadata +12 -10
    
        data/lib/debug/server_dap.rb
    CHANGED
    
    | @@ -274,198 +274,225 @@ module DEBUGGER__ | |
| 274 274 | 
             
                  retry
         | 
| 275 275 | 
             
                end
         | 
| 276 276 |  | 
| 277 | 
            +
                def load_extensions req
         | 
| 278 | 
            +
                  if exts = req.dig('arguments', 'rdbgExtensions')
         | 
| 279 | 
            +
                    exts.each{|ext|
         | 
| 280 | 
            +
                      require_relative "dap_custom/#{File.basename(ext)}"
         | 
| 281 | 
            +
                    }
         | 
| 282 | 
            +
                  end
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                  if scripts = req.dig('arguments', 'rdbgInitialScripts')
         | 
| 285 | 
            +
                    scripts.each do |script|
         | 
| 286 | 
            +
                      begin
         | 
| 287 | 
            +
                        eval(script)
         | 
| 288 | 
            +
                      rescue Exception => e
         | 
| 289 | 
            +
                        puts e.message
         | 
| 290 | 
            +
                        puts e.backtrace.inspect
         | 
| 291 | 
            +
                      end
         | 
| 292 | 
            +
                    end
         | 
| 293 | 
            +
                  end
         | 
| 294 | 
            +
                end
         | 
| 295 | 
            +
             | 
| 277 296 | 
             
                def process
         | 
| 278 297 | 
             
                  while req = recv_request
         | 
| 279 | 
            -
                     | 
| 280 | 
            -
             | 
| 298 | 
            +
                    process_request(req)
         | 
| 299 | 
            +
                  end
         | 
| 300 | 
            +
                ensure
         | 
| 301 | 
            +
                  send_event :terminated unless @sock.closed?
         | 
| 302 | 
            +
                end
         | 
| 281 303 |  | 
| 282 | 
            -
             | 
| 304 | 
            +
                def process_request req
         | 
| 305 | 
            +
                  raise "not a request: #{req.inspect}" unless req['type'] == 'request'
         | 
| 306 | 
            +
                  args = req.dig('arguments')
         | 
| 283 307 |  | 
| 284 | 
            -
             | 
| 285 | 
            -
                    when 'launch'
         | 
| 286 | 
            -
                      send_response req
         | 
| 287 | 
            -
                      # `launch` runs on debuggee on the same file system
         | 
| 288 | 
            -
                      UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
         | 
| 289 | 
            -
                      @nonstop = true
         | 
| 308 | 
            +
                  case req['command']
         | 
| 290 309 |  | 
| 291 | 
            -
             | 
| 292 | 
            -
             | 
| 293 | 
            -
             | 
| 310 | 
            +
                  ## boot/configuration
         | 
| 311 | 
            +
                  when 'launch'
         | 
| 312 | 
            +
                    send_response req
         | 
| 313 | 
            +
                    # `launch` runs on debuggee on the same file system
         | 
| 314 | 
            +
                    UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
         | 
| 315 | 
            +
                    @nonstop = true
         | 
| 294 316 |  | 
| 295 | 
            -
             | 
| 296 | 
            -
                        @nonstop = true
         | 
| 297 | 
            -
                      else
         | 
| 298 | 
            -
                        @nonstop = false
         | 
| 299 | 
            -
                      end
         | 
| 317 | 
            +
                    load_extensions req
         | 
| 300 318 |  | 
| 301 | 
            -
             | 
| 302 | 
            -
             | 
| 319 | 
            +
                  when 'attach'
         | 
| 320 | 
            +
                    send_response req
         | 
| 321 | 
            +
                    UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap')
         | 
| 303 322 |  | 
| 304 | 
            -
             | 
| 305 | 
            -
             | 
| 306 | 
            -
             | 
| 307 | 
            -
             | 
| 308 | 
            -
             | 
| 309 | 
            -
                                                threadId: 1, # maybe ...
         | 
| 310 | 
            -
                                                allThreadsStopped: true
         | 
| 311 | 
            -
                        end
         | 
| 312 | 
            -
                      end
         | 
| 323 | 
            +
                    if req.dig('arguments', 'nonstop') == true
         | 
| 324 | 
            +
                      @nonstop = true
         | 
| 325 | 
            +
                    else
         | 
| 326 | 
            +
                      @nonstop = false
         | 
| 327 | 
            +
                    end
         | 
| 313 328 |  | 
| 314 | 
            -
                     | 
| 315 | 
            -
                      req_path = args.dig('source', 'path')
         | 
| 316 | 
            -
                      path = UI_DAP.local_to_remote_path(req_path)
         | 
| 317 | 
            -
                      if path
         | 
| 318 | 
            -
                        SESSION.clear_line_breakpoints path
         | 
| 319 | 
            -
             | 
| 320 | 
            -
                        bps = []
         | 
| 321 | 
            -
                        args['breakpoints'].each{|bp|
         | 
| 322 | 
            -
                          line = bp['line']
         | 
| 323 | 
            -
                          if cond = bp['condition']
         | 
| 324 | 
            -
                            bps << SESSION.add_line_breakpoint(path, line, cond: cond)
         | 
| 325 | 
            -
                          else
         | 
| 326 | 
            -
                            bps << SESSION.add_line_breakpoint(path, line)
         | 
| 327 | 
            -
                          end
         | 
| 328 | 
            -
                        }
         | 
| 329 | 
            -
                        send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
         | 
| 330 | 
            -
                      else
         | 
| 331 | 
            -
                        send_response req, success: false, message: "#{req_path} is not available"
         | 
| 332 | 
            -
                      end
         | 
| 329 | 
            +
                    load_extensions req
         | 
| 333 330 |  | 
| 334 | 
            -
             | 
| 335 | 
            -
             | 
| 331 | 
            +
                  when 'configurationDone'
         | 
| 332 | 
            +
                    send_response req
         | 
| 336 333 |  | 
| 337 | 
            -
                     | 
| 338 | 
            -
                       | 
| 339 | 
            -
             | 
| 340 | 
            -
             | 
| 341 | 
            -
             | 
| 342 | 
            -
             | 
| 343 | 
            -
             | 
| 344 | 
            -
             | 
| 345 | 
            -
             | 
| 346 | 
            -
                            nil
         | 
| 347 | 
            -
                          end
         | 
| 348 | 
            -
                          {
         | 
| 349 | 
            -
                            verified: !bp.nil?,
         | 
| 350 | 
            -
                            message: bp.inspect,
         | 
| 351 | 
            -
                          }
         | 
| 352 | 
            -
                        }
         | 
| 334 | 
            +
                    if @nonstop
         | 
| 335 | 
            +
                      @q_msg << 'continue'
         | 
| 336 | 
            +
                    else
         | 
| 337 | 
            +
                      if SESSION.in_subsession?
         | 
| 338 | 
            +
                        send_event 'stopped', reason: 'pause',
         | 
| 339 | 
            +
                                              threadId: 1, # maybe ...
         | 
| 340 | 
            +
                                              allThreadsStopped: true
         | 
| 341 | 
            +
                      end
         | 
| 342 | 
            +
                    end
         | 
| 353 343 |  | 
| 354 | 
            -
             | 
| 344 | 
            +
                  when 'setBreakpoints'
         | 
| 345 | 
            +
                    req_path = args.dig('source', 'path')
         | 
| 346 | 
            +
                    path = UI_DAP.local_to_remote_path(req_path)
         | 
| 347 | 
            +
                    if path
         | 
| 348 | 
            +
                      SESSION.clear_line_breakpoints path
         | 
| 349 | 
            +
             | 
| 350 | 
            +
                      bps = []
         | 
| 351 | 
            +
                      args['breakpoints'].each{|bp|
         | 
| 352 | 
            +
                        line = bp['line']
         | 
| 353 | 
            +
                        if cond = bp['condition']
         | 
| 354 | 
            +
                          bps << SESSION.add_line_breakpoint(path, line, cond: cond)
         | 
| 355 | 
            +
                        else
         | 
| 356 | 
            +
                          bps << SESSION.add_line_breakpoint(path, line)
         | 
| 357 | 
            +
                        end
         | 
| 358 | 
            +
                      }
         | 
| 359 | 
            +
                      send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
         | 
| 360 | 
            +
                    else
         | 
| 361 | 
            +
                      send_response req, success: false, message: "#{req_path} is not available"
         | 
| 362 | 
            +
                    end
         | 
| 355 363 |  | 
| 356 | 
            -
             | 
| 357 | 
            -
             | 
| 364 | 
            +
                  when 'setFunctionBreakpoints'
         | 
| 365 | 
            +
                    send_response req
         | 
| 366 | 
            +
             | 
| 367 | 
            +
                  when 'setExceptionBreakpoints'
         | 
| 368 | 
            +
                    process_filter = ->(filter_id, cond = nil) {
         | 
| 369 | 
            +
                      bp =
         | 
| 370 | 
            +
                        case filter_id
         | 
| 371 | 
            +
                        when 'any'
         | 
| 372 | 
            +
                          SESSION.add_catch_breakpoint 'Exception', cond: cond
         | 
| 373 | 
            +
                        when 'RuntimeError'
         | 
| 374 | 
            +
                          SESSION.add_catch_breakpoint 'RuntimeError', cond: cond
         | 
| 375 | 
            +
                        else
         | 
| 376 | 
            +
                          nil
         | 
| 377 | 
            +
                        end
         | 
| 378 | 
            +
                        {
         | 
| 379 | 
            +
                          verified: !bp.nil?,
         | 
| 380 | 
            +
                          message: bp.inspect,
         | 
| 358 381 | 
             
                        }
         | 
| 382 | 
            +
                      }
         | 
| 383 | 
            +
             | 
| 384 | 
            +
                      SESSION.clear_catch_breakpoints 'Exception', 'RuntimeError'
         | 
| 359 385 |  | 
| 360 | 
            -
             | 
| 361 | 
            -
                        process_filter.call( | 
| 386 | 
            +
                      filters = args.fetch('filters').map {|filter_id|
         | 
| 387 | 
            +
                        process_filter.call(filter_id)
         | 
| 362 388 | 
             
                      }
         | 
| 363 389 |  | 
| 364 | 
            -
                       | 
| 390 | 
            +
                      filters += args.fetch('filterOptions', {}).map{|bp_info|
         | 
| 391 | 
            +
                      process_filter.call(bp_info['filterId'], bp_info['condition'])
         | 
| 392 | 
            +
                    }
         | 
| 365 393 |  | 
| 366 | 
            -
                     | 
| 367 | 
            -
                      terminate = args.fetch("terminateDebuggee", false)
         | 
| 394 | 
            +
                    send_response req, breakpoints: filters
         | 
| 368 395 |  | 
| 369 | 
            -
             | 
| 370 | 
            -
             | 
| 396 | 
            +
                  when 'disconnect'
         | 
| 397 | 
            +
                    terminate = args.fetch("terminateDebuggee", false)
         | 
| 371 398 |  | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 374 | 
            -
                          @q_msg << 'kill!'
         | 
| 375 | 
            -
                        else
         | 
| 376 | 
            -
                          @q_msg << 'continue'
         | 
| 377 | 
            -
                        end
         | 
| 378 | 
            -
                      else
         | 
| 379 | 
            -
                        if terminate
         | 
| 380 | 
            -
                          @q_msg << 'kill!'
         | 
| 381 | 
            -
                          pause
         | 
| 382 | 
            -
                        end
         | 
| 383 | 
            -
                      end
         | 
| 399 | 
            +
                    SESSION.clear_all_breakpoints
         | 
| 400 | 
            +
                    send_response req
         | 
| 384 401 |  | 
| 385 | 
            -
                     | 
| 386 | 
            -
             | 
| 387 | 
            -
             | 
| 388 | 
            -
                       | 
| 389 | 
            -
             | 
| 390 | 
            -
                      begin
         | 
| 391 | 
            -
                        @session.check_postmortem
         | 
| 392 | 
            -
                        @q_msg << 'n'
         | 
| 393 | 
            -
                        send_response req
         | 
| 394 | 
            -
                      rescue PostmortemError
         | 
| 395 | 
            -
                        send_response req,
         | 
| 396 | 
            -
                                      success: false, message: 'postmortem mode',
         | 
| 397 | 
            -
                                      result: "'Next' is not supported while postmortem mode"
         | 
| 398 | 
            -
                      end
         | 
| 399 | 
            -
                    when 'stepIn'
         | 
| 400 | 
            -
                      begin
         | 
| 401 | 
            -
                        @session.check_postmortem
         | 
| 402 | 
            -
                        @q_msg << 's'
         | 
| 403 | 
            -
                        send_response req
         | 
| 404 | 
            -
                      rescue PostmortemError
         | 
| 405 | 
            -
                        send_response req,
         | 
| 406 | 
            -
                                      success: false, message: 'postmortem mode',
         | 
| 407 | 
            -
                                      result: "'stepIn' is not supported while postmortem mode"
         | 
| 402 | 
            +
                    if SESSION.in_subsession?
         | 
| 403 | 
            +
                      if terminate
         | 
| 404 | 
            +
                        @q_msg << 'kill!'
         | 
| 405 | 
            +
                      else
         | 
| 406 | 
            +
                        @q_msg << 'continue'
         | 
| 408 407 | 
             
                      end
         | 
| 409 | 
            -
                     | 
| 410 | 
            -
                       | 
| 411 | 
            -
                        @ | 
| 412 | 
            -
                         | 
| 413 | 
            -
                        send_response req
         | 
| 414 | 
            -
                      rescue PostmortemError
         | 
| 415 | 
            -
                        send_response req,
         | 
| 416 | 
            -
                                      success: false, message: 'postmortem mode',
         | 
| 417 | 
            -
                                      result: "'stepOut' is not supported while postmortem mode"
         | 
| 408 | 
            +
                    else
         | 
| 409 | 
            +
                      if terminate
         | 
| 410 | 
            +
                        @q_msg << 'kill!'
         | 
| 411 | 
            +
                        pause
         | 
| 418 412 | 
             
                      end
         | 
| 419 | 
            -
                     | 
| 413 | 
            +
                    end
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                  ## control
         | 
| 416 | 
            +
                  when 'continue'
         | 
| 417 | 
            +
                    @q_msg << 'c'
         | 
| 418 | 
            +
                    send_response req, allThreadsContinued: true
         | 
| 419 | 
            +
                  when 'next'
         | 
| 420 | 
            +
                    begin
         | 
| 421 | 
            +
                      @session.check_postmortem
         | 
| 422 | 
            +
                      @q_msg << 'n'
         | 
| 420 423 | 
             
                      send_response req
         | 
| 421 | 
            -
             | 
| 422 | 
            -
             | 
| 424 | 
            +
                    rescue PostmortemError
         | 
| 425 | 
            +
                      send_response req,
         | 
| 426 | 
            +
                                    success: false, message: 'postmortem mode',
         | 
| 427 | 
            +
                                    result: "'Next' is not supported while postmortem mode"
         | 
| 428 | 
            +
                    end
         | 
| 429 | 
            +
                  when 'stepIn'
         | 
| 430 | 
            +
                    begin
         | 
| 431 | 
            +
                      @session.check_postmortem
         | 
| 432 | 
            +
                      @q_msg << 's'
         | 
| 423 433 | 
             
                      send_response req
         | 
| 424 | 
            -
             | 
| 425 | 
            -
                    when 'reverseContinue'
         | 
| 434 | 
            +
                    rescue PostmortemError
         | 
| 426 435 | 
             
                      send_response req,
         | 
| 427 | 
            -
                                    success: false, message: ' | 
| 428 | 
            -
                                    result: " | 
| 429 | 
            -
                     | 
| 430 | 
            -
             | 
| 436 | 
            +
                                    success: false, message: 'postmortem mode',
         | 
| 437 | 
            +
                                    result: "'stepIn' is not supported while postmortem mode"
         | 
| 438 | 
            +
                    end
         | 
| 439 | 
            +
                  when 'stepOut'
         | 
| 440 | 
            +
                    begin
         | 
| 441 | 
            +
                      @session.check_postmortem
         | 
| 442 | 
            +
                      @q_msg << 'fin'
         | 
| 443 | 
            +
                      send_response req
         | 
| 444 | 
            +
                    rescue PostmortemError
         | 
| 445 | 
            +
                      send_response req,
         | 
| 446 | 
            +
                                    success: false, message: 'postmortem mode',
         | 
| 447 | 
            +
                                    result: "'stepOut' is not supported while postmortem mode"
         | 
| 448 | 
            +
                    end
         | 
| 449 | 
            +
                  when 'terminate'
         | 
| 450 | 
            +
                    send_response req
         | 
| 451 | 
            +
                    exit
         | 
| 452 | 
            +
                  when 'pause'
         | 
| 453 | 
            +
                    send_response req
         | 
| 454 | 
            +
                    Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
         | 
| 455 | 
            +
                  when 'reverseContinue'
         | 
| 456 | 
            +
                    send_response req,
         | 
| 457 | 
            +
                                  success: false, message: 'cancelled',
         | 
| 458 | 
            +
                                  result: "Reverse Continue is not supported. Only \"Step back\" is supported."
         | 
| 459 | 
            +
                  when 'stepBack'
         | 
| 460 | 
            +
                    @q_msg << req
         | 
| 431 461 |  | 
| 432 | 
            -
             | 
| 433 | 
            -
             | 
| 434 | 
            -
             | 
| 435 | 
            -
             | 
| 436 | 
            -
             | 
| 437 | 
            -
                        }
         | 
| 462 | 
            +
                  ## query
         | 
| 463 | 
            +
                  when 'threads'
         | 
| 464 | 
            +
                    send_response req, threads: SESSION.managed_thread_clients.map{|tc|
         | 
| 465 | 
            +
                      { id: tc.id,
         | 
| 466 | 
            +
                        name: tc.name,
         | 
| 438 467 | 
             
                      }
         | 
| 468 | 
            +
                    }
         | 
| 439 469 |  | 
| 440 | 
            -
             | 
| 441 | 
            -
             | 
| 442 | 
            -
             | 
| 443 | 
            -
             | 
| 444 | 
            -
             | 
| 470 | 
            +
                  when 'evaluate'
         | 
| 471 | 
            +
                    expr = req.dig('arguments', 'expression')
         | 
| 472 | 
            +
                    if /\A\s*,(.+)\z/ =~ expr
         | 
| 473 | 
            +
                      dbg_expr = $1.strip
         | 
| 474 | 
            +
                      dbg_expr.split(';;') { |cmd| @q_msg << cmd }
         | 
| 445 475 |  | 
| 446 | 
            -
             | 
| 447 | 
            -
             | 
| 448 | 
            -
             | 
| 449 | 
            -
             | 
| 450 | 
            -
                        @q_msg << req
         | 
| 451 | 
            -
                      end
         | 
| 452 | 
            -
                    when 'stackTrace',
         | 
| 453 | 
            -
                         'scopes',
         | 
| 454 | 
            -
                         'variables',
         | 
| 455 | 
            -
                         'source',
         | 
| 456 | 
            -
                         'completions'
         | 
| 476 | 
            +
                      send_response req,
         | 
| 477 | 
            +
                                    result: "(rdbg:command) #{dbg_expr}",
         | 
| 478 | 
            +
                                    variablesReference: 0
         | 
| 479 | 
            +
                    else
         | 
| 457 480 | 
             
                      @q_msg << req
         | 
| 481 | 
            +
                    end
         | 
| 482 | 
            +
                  when 'stackTrace',
         | 
| 483 | 
            +
                       'scopes',
         | 
| 484 | 
            +
                       'variables',
         | 
| 485 | 
            +
                       'source',
         | 
| 486 | 
            +
                       'completions'
         | 
| 487 | 
            +
                    @q_msg << req
         | 
| 458 488 |  | 
| 489 | 
            +
                  else
         | 
| 490 | 
            +
                    if respond_to? mid = "custom_dap_request_#{req['command']}"
         | 
| 491 | 
            +
                      __send__ mid, req
         | 
| 459 492 | 
             
                    else
         | 
| 460 | 
            -
                       | 
| 461 | 
            -
                        __send__ mid, req
         | 
| 462 | 
            -
                      else
         | 
| 463 | 
            -
                        raise "Unknown request: #{req.inspect}"
         | 
| 464 | 
            -
                      end
         | 
| 493 | 
            +
                      raise "Unknown request: #{req.inspect}"
         | 
| 465 494 | 
             
                    end
         | 
| 466 495 | 
             
                  end
         | 
| 467 | 
            -
                ensure
         | 
| 468 | 
            -
                  send_event :terminated unless @sock.closed?
         | 
| 469 496 | 
             
                end
         | 
| 470 497 |  | 
| 471 498 | 
             
                ## called by the SESSION thread
         | 
| @@ -625,6 +652,7 @@ module DEBUGGER__ | |
| 625 652 | 
             
                      expr = req.dig('arguments', 'expression')
         | 
| 626 653 |  | 
| 627 654 | 
             
                      if find_waiting_tc(tid)
         | 
| 655 | 
            +
                        restart_all_threads
         | 
| 628 656 | 
             
                        request_tc [:dap, :evaluate, req, fid, expr, context]
         | 
| 629 657 | 
             
                      else
         | 
| 630 658 | 
             
                        fail_response req
         | 
| @@ -701,6 +729,7 @@ module DEBUGGER__ | |
| 701 729 | 
             
                    register_vars result[:variables], tid
         | 
| 702 730 | 
             
                    @ui.respond req, result
         | 
| 703 731 | 
             
                  when :evaluate
         | 
| 732 | 
            +
                    stop_all_threads
         | 
| 704 733 | 
             
                    message = result.delete :message
         | 
| 705 734 | 
             
                    if message
         | 
| 706 735 | 
             
                      @ui.respond req, success: false, message: message
         | 
| @@ -759,7 +788,9 @@ module DEBUGGER__ | |
| 759 788 |  | 
| 760 789 | 
             
                def dap_eval b, expr, _context, prompt: '(repl_eval)'
         | 
| 761 790 | 
             
                  begin
         | 
| 762 | 
            -
                     | 
| 791 | 
            +
                    tp_allow_reentry do
         | 
| 792 | 
            +
                      b.eval(expr.to_s, prompt)
         | 
| 793 | 
            +
                    end
         | 
| 763 794 | 
             
                  rescue Exception => e
         | 
| 764 795 | 
             
                    e
         | 
| 765 796 | 
             
                  end
         | 
| @@ -867,7 +898,7 @@ module DEBUGGER__ | |
| 867 898 | 
             
                          }
         | 
| 868 899 | 
             
                        when String
         | 
| 869 900 | 
             
                          vars = [
         | 
| 870 | 
            -
                            variable('# | 
| 901 | 
            +
                            variable('#length', obj.length),
         | 
| 871 902 | 
             
                            variable('#encoding', obj.encoding),
         | 
| 872 903 | 
             
                          ]
         | 
| 873 904 | 
             
                          printed_str = value_inspect(obj)
         | 
| @@ -1014,7 +1045,7 @@ module DEBUGGER__ | |
| 1014 1045 | 
             
                  klass = M_CLASS.bind_call(obj)
         | 
| 1015 1046 |  | 
| 1016 1047 | 
             
                  begin
         | 
| 1017 | 
            -
                    klass | 
| 1048 | 
            +
                    M_NAME.bind_call(klass) || klass.to_s
         | 
| 1018 1049 | 
             
                  rescue Exception => e
         | 
| 1019 1050 | 
             
                    "<Error: #{e.message} (#{e.backtrace.first}>"
         | 
| 1020 1051 | 
             
                  end
         | 
    
        data/lib/debug/session.rb
    CHANGED
    
    | @@ -82,7 +82,7 @@ class RubyVM::InstructionSequence | |
| 82 82 | 
             
              def first_line
         | 
| 83 83 | 
             
                self.to_a[4][:code_location][0]
         | 
| 84 84 | 
             
              end unless method_defined?(:first_line)
         | 
| 85 | 
            -
            end
         | 
| 85 | 
            +
            end if defined?(RubyVM::InstructionSequence)
         | 
| 86 86 |  | 
| 87 87 | 
             
            module DEBUGGER__
         | 
| 88 88 | 
             
              PresetCommands = Struct.new(:commands, :source, :auto_continue)
         | 
| @@ -133,7 +133,7 @@ module DEBUGGER__ | |
| 133 133 | 
             
                  @commands = {}
         | 
| 134 134 | 
             
                  @unsafe_context = false
         | 
| 135 135 |  | 
| 136 | 
            -
                  @has_keep_script_lines = RubyVM. | 
| 136 | 
            +
                  @has_keep_script_lines = defined?(RubyVM.keep_script_lines)
         | 
| 137 137 |  | 
| 138 138 | 
             
                  @tp_load_script = TracePoint.new(:script_compiled){|tp|
         | 
| 139 139 | 
             
                    eval_script = tp.eval_script unless @has_keep_script_lines
         | 
| @@ -202,6 +202,11 @@ module DEBUGGER__ | |
| 202 202 | 
             
                    end
         | 
| 203 203 | 
             
                    @tp_thread_end.enable
         | 
| 204 204 |  | 
| 205 | 
            +
                    if CONFIG[:irb_console] && !CONFIG[:open]
         | 
| 206 | 
            +
                      require_relative "irb_integration"
         | 
| 207 | 
            +
                      thc.activate_irb_integration
         | 
| 208 | 
            +
                    end
         | 
| 209 | 
            +
             | 
| 205 210 | 
             
                    # session start
         | 
| 206 211 | 
             
                    q << true
         | 
| 207 212 | 
             
                    session_server_main
         | 
| @@ -256,6 +261,15 @@ module DEBUGGER__ | |
| 256 261 | 
             
                  @tc << req
         | 
| 257 262 | 
             
                end
         | 
| 258 263 |  | 
| 264 | 
            +
                def request_tc_with_restarted_threads(req)
         | 
| 265 | 
            +
                  restart_all_threads
         | 
| 266 | 
            +
                  request_tc(req)
         | 
| 267 | 
            +
                end
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                def request_eval type, src
         | 
| 270 | 
            +
                  request_tc_with_restarted_threads [:eval, type, src]
         | 
| 271 | 
            +
                end
         | 
| 272 | 
            +
             | 
| 259 273 | 
             
                def process_event evt
         | 
| 260 274 | 
             
                  # variable `@internal_info` is only used for test
         | 
| 261 275 | 
             
                  tc, output, ev, @internal_info, *ev_args = evt
         | 
| @@ -314,7 +328,7 @@ module DEBUGGER__ | |
| 314 328 | 
             
                    if @displays.empty?
         | 
| 315 329 | 
             
                      wait_command_loop
         | 
| 316 330 | 
             
                    else
         | 
| 317 | 
            -
                       | 
| 331 | 
            +
                      request_eval :display, @displays
         | 
| 318 332 | 
             
                    end
         | 
| 319 333 | 
             
                  when :result
         | 
| 320 334 | 
             
                    raise "[BUG] not in subsession" if @subsession_stack.empty?
         | 
| @@ -329,6 +343,7 @@ module DEBUGGER__ | |
| 329 343 | 
             
                        end
         | 
| 330 344 | 
             
                      end
         | 
| 331 345 |  | 
| 346 | 
            +
                      stop_all_threads
         | 
| 332 347 | 
             
                    when :method_breakpoint, :watch_breakpoint
         | 
| 333 348 | 
             
                      bp = ev_args[1]
         | 
| 334 349 | 
             
                      if bp
         | 
| @@ -342,6 +357,7 @@ module DEBUGGER__ | |
| 342 357 | 
             
                      obj_inspect = ev_args[2]
         | 
| 343 358 | 
             
                      opt = ev_args[3]
         | 
| 344 359 | 
             
                      add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt)
         | 
| 360 | 
            +
                      stop_all_threads
         | 
| 345 361 | 
             
                    else
         | 
| 346 362 | 
             
                      stop_all_threads
         | 
| 347 363 | 
             
                    end
         | 
| @@ -685,15 +701,15 @@ module DEBUGGER__ | |
| 685 701 | 
             
                  register_command 'bt', 'backtrace', unsafe: false do |arg|
         | 
| 686 702 | 
             
                    case arg
         | 
| 687 703 | 
             
                    when /\A(\d+)\z/
         | 
| 688 | 
            -
                       | 
| 704 | 
            +
                      request_tc_with_restarted_threads [:show, :backtrace, arg.to_i, nil]
         | 
| 689 705 | 
             
                    when /\A\/(.*)\/\z/
         | 
| 690 706 | 
             
                      pattern = $1
         | 
| 691 | 
            -
                       | 
| 707 | 
            +
                      request_tc_with_restarted_threads [:show, :backtrace, nil, Regexp.compile(pattern)]
         | 
| 692 708 | 
             
                    when /\A(\d+)\s+\/(.*)\/\z/
         | 
| 693 709 | 
             
                      max, pattern = $1, $2
         | 
| 694 | 
            -
                       | 
| 710 | 
            +
                      request_tc_with_restarted_threads [:show, :backtrace, max.to_i, Regexp.compile(pattern)]
         | 
| 695 711 | 
             
                    else
         | 
| 696 | 
            -
                       | 
| 712 | 
            +
                      request_tc_with_restarted_threads [:show, :backtrace, nil, nil]
         | 
| 697 713 | 
             
                    end
         | 
| 698 714 | 
             
                  end
         | 
| 699 715 |  | 
| @@ -810,15 +826,15 @@ module DEBUGGER__ | |
| 810 826 |  | 
| 811 827 | 
             
                    case sub
         | 
| 812 828 | 
             
                    when nil
         | 
| 813 | 
            -
                       | 
| 829 | 
            +
                      request_tc_with_restarted_threads [:show, :default, pat] # something useful
         | 
| 814 830 | 
             
                    when :locals
         | 
| 815 | 
            -
                       | 
| 831 | 
            +
                      request_tc_with_restarted_threads [:show, :locals, pat]
         | 
| 816 832 | 
             
                    when :ivars
         | 
| 817 | 
            -
                       | 
| 833 | 
            +
                      request_tc_with_restarted_threads [:show, :ivars, pat, opt]
         | 
| 818 834 | 
             
                    when :consts
         | 
| 819 | 
            -
                       | 
| 835 | 
            +
                      request_tc_with_restarted_threads [:show, :consts, pat, opt]
         | 
| 820 836 | 
             
                    when :globals
         | 
| 821 | 
            -
                       | 
| 837 | 
            +
                      request_tc_with_restarted_threads [:show, :globals, pat]
         | 
| 822 838 | 
             
                    when :threads
         | 
| 823 839 | 
             
                      thread_list
         | 
| 824 840 | 
             
                      :retry
         | 
| @@ -838,7 +854,7 @@ module DEBUGGER__ | |
| 838 854 | 
             
                  #   * Show you available methods and instance variables of the given object.
         | 
| 839 855 | 
             
                  #   * If the object is a class/module, it also lists its constants.
         | 
| 840 856 | 
             
                  register_command 'outline', 'o', 'ls', unsafe: false do |arg|
         | 
| 841 | 
            -
                     | 
| 857 | 
            +
                    request_tc_with_restarted_threads [:show, :outline, arg]
         | 
| 842 858 | 
             
                  end
         | 
| 843 859 |  | 
| 844 860 | 
             
                  # * `display`
         | 
| @@ -848,9 +864,9 @@ module DEBUGGER__ | |
| 848 864 | 
             
                  register_command 'display', postmortem: false do |arg|
         | 
| 849 865 | 
             
                    if arg && !arg.empty?
         | 
| 850 866 | 
             
                      @displays << arg
         | 
| 851 | 
            -
                       | 
| 867 | 
            +
                      request_eval :try_display, @displays
         | 
| 852 868 | 
             
                    else
         | 
| 853 | 
            -
                       | 
| 869 | 
            +
                      request_eval :display, @displays
         | 
| 854 870 | 
             
                    end
         | 
| 855 871 | 
             
                  end
         | 
| 856 872 |  | 
| @@ -864,7 +880,7 @@ module DEBUGGER__ | |
| 864 880 | 
             
                      if @displays[n = $1.to_i]
         | 
| 865 881 | 
             
                        @displays.delete_at n
         | 
| 866 882 | 
             
                      end
         | 
| 867 | 
            -
                       | 
| 883 | 
            +
                      request_eval :display, @displays
         | 
| 868 884 | 
             
                    when nil
         | 
| 869 885 | 
             
                      if ask "clear all?", 'N'
         | 
| 870 886 | 
             
                        @displays.clear
         | 
| @@ -925,10 +941,11 @@ module DEBUGGER__ | |
| 925 941 | 
             
                  #   * Invoke `irb` on the current frame.
         | 
| 926 942 | 
             
                  register_command 'irb' do |arg|
         | 
| 927 943 | 
             
                    if @ui.remote?
         | 
| 928 | 
            -
                      @ui.puts "not supported on the remote console."
         | 
| 944 | 
            +
                      @ui.puts "\nIRB is not supported on the remote console."
         | 
| 929 945 | 
             
                      :retry
         | 
| 946 | 
            +
                    else
         | 
| 947 | 
            +
                      request_eval :irb, nil
         | 
| 930 948 | 
             
                    end
         | 
| 931 | 
            -
                    request_eval :irb, nil
         | 
| 932 949 | 
             
                  end
         | 
| 933 950 |  | 
| 934 951 | 
             
                  ### Trace
         | 
| @@ -983,7 +1000,7 @@ module DEBUGGER__ | |
| 983 1000 | 
             
                      :retry
         | 
| 984 1001 |  | 
| 985 1002 | 
             
                    when /\Aobject\s+(.+)/
         | 
| 986 | 
            -
                       | 
| 1003 | 
            +
                      request_tc_with_restarted_threads [:trace, :object, $1.strip, {pattern: pattern, into: into}]
         | 
| 987 1004 |  | 
| 988 1005 | 
             
                    when /\Aoff\s+(\d+)\z/
         | 
| 989 1006 | 
             
                      if t = @tracers.values[$1.to_i]
         | 
| @@ -1164,11 +1181,6 @@ module DEBUGGER__ | |
| 1164 1181 | 
             
                  return :retry
         | 
| 1165 1182 | 
             
                end
         | 
| 1166 1183 |  | 
| 1167 | 
            -
                def request_eval type, src
         | 
| 1168 | 
            -
                  restart_all_threads
         | 
| 1169 | 
            -
                  request_tc [:eval, type, src]
         | 
| 1170 | 
            -
                end
         | 
| 1171 | 
            -
             | 
| 1172 1184 | 
             
                def step_command type, arg
         | 
| 1173 1185 | 
             
                  if type == :until
         | 
| 1174 1186 | 
             
                    leave_subsession [:step, type, arg]
         | 
| @@ -1739,15 +1751,19 @@ module DEBUGGER__ | |
| 1739 1751 | 
             
                  # check breakpoints
         | 
| 1740 1752 | 
             
                  if file_path
         | 
| 1741 1753 | 
             
                    @bps.find_all do |_key, bp|
         | 
| 1742 | 
            -
                      LineBreakpoint === bp && bp.path_is?(file_path)
         | 
| 1754 | 
            +
                      LineBreakpoint === bp && bp.path_is?(file_path) && (iseq.first_lineno..iseq.last_line).cover?(bp.line)
         | 
| 1743 1755 | 
             
                    end.each do |_key, bp|
         | 
| 1744 1756 | 
             
                      if !bp.iseq
         | 
| 1745 1757 | 
             
                        bp.try_activate iseq
         | 
| 1746 1758 | 
             
                      elsif reloaded
         | 
| 1747 1759 | 
             
                        @bps.delete bp.key # to allow duplicate
         | 
| 1748 | 
            -
             | 
| 1749 | 
            -
             | 
| 1750 | 
            -
                         | 
| 1760 | 
            +
             | 
| 1761 | 
            +
                        # When we delete a breakpoint from the @bps hash, we also need to deactivate it or else its tracepoint event
         | 
| 1762 | 
            +
                        # will continue to be enabled and we'll suspend on ghost breakpoints
         | 
| 1763 | 
            +
                        bp.delete
         | 
| 1764 | 
            +
             | 
| 1765 | 
            +
                        nbp = LineBreakpoint.copy(bp, iseq)
         | 
| 1766 | 
            +
                        add_bp nbp
         | 
| 1751 1767 | 
             
                      end
         | 
| 1752 1768 | 
             
                    end
         | 
| 1753 1769 | 
             
                  else # !file_path => file_path is not existing
         | 
| @@ -1993,6 +2009,13 @@ module DEBUGGER__ | |
| 1993 2009 | 
             
                def after_fork_parent
         | 
| 1994 2010 | 
             
                  @ui.after_fork_parent
         | 
| 1995 2011 | 
             
                end
         | 
| 2012 | 
            +
             | 
| 2013 | 
            +
                # experimental API
         | 
| 2014 | 
            +
                def extend_feature session: nil, thread_client: nil, ui: nil
         | 
| 2015 | 
            +
                  Session.include session if session
         | 
| 2016 | 
            +
                  ThreadClient.include thread_client if thread_client
         | 
| 2017 | 
            +
                  @ui.extend ui if ui
         | 
| 2018 | 
            +
                end
         | 
| 1996 2019 | 
             
              end
         | 
| 1997 2020 |  | 
| 1998 2021 | 
             
              class ProcessGroup
         | 
| @@ -2167,6 +2190,7 @@ module DEBUGGER__ | |
| 2167 2190 | 
             
                  case loc.absolute_path
         | 
| 2168 2191 | 
             
                  when dir_prefix
         | 
| 2169 2192 | 
             
                  when %r{rubygems/core_ext/kernel_require\.rb}
         | 
| 2193 | 
            +
                  when %r{bundled_gems\.rb}
         | 
| 2170 2194 | 
             
                  else
         | 
| 2171 2195 | 
             
                    return loc if loc.absolute_path
         | 
| 2172 2196 | 
             
                  end
         | 
| @@ -2517,7 +2541,17 @@ module DEBUGGER__ | |
| 2517 2541 |  | 
| 2518 2542 | 
             
              module TrapInterceptor
         | 
| 2519 2543 | 
             
                def trap sig, *command, &command_proc
         | 
| 2520 | 
            -
                   | 
| 2544 | 
            +
                  sym =
         | 
| 2545 | 
            +
                    case sig
         | 
| 2546 | 
            +
                    when String
         | 
| 2547 | 
            +
                      sig.to_sym
         | 
| 2548 | 
            +
                    when Integer
         | 
| 2549 | 
            +
                      Signal.signame(sig)&.to_sym
         | 
| 2550 | 
            +
                    else
         | 
| 2551 | 
            +
                      sig
         | 
| 2552 | 
            +
                    end
         | 
| 2553 | 
            +
             | 
| 2554 | 
            +
                  case sym
         | 
| 2521 2555 | 
             
                  when :INT, :SIGINT
         | 
| 2522 2556 | 
             
                    if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint?
         | 
| 2523 2557 | 
             
                      return SESSION.save_int_trap(command.empty? ? command_proc : command.first)
         |