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& machine, cmsx.kernel.Process* process, ulong exceptionTableAddress, uint& frameSize, List<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.rV, memoryTable.virtualTranslationRegisterValue);
15 frameSize = mem.ReadUInt(exceptionTableAddress, Protection.read);
16 uint numDispatchTableEntries = mem.ReadUInt(exceptionTableAddress + 4u, Protection.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(dispatchTableEntryAddress, Protection.read);
22 entry.length = mem.ReadUInt(dispatchTableEntryAddress + 4u, Protection.read);
23 entry.exceptionBlockTableAddress = mem.ReadULong(dispatchTableEntryAddress + 8u, Protection.read);
24 dispatchTable.Add(entry);
25 dispatchTableEntryAddress = dispatchTableEntryAddress + 16u;
26 }
27 regs.SetSpecial(Registers.rV, prevRV);
28 }
29
30 public void ReadExceptionBlockTableFromProcessMemory(Machine& machine, cmsx.kernel.Process* process, ulong exceptionBlockTableAddress, List<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.rV, memoryTable.virtualTranslationRegisterValue);
37 ulong discriminator = mem.ReadULong(exceptionBlockTableAddress, Protection.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(exceptionBlockEntryAddress, Protection.read);
44 ulong handlerAddress = mem.ReadULong(exceptionBlockEntryAddress + 8u, Protection.read);
45 UniquePtr<cmsx.object.ExceptionBlock> handlerBlock(new cmsx.object.HandlerBlock(catchedClassId, handlerAddress));
46 exceptionBlockTable.Add(Rvalue(handlerBlock));
47 discriminator = mem.ReadULong(exceptionBlockEntryAddress + 16u, Protection.read);
48 exceptionBlockEntryAddress = exceptionBlockEntryAddress + 24u;
49 }
50 else if (discriminator == cmsx.object.cleanupBlockDiscriminator)
51 {
52 ulong cleanupAddress = mem.ReadULong(exceptionBlockEntryAddress, Protection.read);
53 ulong parentTableAddress = mem.ReadULong(exceptionBlockEntryAddress + 8u, Protection.read);
54 UniquePtr<cmsx.object.ExceptionBlock> cleanupBlock(new cmsx.object.CleanupBlock(cleanupAddress, parentTableAddress));
55 exceptionBlockTable.Add(Rvalue(cleanupBlock));
56 discriminator = mem.ReadULong(exceptionBlockEntryAddress + 16u, Protection.read);
57 exceptionBlockEntryAddress = exceptionBlockEntryAddress + 24u;
58 }
59 }
60 regs.SetSpecial(Registers.rV, prevRV);
61 }
62
63 public ulong GetHandlerAddress(Machine& machine, cmsx.kernel.Process* process, ulong exceptionBlockTableAddress, ulong exceptionClassId)
64 {
65 List<UniquePtr<cmsx.object.ExceptionBlock>> exceptionBlockTable;
66 ReadExceptionBlockTableFromProcessMemory(machine, process, exceptionBlockTableAddress, exceptionBlockTable);
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& machine, cmsx.kernel.Process* process, ulong fp)
84 {
85 process->handlerAddress = 0u;
86 process->currentExceptionFrameSize = 0u;
87 ulong exceptionClassId = process->currentExceptionClassId;
88 List<cmsx.object.FunctionTableEntry> functionTable;
89 ReadFunctionTableFromProcessMemory(machine, process, process->functionTableAddress, process->functionTableLength, functionTable);
90 ulong pc = 0u;
91 ulong callPC = 0u;
92 ulong prevFP = 0u;
93 ReadProcessMemory(machine, process, fp, prevFP, 8u, false);
94 ReadProcessMemory(machine, process, fp - 8u, pc, 8u, false);
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(callPC, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
102 List<cmsx.object.FunctionTableEntry>.ConstIterator it = LowerBound(first, last, entry);
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(machine, process, cmsx.machine.dataSegmentBaseAddress + exceptionTableAddress, frameSize, dispatchTable);
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), 0u, 0u, null);
125 List<cmsx.object.DispatchTableEntry>.ConstIterator dit = LowerBound(diFirst, diLast, diEntry);
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(machine, process, exceptionBlockTableAddress, exceptionBlockTable);
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(regFP, fp);
150 machine.GetRegisters().Set(regSP, fp + 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.rW, handlerAddress);
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(machine, process, cmsx.machine.dataSegmentBaseAddress + parentTableAddress, exceptionClassId);
170 if (handlerAddress != 0u)
171 {
172 process->handlerAddress = handlerAddress;
173 }
174 }
175 machine.GetRegisters().Set(regFP, fp);
176 machine.GetRegisters().Set(regSP, fp + frameSize);
177 machine.GetRegisters().SetPC(cleanupAddress);
178 return;
179 }
180 }
181 }
182 }
183 }
184 ReadProcessMemory(machine, process, fp - 8u, pc, 8u, false);
185 ReadProcessMemory(machine, process, fp, prevFP, 8u, false);
186 }
187 throw SystemError(EFAIL, "dispatch exception failed: exception handler not found");
188 }
189
190 public void ContinueExceptionDispatch(Machine& machine, cmsx.kernel.Process* process, ulong fp)
191 {
192 ulong prevFP = 0u;
193 ReadProcessMemory(machine, process, fp, prevFP, 8u, false);
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(regFP, fp);
202 machine.GetRegisters().Set(regSP, fp + 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.rW, handlerAddress);
209 debugger->Run(process);
210 }
211 }
212 else
213 {
214 DispatchException(machine, process, fp);
215 }
216 }
217 }