|
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32utils\d_exc\minkda.cpp |
|
15 // Example of LDD implementing a minimal kernel-side debug agent. |
|
16 // |
|
17 // |
|
18 |
|
19 #include <kernel/kern_priv.h> |
|
20 #ifdef __MARM__ |
|
21 #include <arm.h> |
|
22 #endif |
|
23 #include "minkda.h" |
|
24 |
|
25 // Uncomment following lines to enable traces in UREL builds |
|
26 //#undef __KTRACE_OPT |
|
27 //#define __KTRACE_OPT(c,b) b |
|
28 |
|
29 #ifdef _DEBUG |
|
30 // Panic category used for internal errors |
|
31 static const char KFault[] = "MINKDA-ERROR, line:"; |
|
32 #endif |
|
33 |
|
34 // Panic category and codes used when detecting programming error in |
|
35 // user-side clients. |
|
36 _LIT(KClientPanic, "MINKDA"); |
|
37 enum TPanic |
|
38 { |
|
39 EPanicTrapWhileRequestPending, |
|
40 EPanicNoCrashedThread, |
|
41 EPanicUnsupportedRequest, |
|
42 }; |
|
43 |
|
44 // As this LDD allows to bypass platform security, we need to restrict |
|
45 // access to a few trusted clients. |
|
46 const TUint32 KDexecSid = 0x101F7770; |
|
47 |
|
48 ////////////////////////////////////////////////////////////////////////////// |
|
49 |
|
50 // |
|
51 // Callback invoked on thread panic/exception and associated state. |
|
52 // |
|
53 |
|
54 class DCrashHandler : public DKernelEventHandler |
|
55 { |
|
56 public: |
|
57 // construction & destruction |
|
58 inline DCrashHandler(); |
|
59 TInt Create(DLogicalDevice* aDevice); |
|
60 ~DCrashHandler(); |
|
61 public: |
|
62 void Trap(TRequestStatus* aRs, TAny* aCrashInfo); |
|
63 void CancelTrap(); |
|
64 void KillCrashedThread(); |
|
65 private: |
|
66 static TUint EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis); |
|
67 void HandleCrash(TAny* aContext); |
|
68 void GetCpuExcInfo(const TAny* aContext, TDbgCpuExcInfo& aInfo); |
|
69 private: |
|
70 DMutex* iHandlerMutex; // serialise access to crash handler |
|
71 NFastSemaphore iSuspendSem; // for suspending crashed thread |
|
72 DMutex* iDataMutex; // serialise access to following members |
|
73 DThread* iClient; // client to signal on crash or NULL |
|
74 TRequestStatus* iTrapRq; // signalled on crash (NULL if none) |
|
75 TAny* iCrashInfo; // user-side buffer filled when crash trapped |
|
76 DThread* iCrashedThread; // thread which took exception (NULL if none) |
|
77 DLogicalDevice* iDevice; // open reference to LDD for avoiding lifetime issues |
|
78 }; |
|
79 |
|
80 inline DCrashHandler::DCrashHandler() |
|
81 : DKernelEventHandler(EventHandler, this) |
|
82 { |
|
83 } |
|
84 |
|
85 // |
|
86 // second-phase c'tor. Called in thread critical section. |
|
87 // |
|
88 |
|
89 TInt DCrashHandler::Create(DLogicalDevice* aDevice) |
|
90 { |
|
91 TInt r; |
|
92 r = aDevice->Open(); |
|
93 if (r != KErrNone) |
|
94 return r; |
|
95 iDevice = aDevice; |
|
96 _LIT(KHandlerMutexName, "CtHandlerMutex"); |
|
97 r = Kern::MutexCreate(iHandlerMutex, KHandlerMutexName, KMutexOrdDebug); |
|
98 if (r != KErrNone) |
|
99 return r; |
|
100 _LIT(KDataMutexName, "CtDataMutex"); |
|
101 r = Kern::MutexCreate(iDataMutex, KDataMutexName, KMutexOrdDebug-1); |
|
102 if (r != KErrNone) |
|
103 return r; |
|
104 return Add(); |
|
105 } |
|
106 |
|
107 |
|
108 // |
|
109 // Called when reference count reaches zero. At that point no threads |
|
110 // are in the handler anymore and the handler has been removed from |
|
111 // the queue. |
|
112 // |
|
113 |
|
114 DCrashHandler::~DCrashHandler() |
|
115 { |
|
116 __KTRACE_OPT(KDEBUGGER, Kern::Printf("DCrashHandler::~DCrashHandler")); |
|
117 if (iDataMutex) |
|
118 iDataMutex->Close(NULL); |
|
119 if (iHandlerMutex) |
|
120 iHandlerMutex->Close(NULL); |
|
121 if (iDevice) |
|
122 iDevice->Close(NULL); |
|
123 } |
|
124 |
|
125 inline TBool TookException(const DThread* aThread) |
|
126 { |
|
127 return aThread->iExitType == EExitPanic && |
|
128 aThread->iExitReason == ECausedException && |
|
129 aThread->iExitCategory == KLitKernExec; |
|
130 } |
|
131 |
|
132 // |
|
133 // Called by kernel when various kinds of events occur. In thread critical |
|
134 // section. |
|
135 // |
|
136 |
|
137 TUint DCrashHandler::EventHandler(TKernelEvent aEvent, TAny* a1, TAny* /*a2*/, TAny* aThis) |
|
138 { |
|
139 DThread* pC = &Kern::CurrentThread(); |
|
140 switch (aEvent) |
|
141 { |
|
142 case EEventHwExc: |
|
143 ((DCrashHandler*)aThis)->HandleCrash(a1); |
|
144 break; |
|
145 case EEventKillThread: |
|
146 if (pC->iExitType == EExitPanic && ! TookException(pC)) |
|
147 ((DCrashHandler*)aThis)->HandleCrash(NULL); |
|
148 break; |
|
149 default: |
|
150 // ignore other events |
|
151 break; |
|
152 } |
|
153 return ERunNext; |
|
154 } |
|
155 |
|
156 // |
|
157 // Called when an exception or panic occurs in context of thread which |
|
158 // took the exception/panicked. In thread critical section. |
|
159 // |
|
160 |
|
161 void DCrashHandler::HandleCrash(TAny* aContext) |
|
162 { |
|
163 DThread* pC = &Kern::CurrentThread(); |
|
164 __KTRACE_OPT(KDEBUGGER, Kern::Printf("HandleCrash context=0x%08X thread=%O", aContext, pC)); |
|
165 |
|
166 // Quick exit if crashed thread is debugger (i.e. client thread |
|
167 // which issued trap request). |
|
168 if (pC == iClient) |
|
169 { |
|
170 __KTRACE_OPT(KDEBUGGER, Kern::Printf("ignoring debugger crash")); |
|
171 return; |
|
172 } |
|
173 |
|
174 // Set realtime state to off to allow us to write to possibly paged debugger thread. This is |
|
175 // reasonable as this thread has already crashed. |
|
176 Kern::SetRealtimeState(ERealtimeStateOff); |
|
177 |
|
178 // Ensure that, at any time, at most one thread executes the following |
|
179 // code. This simplifies user-side API. |
|
180 Kern::MutexWait(*iHandlerMutex); |
|
181 __ASSERT_DEBUG(iCrashedThread == NULL, Kern::Fault(KFault, __LINE__)); |
|
182 |
|
183 // If there is a pending trap request, store basic information |
|
184 // about the panic/exception in user-supplied buffer and |
|
185 // freeze the crashed thread so it can be inspected. |
|
186 |
|
187 Kern::MutexWait(*iDataMutex); |
|
188 if (iTrapRq != NULL) |
|
189 { |
|
190 iCrashedThread = pC; |
|
191 iSuspendSem.iOwningThread = &(iCrashedThread->iNThread); |
|
192 |
|
193 TDbgCrashInfo info; |
|
194 info.iTid = iCrashedThread->iId; |
|
195 if (aContext) |
|
196 { |
|
197 GetCpuExcInfo(aContext, info.iCpu); |
|
198 info.iType = TDbgCrashInfo::EException; |
|
199 } |
|
200 else |
|
201 info.iType = TDbgCrashInfo::EPanic; |
|
202 TInt r = Kern::ThreadRawWrite(iClient, iCrashInfo, &info, sizeof(info)); |
|
203 Kern::RequestComplete(iClient, iTrapRq, r); |
|
204 iClient = NULL; |
|
205 } |
|
206 Kern::MutexSignal(*iDataMutex); |
|
207 |
|
208 if (iCrashedThread) |
|
209 { |
|
210 __KTRACE_OPT(KDEBUGGER, Kern::Printf("freezing crashed thread")); |
|
211 NKern::FSWait(&(iSuspendSem)); |
|
212 __KTRACE_OPT(KDEBUGGER, Kern::Printf("resuming crashed thread")); |
|
213 Kern::MutexWait(*iDataMutex); |
|
214 // Must protect in case a cancel executes concurrently. |
|
215 iCrashedThread = NULL; |
|
216 Kern::MutexSignal(*iDataMutex); |
|
217 } |
|
218 |
|
219 Kern::MutexSignal(*iHandlerMutex); |
|
220 } |
|
221 |
|
222 |
|
223 void DCrashHandler::Trap(TRequestStatus* aRs, TAny* aCrashInfo) |
|
224 { |
|
225 if (iTrapRq != NULL) |
|
226 Kern::PanicCurrentThread(KClientPanic, EPanicTrapWhileRequestPending); |
|
227 NKern::ThreadEnterCS(); |
|
228 Kern::MutexWait(*iDataMutex); |
|
229 iClient = &Kern::CurrentThread(); |
|
230 iCrashInfo = aCrashInfo; |
|
231 iTrapRq = aRs; |
|
232 Kern::MutexSignal(*iDataMutex); |
|
233 NKern::ThreadLeaveCS(); |
|
234 } |
|
235 |
|
236 |
|
237 void DCrashHandler::CancelTrap() |
|
238 { |
|
239 __KTRACE_OPT(KDEBUGGER, Kern::Printf(">DCrashHandler::CancelTrap")); |
|
240 NKern::ThreadEnterCS(); |
|
241 Kern::MutexWait(*iDataMutex); |
|
242 |
|
243 __KTRACE_OPT(KDEBUGGER, Kern::Printf("cancel request (0x%08X)", iTrapRq)); |
|
244 Kern::RequestComplete(iClient, iTrapRq, KErrCancel); |
|
245 iClient = NULL; |
|
246 |
|
247 if (iCrashedThread != NULL) |
|
248 { |
|
249 __KTRACE_OPT(KDEBUGGER, Kern::Printf("resume crashed thread")); |
|
250 NKern::FSSignal(&(iSuspendSem)); |
|
251 } |
|
252 |
|
253 Kern::MutexSignal(*iDataMutex); |
|
254 NKern::ThreadLeaveCS(); |
|
255 __KTRACE_OPT(KDEBUGGER, Kern::Printf("<DCrashHandler::CancelTrap")); |
|
256 } |
|
257 |
|
258 |
|
259 void DCrashHandler::KillCrashedThread() |
|
260 { |
|
261 if (iCrashedThread == NULL) |
|
262 Kern::PanicCurrentThread(KClientPanic, EPanicNoCrashedThread); |
|
263 NKern::FSSignal(&iSuspendSem); |
|
264 } |
|
265 |
|
266 |
|
267 void DCrashHandler::GetCpuExcInfo(const TAny* aContext, TDbgCpuExcInfo& aInfo) |
|
268 { |
|
269 #if defined(__MARM__) |
|
270 const TArmExcInfo* pE = (const TArmExcInfo*)aContext; |
|
271 aInfo.iFaultPc = pE->iR15; |
|
272 aInfo.iFaultAddress = pE->iFaultAddress; |
|
273 aInfo.iFaultStatus = pE->iFaultStatus; |
|
274 aInfo.iExcCode = (TDbgCpuExcInfo::TExcCode)pE->iExcCode; |
|
275 aInfo.iR13Svc = pE->iR13Svc; |
|
276 aInfo.iR14Svc = pE->iR14Svc; |
|
277 aInfo.iSpsrSvc = pE->iSpsrSvc; |
|
278 #else |
|
279 (void) aContext; // silence warnings |
|
280 (void) aInfo; |
|
281 #endif |
|
282 } |
|
283 |
|
284 ////////////////////////////////////////////////////////////////////////////// |
|
285 |
|
286 // |
|
287 // Channel initialisation and cleanup. Dispatcher for user-side |
|
288 // requests. Crash-related requests are forwarded to DCrashHandler, |
|
289 // others are implemented here. |
|
290 // |
|
291 |
|
292 class DKdaChannel : public DLogicalChannelBase |
|
293 { |
|
294 public: |
|
295 ~DKdaChannel(); |
|
296 protected: |
|
297 // from DLogicalChannelBase |
|
298 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer); |
|
299 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
300 private: |
|
301 TInt ReadMem(RMinKda::TReadMemParams* aParams); |
|
302 TInt GetThreadInfo(TUint aTid, TAny* aInfo); |
|
303 void GetThreadCpuInfo(DThread* aThread, TDbgRegSet& aInfo); |
|
304 TInt GetCodeSegs(RMinKda::TCodeSnapshotParams* aParams); |
|
305 TInt GetCodeSegInfo(RMinKda::TCodeInfoParams* aParams); |
|
306 TInt OpenTempObject(TUint aId, TObjectType aType); |
|
307 void CloseTempObject(); |
|
308 private: |
|
309 DCrashHandler* iCrashHandler; |
|
310 DObject* iTempObj; // automagically closed if abnormal termination |
|
311 }; |
|
312 |
|
313 |
|
314 // |
|
315 // Called when user-side thread create new channel with LDD. Called |
|
316 // in context of that thread, in thread critical section. |
|
317 // |
|
318 |
|
319 TInt DKdaChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion &aVer) |
|
320 { |
|
321 if (Kern::CurrentThread().iOwningProcess->iS.iSecureId != KDexecSid) |
|
322 return KErrPermissionDenied; |
|
323 if (! Kern::QueryVersionSupported(KKdaLddVersion(), aVer)) |
|
324 return KErrNotSupported; |
|
325 |
|
326 iCrashHandler = new DCrashHandler; |
|
327 if (iCrashHandler == NULL) |
|
328 return KErrNoMemory; |
|
329 return iCrashHandler->Create(iDevice); |
|
330 } |
|
331 |
|
332 |
|
333 // |
|
334 // Called when last reference to channel is closed, in context of |
|
335 // closing thread, in thread critical section. |
|
336 // |
|
337 |
|
338 DKdaChannel::~DKdaChannel() |
|
339 { |
|
340 __KTRACE_OPT(KDEBUGGER, Kern::Printf("DKdaChannel::~DKdaChannel")); |
|
341 Kern::SafeClose(iTempObj, NULL); |
|
342 if (iCrashHandler) |
|
343 { |
|
344 iCrashHandler->CancelTrap(); |
|
345 iCrashHandler->Close(); |
|
346 } |
|
347 } |
|
348 |
|
349 |
|
350 // |
|
351 // Request dispatcher. Called in context of requesting thread. |
|
352 // |
|
353 |
|
354 TInt DKdaChannel::Request(TInt aFunction, TAny* a1, TAny* a2) |
|
355 { |
|
356 __KTRACE_OPT(KDEBUGGER, Kern::Printf(">DKdaChannel::Request function=%d a1=0x%08X a2=0x%08X", aFunction, a1, a2)); |
|
357 |
|
358 TInt r = KErrNone; |
|
359 switch (aFunction) |
|
360 { |
|
361 case RMinKda::ETrap: |
|
362 iCrashHandler->Trap((TRequestStatus*)a1, a2); |
|
363 break; |
|
364 case RMinKda::ECancelTrap: |
|
365 iCrashHandler->CancelTrap(); |
|
366 break; |
|
367 case RMinKda::EKillCrashedThread: |
|
368 iCrashHandler->KillCrashedThread(); |
|
369 break; |
|
370 case RMinKda::EGetThreadInfo: |
|
371 r = GetThreadInfo((TUint)a1, a2); |
|
372 break; |
|
373 case RMinKda::EReadMem: |
|
374 r = ReadMem((RMinKda::TReadMemParams*)a1); |
|
375 break; |
|
376 case RMinKda::EGetCodeSegs: |
|
377 r = GetCodeSegs((RMinKda::TCodeSnapshotParams*)a1); |
|
378 break; |
|
379 case RMinKda::EGetCodeSegInfo: |
|
380 r = GetCodeSegInfo((RMinKda::TCodeInfoParams*)a1); |
|
381 break; |
|
382 default: |
|
383 Kern::PanicCurrentThread(KClientPanic, EPanicUnsupportedRequest); |
|
384 break; |
|
385 } |
|
386 |
|
387 __KTRACE_OPT(KDEBUGGER, Kern::Printf("<DKdaChannel::Request r=%d", r)); |
|
388 return r; |
|
389 } |
|
390 |
|
391 |
|
392 TInt DKdaChannel::ReadMem(RMinKda::TReadMemParams* aParams) |
|
393 { |
|
394 RMinKda::TReadMemParams params; |
|
395 umemget32(¶ms, aParams, sizeof(params)); |
|
396 |
|
397 TInt destLen; |
|
398 TInt destMax; |
|
399 TUint8* destPtr = (TUint8*)Kern::KUDesInfo(*params.iDes, destLen, destMax); |
|
400 |
|
401 TInt r = OpenTempObject(params.iTid, EThread); |
|
402 if (r == KErrNone) |
|
403 { |
|
404 r = Kern::ThreadRawRead((DThread*)iTempObj, (TAny*)params.iAddr, destPtr, destMax); |
|
405 |
|
406 if (r == KErrNone) |
|
407 Kern::KUDesSetLength(*params.iDes, destMax); |
|
408 |
|
409 CloseTempObject(); |
|
410 } |
|
411 |
|
412 return r; |
|
413 } |
|
414 |
|
415 |
|
416 TInt DKdaChannel::GetThreadInfo(TUint aTid, TAny* aInfo) |
|
417 { |
|
418 TInt r = OpenTempObject(aTid, EThread); |
|
419 if (r == KErrNone) |
|
420 { |
|
421 DThread* pT = (DThread*)iTempObj; |
|
422 TDbgThreadInfo info; |
|
423 pT->FullName(info.iFullName); |
|
424 info.iPid = pT->iOwningProcess->iId; |
|
425 info.iStackBase = pT->iUserStackRunAddress; |
|
426 info.iStackSize = pT->iUserStackSize; |
|
427 info.iExitCategory = pT->iExitCategory; |
|
428 info.iExitReason = pT->iExitReason; |
|
429 GetThreadCpuInfo(pT, info.iCpu); |
|
430 umemput32(aInfo, &info, sizeof(info)); |
|
431 CloseTempObject(); |
|
432 } |
|
433 return r; |
|
434 } |
|
435 |
|
436 // :FIXME: improve API |
|
437 TInt DKdaChannel::GetCodeSegs(RMinKda::TCodeSnapshotParams* aParams) |
|
438 { |
|
439 RMinKda::TCodeSnapshotParams params; |
|
440 umemget32(¶ms, aParams, sizeof(params)); |
|
441 |
|
442 TInt maxcount; |
|
443 umemget32(&maxcount, params.iCountPtr, sizeof(maxcount)); |
|
444 |
|
445 __KTRACE_OPT(KDEBUGGER, Kern::Printf(">DKdaChannel::GetCodeSegs pid=%d maxcount=%d", params.iPid, maxcount)); |
|
446 |
|
447 __ASSERT_DEBUG(! iTempObj, Kern::Fault(KFault, __LINE__)); |
|
448 TInt r = OpenTempObject(params.iPid, EProcess); |
|
449 if (r != KErrNone) |
|
450 { |
|
451 __KTRACE_OPT(KDEBUGGER, Kern::Printf("<DKdaChannel::GetCodeSegs process not found")); |
|
452 return r; |
|
453 } |
|
454 |
|
455 DProcess* pP = (DProcess*)iTempObj; |
|
456 |
|
457 Kern::AccessCode(); |
|
458 |
|
459 SDblQue q; |
|
460 TInt actcount = pP->TraverseCodeSegs(&q, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd); |
|
461 |
|
462 CloseTempObject(); |
|
463 |
|
464 TInt n = Min(actcount, maxcount); |
|
465 SDblQueLink* pL = q.iA.iNext; |
|
466 r = KErrNone; |
|
467 for (TInt i=0; i<n; ++i, pL = pL->iNext) |
|
468 { |
|
469 DCodeSeg* pS = _LOFF(pL, DCodeSeg, iTempLink); |
|
470 XTRAP(r, XT_DEFAULT, umemput32(params.iHandles + i, &pS, sizeof(TAny*))); |
|
471 if (r != KErrNone) |
|
472 break; |
|
473 } |
|
474 |
|
475 DCodeSeg::EmptyQueue(q, DCodeSeg::EMarkDebug); |
|
476 |
|
477 Kern::EndAccessCode(); |
|
478 |
|
479 if (r == KErrBadDescriptor) |
|
480 Kern::PanicCurrentThread(KLitKernExec, ECausedException); |
|
481 umemput32(params.iCountPtr, &actcount, sizeof(actcount)); |
|
482 |
|
483 __KTRACE_OPT(KDEBUGGER, Kern::Printf("<DKdaChannel::GetCodeSegs actcount=%d", actcount)); |
|
484 return r; |
|
485 } |
|
486 |
|
487 |
|
488 // :FIXME: improve API |
|
489 TInt DKdaChannel::GetCodeSegInfo(RMinKda::TCodeInfoParams* aParams) |
|
490 { |
|
491 RMinKda::TCodeInfoParams params; |
|
492 umemget32(¶ms, aParams, sizeof(params)); |
|
493 |
|
494 // :FIXME: Currently code segments are always loaded at the same |
|
495 // location in every address space. Consequently we can ignore |
|
496 // the PID provided by the client. |
|
497 DProcess* pP = NULL; |
|
498 |
|
499 TInt r = KErrNotFound; |
|
500 TFileName nameBuffer; |
|
501 nameBuffer.Zero(); |
|
502 Kern::AccessCode(); |
|
503 DCodeSeg* pS = DCodeSeg::VerifyHandle(params.iHandle); |
|
504 if (pS) |
|
505 { |
|
506 TModuleMemoryInfo mmi; |
|
507 r = pS->GetMemoryInfo(mmi, pP); |
|
508 if (r == KErrNone) |
|
509 { |
|
510 params.iCodeBase = mmi.iCodeBase; |
|
511 params.iCodeSize = mmi.iCodeSize; |
|
512 XTRAP(r, XT_DEFAULT, nameBuffer.Append(*(pS->iFileName))); |
|
513 } |
|
514 } |
|
515 Kern::EndAccessCode(); |
|
516 Kern::KUDesPut(*(params.iPathPtr), nameBuffer); |
|
517 if (r == KErrBadDescriptor) |
|
518 Kern::PanicCurrentThread(KLitKernExec, ECausedException); |
|
519 |
|
520 if (r == KErrNone) |
|
521 umemput32(aParams, ¶ms, sizeof(params)); |
|
522 |
|
523 return r; |
|
524 } |
|
525 |
|
526 // |
|
527 // Lookup a thread or process id and open the corresponding object. |
|
528 // |
|
529 // The object is stored in DKdaChannel::iTempObj to ensure it will be |
|
530 // closed even if the client thread terminates unexpectedly. The |
|
531 // caller must call CloseTempObject() when it is finished with it. |
|
532 // |
|
533 |
|
534 TInt DKdaChannel::OpenTempObject(TUint aId, TObjectType aType) |
|
535 { |
|
536 __ASSERT_DEBUG(aType == EProcess || aType == EThread, Kern::Fault(KFault, __LINE__)); |
|
537 __ASSERT_DEBUG(! iTempObj, Kern::Fault(KFault, __LINE__)); |
|
538 |
|
539 DObjectCon* pC = Kern::Containers()[aType]; |
|
540 NKern::ThreadEnterCS(); |
|
541 pC->Wait(); |
|
542 DObject* tempObj = (aType == EProcess) ? (DObject*)Kern::ProcessFromId(aId) : (DObject*)Kern::ThreadFromId(aId); |
|
543 NKern::LockSystem(); |
|
544 iTempObj = tempObj; |
|
545 TInt r = KErrNotFound; |
|
546 if (iTempObj) |
|
547 r = iTempObj->Open(); |
|
548 |
|
549 NKern::UnlockSystem(); |
|
550 pC->Signal(); |
|
551 NKern::ThreadLeaveCS(); |
|
552 return r; |
|
553 } |
|
554 |
|
555 void DKdaChannel::CloseTempObject() |
|
556 { |
|
557 __ASSERT_DEBUG(iTempObj, Kern::Fault(KFault, __LINE__)); |
|
558 NKern::ThreadEnterCS(); |
|
559 iTempObj->Close(NULL); |
|
560 iTempObj = NULL; |
|
561 NKern::ThreadLeaveCS(); |
|
562 } |
|
563 |
|
564 #ifdef __MARM__ |
|
565 |
|
566 void DKdaChannel::GetThreadCpuInfo(DThread* aThread, TDbgRegSet& aInfo) |
|
567 { |
|
568 __ASSERT_DEBUG(aThread != &Kern::CurrentThread(), Kern::Fault(KFault, __LINE__)); |
|
569 |
|
570 TArmRegSet regSet; |
|
571 TUint32 unused; |
|
572 NKern::ThreadGetUserContext(&(aThread->iNThread), ®Set, unused); |
|
573 aInfo.iRn[0] = regSet.iR0; |
|
574 aInfo.iRn[1] = regSet.iR1; |
|
575 aInfo.iRn[2] = regSet.iR2; |
|
576 aInfo.iRn[3] = regSet.iR3; |
|
577 aInfo.iRn[4] = regSet.iR4; |
|
578 aInfo.iRn[5] = regSet.iR5; |
|
579 aInfo.iRn[6] = regSet.iR6; |
|
580 aInfo.iRn[7] = regSet.iR7; |
|
581 aInfo.iRn[8] = regSet.iR8; |
|
582 aInfo.iRn[9] = regSet.iR9; |
|
583 aInfo.iRn[10] = regSet.iR10; |
|
584 aInfo.iRn[11] = regSet.iR11; |
|
585 aInfo.iRn[12] = regSet.iR12; |
|
586 aInfo.iRn[13] = regSet.iR13; |
|
587 aInfo.iRn[14] = regSet.iR14; |
|
588 aInfo.iRn[15] = regSet.iR15; |
|
589 aInfo.iCpsr = regSet.iFlags; |
|
590 } |
|
591 |
|
592 #else |
|
593 |
|
594 void DKdaChannel::GetThreadCpuInfo(DThread* /*aThread*/, TDbgRegSet& /*aInfo*/) |
|
595 { |
|
596 } |
|
597 |
|
598 #endif |
|
599 |
|
600 |
|
601 ////////////////////////////////////////////////////////////////////////////// |
|
602 |
|
603 class DCtDevice : public DLogicalDevice |
|
604 { |
|
605 public: |
|
606 DCtDevice(); |
|
607 // from DLogicalDevice |
|
608 virtual TInt Install(); |
|
609 virtual void GetCaps(TDes8& aDes) const; |
|
610 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
611 }; |
|
612 |
|
613 DCtDevice::DCtDevice() |
|
614 { |
|
615 // iParseMask = 0; |
|
616 // iUnitsMask = 0; |
|
617 iVersion = KKdaLddVersion(); |
|
618 } |
|
619 |
|
620 TInt DCtDevice::Install() |
|
621 { |
|
622 return SetName(&KKdaLddName); |
|
623 } |
|
624 |
|
625 void DCtDevice::GetCaps(TDes8& /*aDes*/) const |
|
626 { |
|
627 } |
|
628 |
|
629 TInt DCtDevice::Create(DLogicalChannelBase*& aChannel) |
|
630 { |
|
631 aChannel = new DKdaChannel; |
|
632 return (aChannel != NULL) ? KErrNone : KErrNoMemory; |
|
633 } |
|
634 |
|
635 ////////////////////////////////////////////////////////////////////////////// |
|
636 |
|
637 DECLARE_STANDARD_LDD() |
|
638 { |
|
639 return new DCtDevice; |
|
640 } |
|
641 |