1 using System;
  2 using System.Collections;
  3 using System.IO;
  4 using cmsx.machine;
  5 
  6 namespace cmsx.kernel
  7 {
  8     public void ReadExceptionTableFromProcessMemory(Machine& machinecmsx.kernel.Process* processulong exceptionTableAddressuint& frameSizeList<cmsx.object.DispatchTableEntry>& dispatchTable)
  9     {
 10         Memory& mem = machine.GetMemory();
 11         Registers& regs = machine.GetRegisters();
 12         ulong prevRV = regs.GetSpecial(Registers.rV);
 13         MemoryTable& memoryTable = process->memoryTable;
 14         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 15         frameSize = mem.ReadUInt(exceptionTableAddressProtection.read);
 16         uint numDispatchTableEntries = mem.ReadUInt(exceptionTableAddress + 4uProtection.read);
 17         ulong dispatchTableEntryAddress = exceptionTableAddress + 8u;
 18         for (uint i = 0u; i < numDispatchTableEntries; ++i;)
 19         {
 20             cmsx.object.DispatchTableEntry entry;
 21             entry.offset = mem.ReadUInt(dispatchTableEntryAddressProtection.read);
 22             entry.length = mem.ReadUInt(dispatchTableEntryAddress + 4uProtection.read);
 23             entry.exceptionBlockTableAddress = mem.ReadULong(dispatchTableEntryAddress + 8uProtection.read);
 24             dispatchTable.Add(entry);
 25             dispatchTableEntryAddress = dispatchTableEntryAddress + 16u;
 26         }
 27         regs.SetSpecial(Registers.rVprevRV);
 28     }
 29 
 30     public void ReadExceptionBlockTableFromProcessMemory(Machine& machinecmsx.kernel.Process* processulong exceptionBlockTableAddressList<UniquePtr<cmsx.object.ExceptionBlock>>& exceptionBlockTable)
 31     {
 32         Memory& mem = machine.GetMemory();
 33         Registers& regs = machine.GetRegisters();
 34         ulong prevRV = regs.GetSpecial(Registers.rV);
 35         MemoryTable& memoryTable = process->memoryTable;
 36         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 37         ulong discriminator = mem.ReadULong(exceptionBlockTableAddressProtection.read);
 38         ulong exceptionBlockEntryAddress = exceptionBlockTableAddress + 8u;
 39         while (discriminator != cmsx.object.endBlockDiscriminator)
 40         {
 41             if (discriminator == cmsx.object.handlerBlockDiscriminator)
 42             {
 43                 ulong catchedClassId = mem.ReadULong(exceptionBlockEntryAddressProtection.read);
 44                 ulong handlerAddress = mem.ReadULong(exceptionBlockEntryAddress + 8uProtection.read);
 45                 UniquePtr<cmsx.object.ExceptionBlock> handlerBlock(new cmsx.object.HandlerBlock(catchedClassIdhandlerAddress));
 46                 exceptionBlockTable.Add(Rvalue(handlerBlock));
 47                 discriminator = mem.ReadULong(exceptionBlockEntryAddress + 16uProtection.read);
 48                 exceptionBlockEntryAddress = exceptionBlockEntryAddress + 24u;
 49             }
 50             else if (discriminator == cmsx.object.cleanupBlockDiscriminator)
 51             {
 52                 ulong cleanupAddress = mem.ReadULong(exceptionBlockEntryAddressProtection.read);
 53                 ulong parentTableAddress = mem.ReadULong(exceptionBlockEntryAddress + 8uProtection.read);
 54                 UniquePtr<cmsx.object.ExceptionBlock> cleanupBlock(new cmsx.object.CleanupBlock(cleanupAddressparentTableAddress));
 55                 exceptionBlockTable.Add(Rvalue(cleanupBlock));
 56                 discriminator = mem.ReadULong(exceptionBlockEntryAddress + 16uProtection.read);
 57                 exceptionBlockEntryAddress = exceptionBlockEntryAddress + 24u;
 58             }
 59         }
 60         regs.SetSpecial(Registers.rVprevRV);
 61     }
 62 
 63     public ulong GetHandlerAddress(Machine& machinecmsx.kernel.Process* processulong exceptionBlockTableAddressulong exceptionClassId)
 64     {
 65         List<UniquePtr<cmsx.object.ExceptionBlock>> exceptionBlockTable;
 66         ReadExceptionBlockTableFromProcessMemory(machineprocessexceptionBlockTableAddressexceptionBlockTable);
 67         for (const UniquePtr<cmsx.object.ExceptionBlock>& exceptionBlock : exceptionBlockTable)
 68         {
 69             if (exceptionBlock.Get() is cmsx.object.HandlerBlock*)
 70             {
 71                 cmsx.object.HandlerBlock* handlerBlock = cast<cmsx.object.HandlerBlock*>(exceptionBlock.Get());
 72                 ulong catchedClassId = handlerBlock->catchedClassId;
 73                 if (exceptionClassId % catchedClassId == 0u)
 74                 {
 75                     ulong handlerAddress = handlerBlock->handlerAddress;
 76                     return handlerAddress;
 77                 }
 78             }
 79         }
 80         return 0u;
 81     }
 82 
 83     public void DispatchException(Machine& machinecmsx.kernel.Process* processulong fp)
 84     {
 85         process->handlerAddress = 0u;
 86         process->currentExceptionFrameSize = 0u;
 87         ulong exceptionClassId = process->currentExceptionClassId;
 88         List<cmsx.object.FunctionTableEntry> functionTable;
 89         ReadFunctionTableFromProcessMemory(machineprocessprocess->functionTableAddressprocess->functionTableLengthfunctionTable);
 90         ulong pc = 0u;
 91         ulong callPC = 0u;
 92         ulong prevFP = 0u;
 93         ReadProcessMemory(machineprocessfpprevFP8ufalse);
 94         ReadProcessMemory(machineprocessfp - 8upc8ufalse);
 95         while (pc != 0u)
 96         {
 97             callPC = pc - 4u;
 98             fp = prevFP;
 99             List<cmsx.object.FunctionTableEntry>.ConstIterator first = functionTable.CBegin();
100             List<cmsx.object.FunctionTableEntry>.ConstIterator last = functionTable.CEnd();
101             cmsx.object.FunctionTableEntry entry(callPC0u0u0u0u0u0u0u);
102             List<cmsx.object.FunctionTableEntry>.ConstIterator it = LowerBound(firstlastentry);
103             if (it != first && it == last)
104             {
105                 --it;
106             }
107             if (it != first && it != last && entry.start < it->start)
108             {
109                 --it;
110             }
111             if (it != last && entry.start >= it->start && entry.start < it->start + it->length)
112             {
113                 const cmsx.object.FunctionTableEntry& functionTableEntry = *it;
114                 ulong functionStart = functionTableEntry.start;
115                 ulong exceptionTableAddress = functionTableEntry.exceptionTableAddress;
116                 if (exceptionTableAddress != 0u)
117                 {
118                     uint frameSize = 0u;
119                     List<cmsx.object.DispatchTableEntry> dispatchTable;
120                     ReadExceptionTableFromProcessMemory(machineprocesscmsx.machine.dataSegmentBaseAddress + exceptionTableAddressframeSizedispatchTable);
121                     process->currentExceptionFrameSize = frameSize;
122                     List<cmsx.object.DispatchTableEntry>.ConstIterator diFirst = dispatchTable.CBegin();
123                     List<cmsx.object.DispatchTableEntry>.ConstIterator diLast = dispatchTable.CEnd();
124                     cmsx.object.DispatchTableEntry diEntry(cast<uint>(callPC - functionStart)0u0unull);
125                     List<cmsx.object.DispatchTableEntry>.ConstIterator dit = LowerBound(diFirstdiLastdiEntry);
126                     if (dit != diFirst && dit == diLast)
127                     {
128                         --dit;
129                     }
130                     if (dit != diFirst && dit != diLast && diEntry.offset < dit->offset)
131                     {
132                         --dit;
133                     }
134                     if (dit != diLast && diEntry.offset >= dit->offset && diEntry.offset < dit->offset + dit->length)
135                     {
136                         const cmsx.object.DispatchTableEntry& dispatchTableEntry = *dit;
137                         ulong exceptionBlockTableAddress = cmsx.machine.dataSegmentBaseAddress + dispatchTableEntry.exceptionBlockTableAddress;
138                         List<UniquePtr<cmsx.object.ExceptionBlock>> exceptionBlockTable;
139                         ReadExceptionBlockTableFromProcessMemory(machineprocessexceptionBlockTableAddressexceptionBlockTable);
140                         for (const UniquePtr<cmsx.object.ExceptionBlock>& exceptionBlock : exceptionBlockTable)
141                         {
142                             if (exceptionBlock.Get() is cmsx.object.HandlerBlock*)
143                             {
144                                 cmsx.object.HandlerBlock* handlerBlock = cast<cmsx.object.HandlerBlock*>(exceptionBlock.Get());
145                                 ulong catchedClassId = handlerBlock->catchedClassId;
146                                 if (exceptionClassId % catchedClassId == 0u)
147                                 {
148                                     ulong handlerAddress = handlerBlock->handlerAddress;
149                                     machine.GetRegisters().Set(regFPfp);
150                                     machine.GetRegisters().Set(regSPfp + frameSize);
151                                     machine.GetRegisters().SetPC(handlerAddress);
152                                     Kernel& kernel = Kernel.Instance();
153                                     if (kernel.HasUserDebugger())
154                                     {
155                                         Debugger* debugger = kernel.GetDebugger();
156                                         machine.GetRegisters().SetSpecial(cmsx.machine.Registers.rWhandlerAddress);
157                                         debugger->Run(process);
158                                     }
159                                     return;
160                                 }
161                             }
162                             else if (exceptionBlock.Get() is cmsx.object.CleanupBlock*)
163                             {
164                                 cmsx.object.CleanupBlock* cleanupBlock = cast<cmsx.object.CleanupBlock*>(exceptionBlock.Get());
165                                 ulong cleanupAddress = cleanupBlock->cleanupAddress;
166                                 ulong parentTableAddress = cleanupBlock->parentTableAddress;
167                                 if (parentTableAddress != 0u)
168                                 {
169                                     ulong handlerAddress = GetHandlerAddress(machineprocesscmsx.machine.dataSegmentBaseAddress + parentTableAddressexceptionClassId);
170                                     if (handlerAddress != 0u)
171                                     {
172                                         process->handlerAddress = handlerAddress;
173                                     }
174                                 }
175                                 machine.GetRegisters().Set(regFPfp);
176                                 machine.GetRegisters().Set(regSPfp + frameSize);
177                                 machine.GetRegisters().SetPC(cleanupAddress);
178                                 return;
179                             }
180                         }
181                     }
182                 }
183             }
184             ReadProcessMemory(machineprocessfp - 8upc8ufalse);
185             ReadProcessMemory(machineprocessfpprevFP8ufalse);
186         }
187         throw SystemError(EFAIL"dispatch exception failed: exception handler not found");
188     }
189 
190     public void ContinueExceptionDispatch(Machine& machinecmsx.kernel.Process* processulong fp)
191     {
192         ulong prevFP = 0u;
193         ReadProcessMemory(machineprocessfpprevFP8ufalse);
194         fp = prevFP;
195         if (process->handlerAddress != 0u)
196         {
197             ulong handlerAddress = process->handlerAddress;
198             ulong frameSize = process->currentExceptionFrameSize;
199             process->handlerAddress = 0u;
200             process->currentExceptionFrameSize = 0u;
201             machine.GetRegisters().Set(regFPfp);
202             machine.GetRegisters().Set(regSPfp + frameSize);
203             machine.GetRegisters().SetPC(handlerAddress);
204             Kernel& kernel = Kernel.Instance();
205             if (kernel.HasUserDebugger())
206             {
207                 Debugger* debugger = kernel.GetDebugger();
208                 machine.GetRegisters().SetSpecial(cmsx.machine.Registers.rWhandlerAddress);
209                 debugger->Run(process);
210             }
211         }
212         else
213         {
214             DispatchException(machineprocessfp);
215         }
216     }
217 }