Skip to content

Commit ec9e3cb

Browse files
n1lordduckDerelictDrone
authored andcommitted
Fix debugger not detaching when CPU entity is removed (#73)
* feat(cpulib): add DetachDebugger method * fix(cpulib): send InvalidDebugger net to deatach debugger properly * feat(cpulib): add safe debugger detach on entity removal * fix(cpulib): avoid duplicate detach notifications * fix(cpulib): properly cleanup debugger hooks on detach
1 parent 1bb4250 commit ec9e3cb

File tree

1 file changed

+118
-40
lines changed

1 file changed

+118
-40
lines changed

lua/wire/cpulib.lua

Lines changed: 118 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -565,52 +565,129 @@ if SERVER then
565565
-- Players and corresponding entities (for the debugger)
566566
CPULib.DebuggerData = {}
567567

568-
------------------------------------------------------------------------------
569-
-- Attach a debugger
570-
function CPULib.AttachDebugger(entity,player)
571-
if entity then
572-
entity.BreakpointInstructions = {}
573-
entity.OnBreakpointInstruction = function(IP)
574-
CPULib.SendDebugData(entity.VM,CPULib.DebuggerData[player:UserID()].MemPointers,player)
568+
569+
----------------------------------------------------------------------
570+
-- Detach debugger
571+
function CPULib.DetachDebugger(player)
572+
if not IsValid(player) then return end
573+
574+
local data = CPULib.DebuggerData[player:UserID()]
575+
if not data then return end
576+
577+
local ent = data.Entity
578+
if IsValid(ent) and ent.VM then
579+
ent.BreakpointInstructions = nil
580+
ent.OnBreakpointInstruction = nil
581+
ent.OnVMStep = nil
582+
583+
584+
if ent.VM.BaseJump then
585+
ent.VM.Jump = ent.VM.BaseJump
586+
ent.VM.BaseJump = nil
587+
end
588+
589+
if ent.VM.BaseInterrupt then
590+
ent.VM.Interrupt = ent.VM.BaseInterrupt
591+
ent.VM.BaseInterrupt = nil
575592
end
576-
entity.OnVMStep = function()
577-
if CurTime() - CPULib.DebuggerData[player:UserID()].PreviousUpdateTime > 0.2 then
578-
CPULib.DebuggerData[player:UserID()].PreviousUpdateTime = CurTime()
579-
580-
-- Send a fake update that messes up line pointer, updates registers
581-
local tempIP = entity.VM.IP
582-
entity.VM.IP = INVALID_BREAKPOINT_IP
583-
CPULib.SendDebugData(entity.VM,nil,player)
584-
entity.VM.IP = tempIP
593+
594+
if ent._CPULibDebuggerHooked then
595+
ent._CPULibDebuggerHooked = nil
596+
597+
if ent._CPULibOriginalOnRemove then
598+
ent.OnRemove = ent._CPULibOriginalOnRemove
599+
ent._CPULibOriginalOnRemove = nil
600+
else
601+
ent.OnRemove = nil
585602
end
586603
end
587-
if not entity.VM.BaseJump then
588-
entity.VM.BaseJump = entity.VM.Jump
589-
entity.VM.Jump = function(VM,IP,CS)
590-
VM:BaseJump(IP,CS)
591-
entity.ForceLastInstruction = true
604+
end
605+
606+
CPULib.DebuggerData[player:UserID()] = nil
607+
end
608+
609+
610+
----------------------------------------------------------------------
611+
-- Attach a debugger
612+
function CPULib.AttachDebugger(entity, player)
613+
if not IsValid(player) then return end
614+
615+
-- DETACH PATH
616+
if not entity then
617+
CPULib.DetachDebugger(player)
618+
return
619+
end
620+
621+
if not IsValid(entity) or not entity.VM then return end
622+
623+
624+
--// detach any existing debugger first
625+
CPULib.DetachDebugger(player)
626+
627+
628+
if not entity._CPULibDebuggerHooked then
629+
entity._CPULibDebuggerHooked = true
630+
631+
entity._CPULibOriginalOnRemove = entity.OnRemove
632+
633+
entity.OnRemove = function(ent)
634+
if entity._CPULibOriginalOnRemove then
635+
entity._CPULibOriginalOnRemove(ent)
592636
end
593-
entity.VM.BaseInterrupt = entity.VM.Interrupt
594-
entity.VM.Interrupt = function(VM,interruptNo,interruptParameter,isExternal,cascadeInterrupt)
595-
VM:BaseInterrupt(interruptNo,interruptParameter,isExternal,cascadeInterrupt)
596-
if interruptNo < 27 then
597-
CPULib.DebugLogInterrupt(player,interruptNo,interruptParameter,isExternal,cascadeInterrupt)
598-
CPULib.SendDebugData(entity.VM,CPULib.DebuggerData[player:UserID()].MemPointers,player)
599-
end
637+
638+
if IsValid(player) then
639+
if not CPULib.DebuggerData[player:UserID()] then return end
640+
641+
CPULib.DetachDebugger(player)
642+
643+
net.Start("CPULib.InvalidateDebugger")
644+
net.WriteUInt(1, 2) --// 1 = detach
645+
net.Send(player)
600646
end
601647
end
602-
else
603-
if CPULib.DebuggerData[player:UserID()] then
604-
if CPULib.DebuggerData[player:UserID()].Entity and
605-
CPULib.DebuggerData[player:UserID()].Entity.VM and
606-
CPULib.DebuggerData[player:UserID()].Entity.VM.BaseInterrupt then
607-
608-
CPULib.DebuggerData[player:UserID()].Entity.BreakpointInstructions = nil
609-
if CPULib.DebuggerData[player:UserID()].Entity.VM.BaseJump then
610-
CPULib.DebuggerData[player:UserID()].Entity.VM.Jump = CPULib.DebuggerData[player:UserID()].Entity.VM.BaseJump
611-
CPULib.DebuggerData[player:UserID()].Entity.VM.Interrupt = CPULib.DebuggerData[player:UserID()].Entity.VM.BaseInterrupt
612-
CPULib.DebuggerData[player:UserID()].Entity.VM.BaseJump = nil
613-
CPULib.DebuggerData[player:UserID()].Entity.VM.BaseInterrupt = nil
648+
end
649+
650+
entity.BreakpointInstructions = {}
651+
652+
entity.OnBreakpointInstruction = function(IP)
653+
local data = CPULib.DebuggerData[player:UserID()]
654+
if not data then return end
655+
656+
CPULib.SendDebugData(entity.VM, data.MemPointers, player)
657+
end
658+
659+
entity.OnVMStep = function()
660+
local data = CPULib.DebuggerData[player:UserID()]
661+
if not data then return end
662+
663+
if CurTime() - data.PreviousUpdateTime > 0.2 then
664+
data.PreviousUpdateTime = CurTime()
665+
666+
-- Send a fake update that messes up line pointer, updates registers
667+
local tempIP = entity.VM.IP
668+
entity.VM.IP = INVALID_BREAKPOINT_IP
669+
CPULib.SendDebugData(entity.VM, nil, player)
670+
entity.VM.IP = tempIP
671+
end
672+
end
673+
674+
if not entity.VM.BaseJump then
675+
entity.VM.BaseJump = entity.VM.Jump
676+
entity.VM.Jump = function(VM, IP, CS)
677+
VM:BaseJump(IP, CS)
678+
entity.ForceLastInstruction = true
679+
end
680+
681+
entity.VM.BaseInterrupt = entity.VM.Interrupt
682+
entity.VM.Interrupt = function(VM, interruptNo, interruptParameter, isExternal, cascadeInterrupt)
683+
VM:BaseInterrupt(interruptNo, interruptParameter, isExternal, cascadeInterrupt)
684+
685+
if interruptNo < 27 then
686+
CPULib.DebugLogInterrupt(player, interruptNo, interruptParameter, isExternal, cascadeInterrupt)
687+
688+
local data = CPULib.DebuggerData[player:UserID()]
689+
if data then
690+
CPULib.SendDebugData(entity.VM, data.MemPointers, player)
614691
end
615692
end
616693
end
@@ -624,6 +701,7 @@ if SERVER then
624701
}
625702
end
626703

704+
627705
-- Log debug interrupt
628706
function CPULib.DebugLogInterrupt(player,interruptNo,interruptParameter,isExternal,cascadeInterrupt)
629707
local umsgrp = RecipientFilter()

0 commit comments

Comments
 (0)