1 // Copyright (c) 2004-2010 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 // Device driver for kernel side debug assist |
|
15 // |
|
16 |
|
17 #ifdef __WINS__ |
|
18 #error - this driver cannot be built for emulation |
|
19 #endif |
|
20 |
|
21 #include <e32def.h> |
|
22 #include <e32def_private.h> |
|
23 #include <e32cmn.h> |
|
24 #include <e32cmn_private.h> |
|
25 #include <e32ldr.h> |
|
26 #include <u32std.h> |
|
27 #include <kernel/kernel.h> |
|
28 #include <kernel/kern_priv.h> |
|
29 #include <nk_trace.h> |
|
30 #include <arm.h> |
|
31 #include <kernel/cache.h> |
|
32 #include <platform.h> |
|
33 #include <nkern.h> |
|
34 #include <u32hal.h> |
|
35 #include <kernel/kdebug.h> |
|
36 #include <rm_debug_api.h> |
|
37 |
|
38 #include "debug_logging.h" |
|
39 #include "d_rmd_breakpoints.h" // moved breakpoints code lives here |
|
40 #include "d_rmd_stepping.h" // moved stepping code lives here |
|
41 #include "rm_debug_kerneldriver.h" |
|
42 #include "d_list_manager.h" |
|
43 #include "rm_debug_driver.h" |
|
44 #include "rm_debug_eventhandler.h" |
|
45 #include "d_debug_functionality.h" |
|
46 #include "d_process_tracker.h" |
|
47 #include "debug_utils.h" |
|
48 #include "d_buffer_manager.h" |
|
49 |
|
50 using namespace Debug; |
|
51 |
|
52 ///////////////////////////////////////////////////////////////////////// |
|
53 // |
|
54 // DRM_DebugDriverFactory implementation |
|
55 // |
|
56 ///////////////////////////////////////////////////////////////////////// |
|
57 |
|
58 // |
|
59 // DRM_DebugDriverFactory constructor |
|
60 // |
|
61 DRM_DebugDriverFactory::DRM_DebugDriverFactory() |
|
62 { |
|
63 iVersion = TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); |
|
64 } |
|
65 |
|
66 // |
|
67 // DRM_DebugDriverFactory::Create |
|
68 // |
|
69 TInt DRM_DebugDriverFactory::Create(DLogicalChannelBase*& aChannel) |
|
70 { |
|
71 if (iOpenChannels != 0) |
|
72 return KErrInUse; // a channel is already open |
|
73 |
|
74 aChannel = new DRM_DebugChannel(this); |
|
75 |
|
76 return aChannel ? KErrNone : KErrNoMemory; |
|
77 } |
|
78 |
|
79 // |
|
80 // DRM_DebugDriverFactory::Install |
|
81 // |
|
82 TInt DRM_DebugDriverFactory::Install() |
|
83 { |
|
84 return(SetName(&KRM_DebugDriverName)); |
|
85 } |
|
86 |
|
87 // |
|
88 // DRM_DebugDriverFactory::Install |
|
89 // |
|
90 void DRM_DebugDriverFactory::GetCaps(TDes8& aDes) const |
|
91 { |
|
92 TCapsRM_DebugDriver b; |
|
93 b.iVersion = TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber); |
|
94 |
|
95 Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b)); |
|
96 } |
|
97 |
|
98 ///////////////////////////////////////////////////////////////////////// |
|
99 // |
|
100 // DRM_DebugChannel implementation |
|
101 // |
|
102 ///////////////////////////////////////////////////////////////////////// |
|
103 |
|
104 // |
|
105 // DRM_DebugChannel constructor |
|
106 // |
|
107 DRM_DebugChannel::DRM_DebugChannel(DLogicalDevice* aLogicalDevice) |
|
108 : iExcludedROMAddressStart(ROM_LINEAR_BASE), |
|
109 iExcludedROMAddressEnd(0), |
|
110 iPageSize(0x1000), |
|
111 iBreakManager(0), |
|
112 iStepper(0), |
|
113 iStepLock(0), |
|
114 iDfcQ(NULL), |
|
115 iInitialisedCodeModifier(0), |
|
116 iAsyncGetValueRequest(NULL) |
|
117 { |
|
118 LOG_MSG("DRM_DebugChannel::DRM_DebugChannel()"); |
|
119 |
|
120 iDevice = aLogicalDevice; |
|
121 |
|
122 iClientThread = &Kern::CurrentThread(); |
|
123 iClientThread->Open(); |
|
124 |
|
125 LOG_MSG3("DRM_DebugChannel::DRM_DebugChannel() clientThread = 0x%08x, id=%d", |
|
126 iClientThread, iClientThread->iId ); |
|
127 |
|
128 |
|
129 iPageSize = Kern::RoundToPageSize(1); |
|
130 } |
|
131 |
|
132 // |
|
133 // DRM_DebugChannel destructor |
|
134 // |
|
135 DRM_DebugChannel::~DRM_DebugChannel() |
|
136 { |
|
137 LOG_MSG("DRM_DebugChannel::~DRM_DebugChannel()"); |
|
138 |
|
139 if (iAsyncGetValueRequest) |
|
140 { |
|
141 Kern::QueueRequestComplete(iClientThread, iAsyncGetValueRequest, KErrCancel); // does nothing if request not pending |
|
142 Kern::DestroyClientRequest(iAsyncGetValueRequest); |
|
143 } |
|
144 |
|
145 NKern::ThreadEnterCS(); |
|
146 Kern::SafeClose((DObject*&)iClientThread, NULL); |
|
147 NKern::ThreadLeaveCS(); |
|
148 |
|
149 // Close breakpoint manager |
|
150 if (iBreakManager) |
|
151 { |
|
152 NKern::ThreadEnterCS(); |
|
153 delete iBreakManager; |
|
154 NKern::ThreadLeaveCS(); |
|
155 } |
|
156 |
|
157 // Close stepping manager |
|
158 if (iStepper) |
|
159 { |
|
160 NKern::ThreadEnterCS(); |
|
161 delete iStepper; |
|
162 NKern::ThreadLeaveCS(); |
|
163 } |
|
164 |
|
165 //close the debug process list |
|
166 iDebugProcessList.Close(); |
|
167 |
|
168 DestroyDfcQ(); |
|
169 |
|
170 //close the code modifier |
|
171 if (iInitialisedCodeModifier) |
|
172 { |
|
173 DebugSupport::CloseCodeModifier(); |
|
174 } |
|
175 } |
|
176 |
|
177 void DRM_DebugChannel::DestroyDfcQ() |
|
178 { |
|
179 LOG_MSG("DRM_DebugChannel::DestroyDfcQ()"); |
|
180 if (iDfcQ) |
|
181 { |
|
182 NKern::ThreadEnterCS(); |
|
183 iDfcQ->Destroy(); |
|
184 NKern::ThreadLeaveCS(); |
|
185 } |
|
186 } |
|
187 |
|
188 // |
|
189 // DRM_DebugChannel::DoCreate |
|
190 // |
|
191 TInt DRM_DebugChannel::DoCreate(TInt /*aUnit*/, const TDesC* anInfo, const TVersion& aVer) |
|
192 { |
|
193 LOG_MSG("DRM_DebugChannel::DoCreate()"); |
|
194 TInt err = Kern::CreateClientDataRequest(iAsyncGetValueRequest); |
|
195 if(err != KErrNone) |
|
196 return err; |
|
197 |
|
198 if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber), aVer)) |
|
199 return KErrNotSupported; |
|
200 |
|
201 // Do the security check here so that any arbitrary application doesn't make |
|
202 // use of Trk kernel driver. |
|
203 if (!DoSecurityCheck()) |
|
204 { |
|
205 LOG_MSG("DRM_DebugChannel::DoCreate() - permission denied!"); |
|
206 return KErrPermissionDenied; |
|
207 } |
|
208 |
|
209 if (anInfo) |
|
210 { |
|
211 // this is the end address of the user library. |
|
212 // this doesn't seem to be valid for EKA2. |
|
213 // right now we dont need this for EKA2 since we are not worried |
|
214 // about kernel being stopped as kernel is multithreaded. |
|
215 // just retaining this for future use. |
|
216 TBuf8<32> buf; |
|
217 TInt err = Kern::ThreadRawRead(iClientThread, anInfo, &buf, 32); |
|
218 if(err != KErrNone) |
|
219 return err; |
|
220 } |
|
221 |
|
222 // Allocate a D_RMD_Breakpoints class as a breakpoint manager |
|
223 NKern::ThreadEnterCS(); |
|
224 iBreakManager = new D_RMD_Breakpoints(this); |
|
225 NKern::ThreadLeaveCS(); |
|
226 if (iBreakManager == NULL) |
|
227 { |
|
228 LOG_MSG("DRM_DebugChannel::DRM_DebugChannel - could not construct breakpoint manager"); |
|
229 return KErrNoMemory; |
|
230 } |
|
231 |
|
232 // Initialise the new breakpoint manager object |
|
233 iBreakManager->Init(); |
|
234 |
|
235 // Allocate a DRMDStepping class as the stepping manager |
|
236 NKern::ThreadEnterCS(); |
|
237 iStepper = new DRMDStepping(this); |
|
238 NKern::ThreadLeaveCS(); |
|
239 if (iStepper == NULL) |
|
240 { |
|
241 LOG_MSG("DRM_DebugChannel::DRM_DebugChannel - could not construct stepper manager"); |
|
242 return KErrNoMemory; |
|
243 } |
|
244 |
|
245 // Initialize the code modifier for managing breakpoints. |
|
246 TUint caps; //ignored for now |
|
247 err = DebugSupport::InitialiseCodeModifier(caps, NUMBER_OF_MAX_BREAKPOINTS); |
|
248 //if code modifier initializer failed, |
|
249 //return here, since we can't set an breakpoints |
|
250 if(err != KErrNone) |
|
251 { |
|
252 return err; |
|
253 } |
|
254 else |
|
255 { |
|
256 iInitialisedCodeModifier = ETrue; |
|
257 } |
|
258 |
|
259 //create and set the driver's Dfc queue |
|
260 err = CreateDfcQ(); |
|
261 if(err != KErrNone) |
|
262 { |
|
263 LOG_MSG("DRM_DebugChannel::DoCreate() Creating Dfc queue failed."); |
|
264 } |
|
265 SetDfcQ(iDfcQ); |
|
266 |
|
267 iMsgQ.Receive(); |
|
268 |
|
269 iEventHandler = new DRM_DebugEventHandler; |
|
270 if (!iEventHandler) |
|
271 return KErrNoMemory; |
|
272 err = iEventHandler->Create(iDevice, this, iClientThread); |
|
273 if (err != KErrNone) |
|
274 return err; |
|
275 |
|
276 //return KErrNone; |
|
277 return iEventHandler->Start(); |
|
278 } |
|
279 |
|
280 /** |
|
281 Forward call to either synch or asynch methods while serialising all calls via lock. |
|
282 |
|
283 Protect access via a the event handler lock to |
|
284 serialise all calls and protect concurrent access to data structures |
|
285 |
|
286 @param aMsg pointer to a TMessageBase object |
|
287 |
|
288 @return error returned by called methods |
|
289 |
|
290 @see DRM_DebugEventHandler::HandleSpecificEvent where lock is also used |
|
291 @see DRM_DebugEventHandler::iProtectionLock |
|
292 |
|
293 */ |
|
294 TInt DRM_DebugChannel::SendMsg(TMessageBase* aMsg) |
|
295 { |
|
296 DThread * currThread = &Kern::CurrentThread(); |
|
297 LOG_MSG3("DRM_DebugChannel::SendMsg() currThread = 0x%08x, iClientThread=0x%08x", currThread, iClientThread ); |
|
298 |
|
299 iEventHandler->LockDataAccess(); |
|
300 |
|
301 TThreadMessage& m = *(TThreadMessage*)aMsg; |
|
302 TInt id = m.iValue; |
|
303 TInt err = KErrNone; |
|
304 |
|
305 if (id != (TInt)ECloseMsg && id != KMaxTInt && id < 0) |
|
306 { |
|
307 // DoRequest |
|
308 TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); |
|
309 err = SendRequest(aMsg); |
|
310 if (err != KErrNone) |
|
311 Kern::RequestComplete(pStatus,err); |
|
312 } |
|
313 else |
|
314 { |
|
315 err = DLogicalChannel::SendMsg(aMsg); |
|
316 } |
|
317 |
|
318 iEventHandler->ReleaseDataAccess(); |
|
319 return err; |
|
320 } |
|
321 |
|
322 // |
|
323 // DRM_DebugChannel::SendRequest |
|
324 // |
|
325 TInt DRM_DebugChannel::SendRequest(TMessageBase* aMsg) |
|
326 { |
|
327 LOG_MSG("DRM_DebugChannel::SendRequest()"); |
|
328 |
|
329 TThreadMessage& m = *(TThreadMessage*)aMsg; |
|
330 TInt function = ~m.iValue; |
|
331 TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); |
|
332 TAny* a1 = m.Ptr1(); |
|
333 |
|
334 TInt err = KErrNotSupported; |
|
335 switch(function) |
|
336 { |
|
337 case RRM_DebugDriver::ERequestGetEvent: |
|
338 err = PreAsyncGetValue((TEventInfo*)a1,pStatus); |
|
339 break; |
|
340 } |
|
341 if (err == KErrNone) |
|
342 err = DLogicalChannel::SendMsg(aMsg); |
|
343 return err; |
|
344 } |
|
345 |
|
346 // |
|
347 // DRM_DebugChannel::PreAsyncGetValue |
|
348 // |
|
349 TInt DRM_DebugChannel::PreAsyncGetValue(TEventInfo* aValue, TRequestStatus* aStatus) |
|
350 { |
|
351 LOG_MSG3("DRM_DebugChannel::PreAsyncGetValue() TEventInfo=0x%08x, TRequestStatus=0x%08x", |
|
352 aValue, aStatus ); |
|
353 |
|
354 iAsyncGetValueRequest->Reset(); |
|
355 |
|
356 TInt err = iAsyncGetValueRequest->SetStatus(aStatus); |
|
357 if (err != KErrNone) |
|
358 return err; |
|
359 |
|
360 iAsyncGetValueRequest->SetDestPtr(aValue); |
|
361 return KErrNone; |
|
362 } |
|
363 |
|
364 /** |
|
365 Create the Dfc queue for receiving messages |
|
366 */ |
|
367 TInt DRM_DebugChannel::CreateDfcQ() |
|
368 { |
|
369 LOG_MSG("DRM_DebugChannel::CreateDfcQ()"); |
|
370 TInt r = Kern::DynamicDfcQCreate(iDfcQ, KRmDebugDriverThreadPriority, KRM_DebugDriverName); |
|
371 // Fix to stop t_rmdebug2 etc crashing the device. |
|
372 // This should be removed once the rm debug driver has been updated for WDP. |
|
373 if (r == KErrNone) |
|
374 iDfcQ->SetRealtimeState(ERealtimeStateOff); |
|
375 return r; |
|
376 } |
|
377 |
|
378 // |
|
379 // DRM_DebugChannel::DoCancel |
|
380 // |
|
381 // New: The cancel call does not take an enum parameter describing |
|
382 // the request to be cancelled. Rather it supplies a pointer |
|
383 // to a user-side struct defining the cancellation |
|
384 // |
|
385 void DRM_DebugChannel::DoCancel(TInt aReqNo) |
|
386 { |
|
387 LOG_MSG("DRM_DebugChannel::DoCancel()"); |
|
388 |
|
389 TRMD_DebugCancelInfo info; |
|
390 |
|
391 TInt err = Kern::ThreadRawRead(iClientThread,(TAny*)aReqNo,(TAny*)&info,sizeof(info)); |
|
392 if (err != KErrNone) |
|
393 { |
|
394 // How do we cancel something we know nothing about??? |
|
395 LOG_MSG("DRM_DebugChannel::DoCancel - bad arguments"); |
|
396 return; |
|
397 } |
|
398 |
|
399 // Find the process |
|
400 DTargetProcess* pProcess = TheDProcessTracker.FindProcess(info.iProcessName); |
|
401 if (pProcess == NULL) |
|
402 { |
|
403 // We are doomed. We don't know which event to cancel.. |
|
404 LOG_MSG2("Cannot determine which process is being debugged: %S", &(info.iProcessName)); |
|
405 |
|
406 return; |
|
407 } |
|
408 |
|
409 // Find the agent |
|
410 DDebugAgent* debugAgent = pProcess->Agent(info.iAgentId); |
|
411 if (debugAgent == NULL) |
|
412 { |
|
413 // Bad agent means there is no tracking agent |
|
414 LOG_MSG2("Cannot locate debug agent with pid 0x%0x16lx",info.iAgentId); |
|
415 return; |
|
416 } |
|
417 |
|
418 // Agent completes/pends the request as appropriate. |
|
419 debugAgent->CancelGetEvent(); |
|
420 |
|
421 } |
|
422 |
|
423 // |
|
424 // DRM_DebugChannel::DoRequest |
|
425 // |
|
426 void DRM_DebugChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
427 { |
|
428 LOG_MSG4("DRM_DebugChannel::DoRequest(), iClientThread=0x%08x, tid=0x%08x, TRequestStatus=0x%08x", |
|
429 iClientThread, I64LOW(iClientThread->iId), aStatus); |
|
430 |
|
431 switch(aReqNo) |
|
432 { |
|
433 case RRM_DebugDriver::ERequestGetEvent: |
|
434 { |
|
435 TEventMetaData eventMetaData; |
|
436 TInt err = Kern::ThreadRawRead(iClientThread, a2, (TUint8 *)&eventMetaData, sizeof(TEventMetaData) ); |
|
437 if (err != KErrNone) |
|
438 { |
|
439 LOG_MSG("Error: could not read argument data from the DSS (TEventMetaData)"); |
|
440 |
|
441 // We could not read information from the user, so the a2 argument is probably wrong |
|
442 Kern::RequestComplete(iClientThread, aStatus, KErrArgument); |
|
443 return; |
|
444 } |
|
445 |
|
446 // Find the process |
|
447 DTargetProcess* pProcess = TheDProcessTracker.FindProcess(eventMetaData.iTargetProcessName); |
|
448 if (pProcess == NULL) |
|
449 { |
|
450 LOG_MSG("Cannot identify process being debugged"); |
|
451 |
|
452 // We could not locate the process, so the user asked for the wrong one. |
|
453 Kern::RequestComplete(iClientThread, aStatus, KErrArgument); |
|
454 return; |
|
455 } |
|
456 |
|
457 // Find the agent |
|
458 DDebugAgent* debugAgent = pProcess->Agent(eventMetaData.iDebugAgentProcessId); |
|
459 LOG_MSG5(" For agent pid=%d, DTargetProcess=0x%08x, Agent=0x%08x, iAsyncGetValueRequest0x%08x", |
|
460 I64LOW(eventMetaData.iDebugAgentProcessId), pProcess, debugAgent, iAsyncGetValueRequest ); |
|
461 |
|
462 if (debugAgent == NULL) |
|
463 { |
|
464 // Bad agent means there is no tracking agent |
|
465 LOG_MSG2("Cannot locate debug agent with pid 0x%0x16lx",eventMetaData.iDebugAgentProcessId); |
|
466 return; |
|
467 } |
|
468 // Agent completes/pends the request as appropriate. |
|
469 debugAgent->GetEvent(iAsyncGetValueRequest, iClientThread); |
|
470 |
|
471 break; |
|
472 } |
|
473 default: |
|
474 { |
|
475 // Don't know what to do, should not get here! |
|
476 LOG_MSG("DRM_DebugChannel::DoRequest was passed an unsupported request aReqNo"); |
|
477 |
|
478 Kern::RequestComplete(iClientThread, aStatus, KErrNotSupported); |
|
479 } |
|
480 } |
|
481 } |
|
482 |
|
483 // |
|
484 // DRM_DebugChannel::DoControl |
|
485 // |
|
486 TInt DRM_DebugChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
487 { |
|
488 LOG_MSG("DRM_DebugChannel::DoControl()"); |
|
489 |
|
490 LOG_MSG2("DoControl Function %d", aFunction); |
|
491 |
|
492 TInt err = KErrBadHandle; |
|
493 DThread* threadObj = NULL; |
|
494 |
|
495 switch(aFunction) |
|
496 { |
|
497 /* Security first */ |
|
498 case RRM_DebugDriver::EControlIsDebuggable: |
|
499 { |
|
500 err = IsDebuggable((TUint32)a1); |
|
501 break; |
|
502 } |
|
503 case RRM_DebugDriver::EControlSetBreak: |
|
504 { |
|
505 err = SetBreak((TSetBreakInfo*)a1); |
|
506 break; |
|
507 } |
|
508 case RRM_DebugDriver::EControlClearBreak: |
|
509 { |
|
510 err = iBreakManager->DoClearBreak((TInt32)a1); |
|
511 break; |
|
512 } |
|
513 case RRM_DebugDriver::EControlModifyBreak: |
|
514 { |
|
515 err = iBreakManager->DoModifyBreak((TModifyBreakInfo*)a1); |
|
516 break; |
|
517 } |
|
518 case RRM_DebugDriver::EControlModifyProcessBreak: |
|
519 { |
|
520 err = iBreakManager->DoModifyProcessBreak((TModifyProcessBreakInfo*)a1); |
|
521 break; |
|
522 } |
|
523 case RRM_DebugDriver::EControlBreakInfo: |
|
524 { |
|
525 err = iBreakManager->DoBreakInfo((TGetBreakInfo*)a1); |
|
526 break; |
|
527 } |
|
528 case RRM_DebugDriver::EControlSuspendThread: |
|
529 { |
|
530 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
531 if (threadObj) |
|
532 { |
|
533 err = DoSuspendThread(threadObj); |
|
534 } |
|
535 break; |
|
536 } |
|
537 case RRM_DebugDriver::EControlResumeThread: |
|
538 { |
|
539 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
540 if (threadObj) |
|
541 { |
|
542 err = DoResumeThread(threadObj); |
|
543 } |
|
544 break; |
|
545 } |
|
546 case RRM_DebugDriver::EControlStepRange: |
|
547 { |
|
548 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
549 if (threadObj) |
|
550 { |
|
551 err = StepRange(threadObj, (TRM_DebugStepInfo*)a2); |
|
552 } |
|
553 break; |
|
554 } |
|
555 case RRM_DebugDriver::EControlReadMemory: |
|
556 { |
|
557 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
558 if (threadObj) |
|
559 { |
|
560 err = ReadMemory(threadObj, (TRM_DebugMemoryInfo*)a2); |
|
561 } |
|
562 break; |
|
563 } |
|
564 case RRM_DebugDriver::EControlWriteMemory: |
|
565 { |
|
566 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
567 if (threadObj) |
|
568 { |
|
569 err = WriteMemory(threadObj, (TRM_DebugMemoryInfo*)a2); |
|
570 } |
|
571 break; |
|
572 } |
|
573 case RRM_DebugDriver::EControlReadRegistersLegacy: |
|
574 { |
|
575 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
576 if (threadObj) |
|
577 { |
|
578 err = ReadRegistersLegacy(threadObj, (TRM_DebugRegisterInfo*)a2); |
|
579 } |
|
580 break; |
|
581 } |
|
582 case RRM_DebugDriver::EControlWriteRegistersLegacy: |
|
583 { |
|
584 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
585 if (threadObj) |
|
586 { |
|
587 err = WriteRegistersLegacy(threadObj, (TRM_DebugRegisterInfo*)a2); |
|
588 } |
|
589 break; |
|
590 } |
|
591 case RRM_DebugDriver::EControlReadRegisters: |
|
592 { |
|
593 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
594 if (threadObj) |
|
595 { |
|
596 err = ReadRegisters(threadObj, (TRM_DebugRegisterInformation*)a2); |
|
597 } |
|
598 break; |
|
599 } |
|
600 case RRM_DebugDriver::EControlWriteRegisters: |
|
601 { |
|
602 threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); |
|
603 if (threadObj) |
|
604 { |
|
605 err = WriteRegisters(threadObj, (TRM_DebugRegisterInformation*)a2); |
|
606 } |
|
607 break; |
|
608 } |
|
609 case RRM_DebugDriver::EControlGetDebugFunctionalityBufSize: |
|
610 { |
|
611 LOG_MSG("RRM_DebugDriver::EControlGetDebugFunctionalityBufSize\n"); |
|
612 |
|
613 TDebugFunctionality df; |
|
614 |
|
615 TUint size = df.GetDebugFunctionalityBufSize(); |
|
616 |
|
617 // Return size to user-side in a safe manner |
|
618 err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8*)&size, sizeof(TUint), iClientThread); |
|
619 break; |
|
620 } |
|
621 case RRM_DebugDriver::EControlGetDebugFunctionality: |
|
622 { |
|
623 LOG_MSG("RRM_DebugDriver::EControlGetDebugFunctionality\n"); |
|
624 |
|
625 TDebugFunctionality df; |
|
626 |
|
627 TUint32 dfsize = df.GetDebugFunctionalityBufSize(); |
|
628 |
|
629 // Alloc tmp buffer for Debug Functionality data |
|
630 NKern::ThreadEnterCS(); |
|
631 TUint8* dfbuffer = (TUint8*)Kern::AllocZ(dfsize); |
|
632 NKern::ThreadLeaveCS(); |
|
633 if (dfbuffer==NULL) |
|
634 { |
|
635 LOG_MSG2("Could not allocate memory for %d bytes\n",dfsize); |
|
636 |
|
637 // could not allocate memory |
|
638 return KErrNoMemory; |
|
639 } |
|
640 |
|
641 // Temporary descriptor to hold DF data |
|
642 TPtr8 tmpPtr(dfbuffer,0,dfsize); |
|
643 |
|
644 // Obtain the DF data |
|
645 if (df.GetDebugFunctionality(tmpPtr) ) |
|
646 { |
|
647 // Return the DF data to the user-side |
|
648 err = Kern::ThreadDesWrite(iClientThread, a1, tmpPtr, 0, KChunkShiftBy0, iClientThread); |
|
649 } |
|
650 else |
|
651 { |
|
652 // Failed. |
|
653 err = KErrGeneral; |
|
654 } |
|
655 |
|
656 // Free tmp buffer |
|
657 NKern::ThreadEnterCS(); |
|
658 Kern::Free(dfbuffer); |
|
659 NKern::ThreadLeaveCS(); |
|
660 break; |
|
661 } |
|
662 case RRM_DebugDriver::EControlAttachProcess: |
|
663 { |
|
664 LOG_MSG("RRM_DebugDriver::EControlAttachProcess"); |
|
665 |
|
666 err = AttachProcess(a1,a2); |
|
667 break; |
|
668 } |
|
669 case RRM_DebugDriver::EControlDetachProcess: |
|
670 { |
|
671 LOG_MSG("RRM_DebugDriver::EControlDetachProcess"); |
|
672 |
|
673 err = DetachProcess(a1,a2); |
|
674 break; |
|
675 } |
|
676 case RRM_DebugDriver::EControlDetachAgent: |
|
677 { |
|
678 LOG_MSG("RRM_DebugDriver::EControlDetachAgent"); |
|
679 |
|
680 err = DetachAgent(a1,a2); |
|
681 break; |
|
682 } |
|
683 case RRM_DebugDriver::EControlSetEventAction: |
|
684 { |
|
685 LOG_MSG("RRM_DebugDriver::EControlSetEventAction"); |
|
686 |
|
687 err = SetEventAction(a1,a2); |
|
688 break; |
|
689 } |
|
690 case RRM_DebugDriver::EControlGetMemoryOperationMaxBlockSize: |
|
691 { |
|
692 LOG_MSG("RRM_DebugDriver::EControlGetMemoryOperationMaxBlockSize\n"); |
|
693 |
|
694 TUint32 maxSize = TDebugFunctionality::GetMemoryOperationMaxBlockSize(); |
|
695 |
|
696 // Return size to user-side in a safe manner |
|
697 err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8*)&maxSize, sizeof(TUint32), iClientThread); |
|
698 break; |
|
699 } |
|
700 case RRM_DebugDriver::EControlGetList: |
|
701 { |
|
702 LOG_MSG("RRM_DebugDriver::EControlGetList\n"); |
|
703 err = GetList((TListInformation*)a1); |
|
704 break; |
|
705 } |
|
706 case RRM_DebugDriver::EControlStep: |
|
707 { |
|
708 LOG_MSG("RRM_DebugDriver::EControlStep\n"); |
|
709 |
|
710 err = Step((TUint32)a1,(TUint32)a2); |
|
711 break; |
|
712 } |
|
713 case RRM_DebugDriver::EControlKillProcess: |
|
714 { |
|
715 LOG_MSG("RRM_DebugDriver::EControlKillProcess\n"); |
|
716 |
|
717 err = KillProcess((TUint32)a1,(TUint32)a2); |
|
718 break; |
|
719 } |
|
720 default: |
|
721 { |
|
722 err = KErrGeneral; |
|
723 } |
|
724 } |
|
725 |
|
726 if (KErrNone != err) |
|
727 { |
|
728 LOG_MSG2("Error %d from control function", err); |
|
729 } |
|
730 |
|
731 if (threadObj) |
|
732 { |
|
733 // Close the thread handle which has been opened by DebugUtils::OpenThreadHandle |
|
734 threadObj->Close(NULL); |
|
735 } |
|
736 |
|
737 return err; |
|
738 } |
|
739 |
|
740 void DRM_DebugChannel::HandleMsg(TMessageBase* aMsg) |
|
741 { |
|
742 LOG_MSG("DRM_DebugChannel::HandleMsg()"); |
|
743 |
|
744 TThreadMessage& m = *(TThreadMessage*)aMsg; |
|
745 TInt id = m.iValue; |
|
746 |
|
747 if (id == (TInt)ECloseMsg) |
|
748 { |
|
749 if (iEventHandler) |
|
750 { |
|
751 iEventHandler->Stop(); |
|
752 iEventHandler->Close(); |
|
753 iEventHandler = NULL; |
|
754 } |
|
755 m.Complete(KErrNone, EFalse); |
|
756 return; |
|
757 } |
|
758 |
|
759 if (id == KMaxTInt) |
|
760 { |
|
761 // DoCancel |
|
762 DoCancel(m.Int0()); |
|
763 m.Complete(KErrNone, ETrue); |
|
764 return; |
|
765 } |
|
766 |
|
767 if (id < 0) |
|
768 { |
|
769 // DoRequest |
|
770 TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); |
|
771 DoRequest(~id, pStatus, m.Ptr1(), m.Ptr2()); |
|
772 m.Complete(KErrNone, ETrue); |
|
773 } |
|
774 else |
|
775 { |
|
776 // DoControl |
|
777 TInt err = DoControl(id, m.Ptr0(), m.Ptr1()); |
|
778 m.Complete(err, ETrue); |
|
779 } |
|
780 } |
|
781 |
|
782 // |
|
783 // DRM_DebugChannel::RemoveProcess |
|
784 // |
|
785 TBool DRM_DebugChannel::RemoveProcess(TAny* a1, TAny* a2) |
|
786 { |
|
787 LOG_MSG("DRM_DebugChannel::RemoveProcess()"); |
|
788 |
|
789 DProcess *aProcess = (DProcess*)a1; |
|
790 |
|
791 // Sanity check |
|
792 if (!aProcess) |
|
793 { |
|
794 // No process was specified! |
|
795 LOG_MSG("DRM_DebugChannel::RemoveProcess was called with an invalid process ID"); |
|
796 return EFalse; |
|
797 } |
|
798 |
|
799 // this is called when a process dies. we want to mark any breakpoints in this |
|
800 // process space as obsolete. the main reason for this is so we don't return |
|
801 // an error when the host debugger tries to clear breakpoints for the process |
|
802 |
|
803 TUint32 codeAddress = 0; |
|
804 TUint32 codeSize = 0; |
|
805 |
|
806 LOG_EVENT_MSG2("Process being removed, Name %S", aProcess->iName); |
|
807 |
|
808 DCodeSeg* codeSeg = aProcess->iCodeSeg; |
|
809 |
|
810 if (codeSeg) |
|
811 { |
|
812 TModuleMemoryInfo processMemoryInfo; |
|
813 TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, aProcess); |
|
814 if (err != KErrNone) |
|
815 { |
|
816 codeAddress = processMemoryInfo.iCodeBase; |
|
817 codeSize = processMemoryInfo.iCodeSize; |
|
818 } |
|
819 else |
|
820 { |
|
821 LOG_MSG2("Error in getting memory info: %d", err); |
|
822 } |
|
823 } |
|
824 |
|
825 if (!codeAddress || !codeSize) |
|
826 { |
|
827 LOG_EVENT_MSG2("Code segment not available for process %d", aProcess->iId); |
|
828 // make sure there is not already a breakpoint at this address |
|
829 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
830 { |
|
831 if (iDebugProcessList[i].iId == aProcess->iId) |
|
832 { |
|
833 codeAddress = iDebugProcessList[i].iCodeAddress; |
|
834 codeSize = iDebugProcessList[i].iCodeSize; |
|
835 |
|
836 //now remove from the list |
|
837 iDebugProcessList.Remove(i); |
|
838 break; |
|
839 } |
|
840 } |
|
841 } |
|
842 |
|
843 if (!codeAddress || !codeSize) |
|
844 { |
|
845 return EFalse; |
|
846 } |
|
847 |
|
848 iBreakManager->RemoveBreaksForProcess(aProcess->iId, codeAddress, codeSize); |
|
849 return EFalse; |
|
850 } |
|
851 |
|
852 // |
|
853 // DRM_DebugChannel::StartThread |
|
854 // |
|
855 TBool DRM_DebugChannel::StartThread(TAny* a1, TAny* a2) |
|
856 { |
|
857 LOG_EVENT_MSG("DRM_DebugChannel::StartThread()"); |
|
858 |
|
859 DThread *aThread = (DThread*)a1; |
|
860 if(!aThread) |
|
861 { |
|
862 LOG_MSG("Error getting DThread object"); |
|
863 __NK_ASSERT_DEBUG(aThread); |
|
864 return EFalse; |
|
865 } |
|
866 |
|
867 //a2 points to the thread creating the new thread. |
|
868 //We have no use for it at the moment so just ignore it for now |
|
869 |
|
870 TDriverEventInfo info; |
|
871 info.iEventType = EEventsStartThread; |
|
872 info.iThreadId = aThread->iId; |
|
873 info.iThreadIdValid = ETrue; |
|
874 DProcess* owningProcess = aThread->iOwningProcess; |
|
875 if(owningProcess) |
|
876 { |
|
877 info.iProcessId = owningProcess->iId; |
|
878 info.iProcessIdValid = ETrue; |
|
879 DCodeSeg* p = owningProcess->iCodeSeg; |
|
880 if(p && p->iFileName) |
|
881 { |
|
882 info.iFileName.Copy(*(p->iFileName)); |
|
883 DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(p->iFileName)); |
|
884 if(foundProcess) |
|
885 { |
|
886 foundProcess->NotifyEvent(info); |
|
887 } |
|
888 else |
|
889 { |
|
890 LOG_EVENT_MSG2("Couldn't find process with name [%S]", p->iFileName); |
|
891 } |
|
892 } |
|
893 else |
|
894 { |
|
895 if(p) |
|
896 { |
|
897 LOG_EVENT_MSG("\tCode segment name missing"); |
|
898 } |
|
899 else |
|
900 { |
|
901 LOG_EVENT_MSG("\tCode segment is NULL"); |
|
902 } |
|
903 } |
|
904 } |
|
905 return EFalse; |
|
906 } |
|
907 |
|
908 // |
|
909 // DRM_DebugChannel::HandleAddProcessEvent |
|
910 // |
|
911 TBool DRM_DebugChannel::HandleAddProcessEvent(TAny* a1, TAny* a2) |
|
912 { |
|
913 LOG_EVENT_MSG("DRM_DebugChannel::AddProcess()"); |
|
914 |
|
915 DProcess *aProcess = (DProcess*)a1; |
|
916 // a2 points to the thread creating the new process. |
|
917 DThread *aThread = (DThread*)a2; |
|
918 |
|
919 if(!aProcess) |
|
920 { |
|
921 LOG_MSG("Error getting DProcess object"); |
|
922 __NK_ASSERT_DEBUG(aProcess); |
|
923 return EFalse; |
|
924 } |
|
925 |
|
926 TDriverEventInfo info; |
|
927 info.iEventType = EEventsAddProcess; |
|
928 info.iProcessId = aProcess->iId; |
|
929 |
|
930 info.iCreatorThreadId = aThread ? aThread->iId : 0; |
|
931 info.iProcessIdValid = ETrue; |
|
932 |
|
933 // Copy TUids |
|
934 info.iUids = aProcess->iUids; |
|
935 |
|
936 info.iUidsValid = ETrue; |
|
937 |
|
938 // copy name of the process |
|
939 if (aProcess->iName) |
|
940 { |
|
941 // copy the name of the process |
|
942 info.iFileName.Copy(*aProcess->iName); |
|
943 |
|
944 DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(aProcess->iName)); |
|
945 if(foundProcess) |
|
946 { |
|
947 foundProcess->NotifyEvent(info); |
|
948 } |
|
949 else |
|
950 { |
|
951 // AddProcess event does not have fully-qualified path, it has "filename.exe" |
|
952 // So we try a less-precise match |
|
953 DTargetProcess* foundProcess = TheDProcessTracker.FuzzyFindProcess(*(aProcess->iName)); |
|
954 if(foundProcess) |
|
955 { |
|
956 foundProcess->NotifyEvent(info); |
|
957 } |
|
958 else |
|
959 { |
|
960 LOG_EVENT_MSG2("Couldn't find process with name [%S]", aProcess->iName); |
|
961 } |
|
962 } |
|
963 } |
|
964 else |
|
965 { |
|
966 LOG_EVENT_MSG("DRM_DebugChannel::AddProcess - No iName for this process"); |
|
967 } |
|
968 |
|
969 return EFalse; |
|
970 } |
|
971 |
|
972 // |
|
973 // DRM_DebugChannel::HandleRemoveProcessEvent |
|
974 // |
|
975 TBool DRM_DebugChannel::HandleRemoveProcessEvent(TAny* a1, TAny* a2) |
|
976 { |
|
977 LOG_EVENT_MSG("DRM_DebugChannel::RemoveProcess()"); |
|
978 |
|
979 DProcess *aProcess = (DProcess*)a1; |
|
980 if(!aProcess) |
|
981 { |
|
982 LOG_MSG("Error getting DProcess object"); |
|
983 __NK_ASSERT_DEBUG(aProcess); |
|
984 return EFalse; |
|
985 } |
|
986 |
|
987 // a2 points to the thread creating the new process. |
|
988 // We have no use for it at the moment so just ignore it for now |
|
989 // Also, it may not be known and therefore NULL |
|
990 |
|
991 TDriverEventInfo info; |
|
992 info.iEventType = EEventsRemoveProcess; |
|
993 info.iProcessId = aProcess->iId; |
|
994 info.iProcessIdValid = ETrue; |
|
995 |
|
996 // copy name of the process |
|
997 if (aProcess->iName) |
|
998 { |
|
999 // copy the name of the process |
|
1000 info.iFileName.Copy(*aProcess->iName); |
|
1001 |
|
1002 DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(aProcess->iName)); |
|
1003 if(foundProcess) |
|
1004 { |
|
1005 foundProcess->NotifyEvent(info); |
|
1006 } |
|
1007 else |
|
1008 { |
|
1009 // RemoveProcess event does not have fully-qualified path, it has "filename.exe" |
|
1010 // So we try a less-precise match |
|
1011 DTargetProcess* foundProcess = TheDProcessTracker.FuzzyFindProcess(*(aProcess->iName)); |
|
1012 if(foundProcess) |
|
1013 { |
|
1014 foundProcess->NotifyEvent(info); |
|
1015 } |
|
1016 else |
|
1017 { |
|
1018 LOG_EVENT_MSG2("Couldn't find process with name [%S]", aProcess->iName); |
|
1019 } |
|
1020 } |
|
1021 |
|
1022 } |
|
1023 else |
|
1024 { |
|
1025 LOG_EVENT_MSG("DRM_DebugChannel::AddProcess - No iName for this process"); |
|
1026 } |
|
1027 |
|
1028 return EFalse; |
|
1029 } |
|
1030 |
|
1031 // |
|
1032 // DRM_DebugChannel::AddLibrary |
|
1033 // |
|
1034 TBool DRM_DebugChannel::AddLibrary(TAny* a1, TAny* a2) |
|
1035 { |
|
1036 LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary()"); |
|
1037 |
|
1038 DLibrary *aLibrary = (DLibrary*)a1; |
|
1039 DThread *aThread = (DThread*)a2; |
|
1040 |
|
1041 // sanity check |
|
1042 if (!aLibrary) |
|
1043 { |
|
1044 LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary called with no library specified"); |
|
1045 return EFalse; |
|
1046 } |
|
1047 |
|
1048 if (!aThread) |
|
1049 { |
|
1050 LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary called with no thread specified"); |
|
1051 return EFalse; |
|
1052 } |
|
1053 |
|
1054 LOG_EVENT_MSG2(("Lib loaded: %S"), aLibrary->iName); |
|
1055 |
|
1056 if (aThread) |
|
1057 { |
|
1058 // make sure this is not the debugger thread |
|
1059 if ((aThread != iClientThread) && (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) |
|
1060 { |
|
1061 TDriverEventInfo info; |
|
1062 |
|
1063 info.iEventType = EEventsAddLibrary; |
|
1064 info.iProcessId = aThread->iOwningProcess->iId; |
|
1065 info.iProcessIdValid = ETrue; |
|
1066 info.iThreadId = aThread->iId; |
|
1067 info.iThreadIdValid = ETrue; |
|
1068 |
|
1069 //get the code address |
|
1070 DCodeSeg* codeSeg = aLibrary->iCodeSeg; |
|
1071 if (!codeSeg) |
|
1072 { |
|
1073 LOG_EVENT_MSG2("Code segment not available for library %S", aLibrary->iName); |
|
1074 return EFalse; |
|
1075 } |
|
1076 |
|
1077 // Uid3 |
|
1078 info.iUids = codeSeg->iUids; |
|
1079 info.iUidsValid = ETrue; |
|
1080 |
|
1081 TModuleMemoryInfo memoryInfo; |
|
1082 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); //NULL for DProcess should be ok; |
|
1083 if (err != KErrNone) |
|
1084 { |
|
1085 LOG_EVENT_MSG2("Error in getting memory info: %d", err); |
|
1086 return EFalse; |
|
1087 } |
|
1088 |
|
1089 info.iCodeAddress = memoryInfo.iCodeBase; |
|
1090 info.iDataAddress = memoryInfo.iInitialisedDataBase; |
|
1091 |
|
1092 info.iFileName.Copy(*(aLibrary->iName)); //just the name, without uid info. |
|
1093 |
|
1094 //queue up or complete the event |
|
1095 info.iArg1 = a1; |
|
1096 info.iArg2 = a2; |
|
1097 NotifyEvent(info); |
|
1098 } |
|
1099 |
|
1100 } |
|
1101 return EFalse; |
|
1102 } |
|
1103 |
|
1104 // |
|
1105 // DRM_DebugChannel::RemoveLibrary |
|
1106 // |
|
1107 TBool DRM_DebugChannel::RemoveLibrary(TAny* a1, TAny* a2) |
|
1108 { |
|
1109 LOG_EVENT_MSG("DRM_DebugChannel::RemoveLibrary()"); |
|
1110 DLibrary *aLibrary = (DLibrary*)a1; |
|
1111 |
|
1112 // sanity check |
|
1113 if (!aLibrary) |
|
1114 { |
|
1115 LOG_EVENT_MSG("DRM_DebugChannel::RemoveLibrary called with no library specified"); |
|
1116 return EFalse; |
|
1117 } |
|
1118 |
|
1119 LOG_EVENT_MSG2(("Lib unloaded: %S"), aLibrary->iName); |
|
1120 |
|
1121 // this is called when all handles to this library have been closed. this can happen when a process dies, or when a dll is |
|
1122 // unloaded while the process lives on. in former case, we don't need to notify the host debugger because that process is |
|
1123 // dying anyway. for the latter case, we do need to notify the host so it can unload the symbolics, etc. |
|
1124 |
|
1125 DThread* aThread = &Kern::CurrentThread(); |
|
1126 |
|
1127 if ((aThread) && |
|
1128 (aThread != iClientThread) && |
|
1129 (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) |
|
1130 { |
|
1131 //the library gets unloaded only when the mapcount is 0. |
|
1132 if (aLibrary->iMapCount != 0) |
|
1133 return EFalse; |
|
1134 |
|
1135 DCodeSeg* codeSeg = aLibrary->iCodeSeg; |
|
1136 if (!codeSeg) |
|
1137 { |
|
1138 LOG_EVENT_MSG2("Code segment not available for library %S", aLibrary->iName); |
|
1139 return EFalse; |
|
1140 } |
|
1141 |
|
1142 TModuleMemoryInfo processMemoryInfo; |
|
1143 TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, NULL); //passing NULL for the DProcess argument should be ok; |
|
1144 if (err != KErrNone) |
|
1145 { |
|
1146 LOG_EVENT_MSG2("Error in getting memory info: %d", err); |
|
1147 return EFalse; |
|
1148 } |
|
1149 |
|
1150 TUint32 codeAddress = processMemoryInfo.iCodeBase; |
|
1151 TUint32 codeSize = processMemoryInfo.iCodeSize; |
|
1152 |
|
1153 // first invalidate all breakpoints that were set in the library code |
|
1154 iBreakManager->InvalidateLibraryBreakPoints(codeAddress, codeSize); |
|
1155 DProcess *process = &Kern::CurrentProcess(); |
|
1156 RArray<SCodeSegEntry>* dynamicCode = &(process->iDynamicCode); |
|
1157 |
|
1158 for (TInt j=0; j<dynamicCode->Count(); j++) |
|
1159 { |
|
1160 if ((*dynamicCode)[j].iLib == aLibrary) |
|
1161 { |
|
1162 TDriverEventInfo info; |
|
1163 |
|
1164 info.iEventType = EEventsRemoveLibrary; |
|
1165 info.iFileName.Copy(*(aLibrary->iName)); //lib name without uid info |
|
1166 //info.iFileName.ZeroTerminate(); |
|
1167 info.iProcessId = process->iId; |
|
1168 info.iProcessIdValid = ETrue; |
|
1169 info.iThreadId = 0xFFFFFFFF; // don't care! |
|
1170 info.iThreadIdValid = EFalse; |
|
1171 // Uid3 |
|
1172 info.iUids = codeSeg->iUids; |
|
1173 info.iUidsValid = ETrue; |
|
1174 |
|
1175 //queue up or complete the event |
|
1176 info.iArg1 = a1; |
|
1177 info.iArg2 = a2; |
|
1178 NotifyEvent(info); |
|
1179 } |
|
1180 } |
|
1181 } |
|
1182 return EFalse; |
|
1183 } |
|
1184 |
|
1185 // |
|
1186 // DRM_DebugChannel::HandleEventKillThread |
|
1187 // |
|
1188 TBool DRM_DebugChannel::HandleEventKillThread(TAny* a1, TAny* a2) |
|
1189 { |
|
1190 |
|
1191 LOG_MSG2("DRM_DebugChannel::HandleEventKillThread(Thread a1=0x%08x)", a1 ); |
|
1192 |
|
1193 DThread* currentThread = &Kern::CurrentThread(); |
|
1194 if (!currentThread) |
|
1195 { |
|
1196 LOG_MSG("Error getting current thread"); |
|
1197 __NK_ASSERT_DEBUG(currentThread); |
|
1198 return EFalse; |
|
1199 } |
|
1200 |
|
1201 // a1 should point to the current thread, check this to make sure it does |
|
1202 __NK_ASSERT_DEBUG((DThread*)a1 == currentThread); |
|
1203 |
|
1204 TDriverEventInfo info; |
|
1205 |
|
1206 info.iProcessId = currentThread->iOwningProcess->iId; |
|
1207 info.iProcessIdValid = ETrue; |
|
1208 info.iThreadId = currentThread->iId; |
|
1209 info.iThreadIdValid = ETrue; |
|
1210 // 14 should probably be replaced by PC_REGISTER, for some reason PC_REGISTER had been replaced with 14 in the code |
|
1211 TInt err = ReadKernelRegisterValue(currentThread, 14, info.iCurrentPC); |
|
1212 if(err != KErrNone) |
|
1213 { |
|
1214 LOG_EVENT_MSG2("DRM_DebugChannel::HandleEventKillThread - Non-zero error code discarded: %d", err); |
|
1215 } |
|
1216 |
|
1217 if (currentThread->iExitType == EExitPanic) |
|
1218 { |
|
1219 info.iPanicCategory.Copy(currentThread->iExitCategory); |
|
1220 } |
|
1221 info.iExceptionNumber = currentThread->iExitReason; |
|
1222 info.iExitType = currentThread->iExitType; |
|
1223 info.iEventType = EEventsKillThread; |
|
1224 |
|
1225 // Are we debugging this process - decide based on iFileName |
|
1226 DCodeSeg* codeSeg = currentThread->iOwningProcess->iCodeSeg; |
|
1227 |
|
1228 // remove all the breakpoints in this thread, whether we are debugging it or not. |
|
1229 iBreakManager->DoRemoveThreadBreaks(info.iThreadId); |
|
1230 |
|
1231 // if the code seg exists then get the file name from it and check we're debugging it |
|
1232 if(codeSeg) |
|
1233 { |
|
1234 DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(codeSeg->iFileName)); |
|
1235 if(!foundProcess) |
|
1236 { |
|
1237 // not debugging this process so return false |
|
1238 return EFalse; |
|
1239 } |
|
1240 } |
|
1241 else |
|
1242 { |
|
1243 // can't validate that we are debugging the thread |
|
1244 return EFalse; |
|
1245 } |
|
1246 |
|
1247 info.iArg1 = a1; |
|
1248 info.iArg2 = a2; |
|
1249 NotifyEvent(info); |
|
1250 |
|
1251 return ETrue; |
|
1252 } |
|
1253 |
|
1254 // |
|
1255 // DRM_DebugChannel::HandleSwException |
|
1256 // |
|
1257 TBool DRM_DebugChannel::HandleSwException(TAny* a1, TAny* a2) |
|
1258 { |
|
1259 LOG_EVENT_MSG("DRM_DebugChannel::HandleSwException"); |
|
1260 TExcType aExcType = (TExcType)(TInt)a1; |
|
1261 |
|
1262 TDriverEventInfo info; |
|
1263 |
|
1264 DThread* currentThread = &Kern::CurrentThread(); |
|
1265 if (!currentThread) |
|
1266 { |
|
1267 LOG_MSG("Error getting current thread"); |
|
1268 __NK_ASSERT_DEBUG(currentThread); |
|
1269 return EFalse; |
|
1270 } |
|
1271 |
|
1272 info.iProcessId = currentThread->iOwningProcess->iId; |
|
1273 info.iProcessIdValid = ETrue; |
|
1274 info.iThreadId = currentThread->iId; |
|
1275 info.iThreadIdValid = ETrue; |
|
1276 TInt err = ReadKernelRegisterValue(currentThread, PC_REGISTER, info.iCurrentPC); |
|
1277 if(err != KErrNone) |
|
1278 { |
|
1279 LOG_EVENT_MSG2("DRM_DebugChannel::HandleSwException - Non-zero error code discarded: %d", err); |
|
1280 } |
|
1281 info.iExceptionNumber = aExcType; |
|
1282 info.iEventType = EEventsSwExc; |
|
1283 info.iArg1 = a1; |
|
1284 info.iArg2 = a2; |
|
1285 |
|
1286 NotifyEvent(info); |
|
1287 |
|
1288 return EFalse; |
|
1289 } |
|
1290 |
|
1291 // |
|
1292 // DRM_DebugChannel::HandleHwException |
|
1293 // |
|
1294 TBool DRM_DebugChannel::HandleHwException(TAny* a1, TAny* a2) |
|
1295 { |
|
1296 TArmExcInfo* aExcInfo = (TArmExcInfo*)a1; |
|
1297 |
|
1298 // sanity check |
|
1299 if (!aExcInfo) |
|
1300 { |
|
1301 LOG_MSG("DRM_DebugChannel::HandleHwException called with no aExcInfo"); |
|
1302 __NK_ASSERT_DEBUG(aExcInfo); |
|
1303 return EFalse; |
|
1304 } |
|
1305 |
|
1306 TDriverEventInfo info; |
|
1307 |
|
1308 DThread* currentThread = &Kern::CurrentThread(); |
|
1309 |
|
1310 if (!currentThread) |
|
1311 { |
|
1312 LOG_MSG("Error getting current thread"); |
|
1313 __NK_ASSERT_DEBUG(currentThread); |
|
1314 return EFalse; |
|
1315 } |
|
1316 |
|
1317 info.iProcessId = currentThread->iOwningProcess->iId; |
|
1318 info.iProcessIdValid = ETrue; |
|
1319 info.iThreadId = currentThread->iId; |
|
1320 info.iThreadIdValid = ETrue; |
|
1321 info.iRmdArmExcInfo.iFaultAddress= aExcInfo->iFaultAddress; |
|
1322 info.iRmdArmExcInfo.iFaultStatus= aExcInfo->iFaultStatus; |
|
1323 |
|
1324 LOG_MSG5("DRM_DebugChannel::HandleHwException current thread = 0x%08x, CritSect count=%d,\n" |
|
1325 " iFaultAddress=0x%08x, iFaultStatus=0x%08x", |
|
1326 currentThread, currentThread->iNThread.iCsCount, aExcInfo->iFaultAddress, aExcInfo->iFaultStatus); |
|
1327 |
|
1328 info.iRmdArmExcInfo.iR0= aExcInfo->iR0; |
|
1329 info.iRmdArmExcInfo.iR1= aExcInfo->iR1; |
|
1330 info.iRmdArmExcInfo.iR2= aExcInfo->iR2; |
|
1331 info.iRmdArmExcInfo.iR3= aExcInfo->iR3; |
|
1332 |
|
1333 info.iRmdArmExcInfo.iR4= aExcInfo->iR4; |
|
1334 info.iRmdArmExcInfo.iR5= aExcInfo->iR5; |
|
1335 info.iRmdArmExcInfo.iR6= aExcInfo->iR6; |
|
1336 info.iRmdArmExcInfo.iR7= aExcInfo->iR7; |
|
1337 info.iRmdArmExcInfo.iR8= aExcInfo->iR8; |
|
1338 info.iRmdArmExcInfo.iR9= aExcInfo->iR9; |
|
1339 info.iRmdArmExcInfo.iR10= aExcInfo->iR10; |
|
1340 info.iRmdArmExcInfo.iR11= aExcInfo->iR11; |
|
1341 info.iRmdArmExcInfo.iR12= aExcInfo->iR12; |
|
1342 |
|
1343 info.iRmdArmExcInfo.iR13= aExcInfo->iR13; |
|
1344 info.iRmdArmExcInfo.iR14= aExcInfo->iR14; |
|
1345 info.iRmdArmExcInfo.iR15= aExcInfo->iR15; |
|
1346 |
|
1347 info.iRmdArmExcInfo.iCpsr= aExcInfo->iCpsr; |
|
1348 info.iRmdArmExcInfo.iR13Svc= aExcInfo->iR13Svc; |
|
1349 info.iRmdArmExcInfo.iR14Svc= aExcInfo->iR14Svc; |
|
1350 info.iRmdArmExcInfo.iSpsrSvc= aExcInfo->iSpsrSvc; |
|
1351 LOG_MSG5(" iCpsr=0x%x, iExcCode=0x%x, R14=0x%x, R15=0x%x", |
|
1352 aExcInfo->iCpsr, aExcInfo->iExcCode, aExcInfo->iR14, aExcInfo->iR15); |
|
1353 |
|
1354 switch (aExcInfo->iExcCode) |
|
1355 { |
|
1356 case 0: |
|
1357 info.iExceptionNumber = EExcCodeAbort; |
|
1358 LOG_EVENT_MSG(" iExcCode == 0 => EExcCodeAbort"); |
|
1359 break; |
|
1360 case 1: |
|
1361 info.iExceptionNumber = EExcDataAbort; |
|
1362 LOG_EVENT_MSG(" iExcCode == 1 => EExcDataAbort"); |
|
1363 break; |
|
1364 case 2: |
|
1365 info.iExceptionNumber = EExcInvalidOpCode; |
|
1366 LOG_EVENT_MSG(" iExcCode == 2 => EExcInvalidOpCode"); |
|
1367 break; |
|
1368 default: |
|
1369 // new event? Something gone wrong? |
|
1370 __NK_ASSERT_DEBUG(EFalse); |
|
1371 return EFalse; |
|
1372 } |
|
1373 |
|
1374 info.iEventType = EEventsHwExc; |
|
1375 |
|
1376 info.iArg1 = a1; |
|
1377 info.iArg2 = a2; |
|
1378 |
|
1379 if(EExcInvalidOpCode == info.iExceptionNumber) |
|
1380 { |
|
1381 return HandleInvalidOpCodeException(info, currentThread); |
|
1382 } |
|
1383 |
|
1384 NotifyEvent(info); |
|
1385 return EFalse; |
|
1386 } |
|
1387 |
|
1388 // |
|
1389 // DRM_DebugChannel::HandUserTrace |
|
1390 // |
|
1391 TBool DRM_DebugChannel::HandleUserTrace(TAny* a1, TAny* a2) |
|
1392 { |
|
1393 LOG_EVENT_MSG("DRM_DebugChannel::HandleUserTrace()"); |
|
1394 |
|
1395 DThread* currentThread = &Kern::CurrentThread(); |
|
1396 if (!currentThread) |
|
1397 { |
|
1398 LOG_EVENT_MSG("Error getting current thread"); |
|
1399 __NK_ASSERT_DEBUG(currentThread); |
|
1400 return EFalse; |
|
1401 } |
|
1402 |
|
1403 TDriverEventInfo info; |
|
1404 info.iProcessId = currentThread->iOwningProcess->iId; |
|
1405 info.iProcessIdValid = ETrue; |
|
1406 info.iThreadId = currentThread->iId; |
|
1407 info.iThreadIdValid = ETrue; |
|
1408 info.iEventType = EEventsUserTrace; |
|
1409 info.iArg1 = a1; |
|
1410 info.iArg2 = a2; |
|
1411 |
|
1412 TInt err = KErrNone; |
|
1413 |
|
1414 //User Trace info |
|
1415 XTRAP(err, XT_DEFAULT, kumemget(info.iUserTraceText, info.iArg1, (TInt)a2)); |
|
1416 if(KErrNone != err) |
|
1417 { |
|
1418 return EFalse; |
|
1419 } |
|
1420 |
|
1421 info.iMessageStatus = ESingleMessage; |
|
1422 |
|
1423 NotifyEvent(info); |
|
1424 |
|
1425 return EFalse; |
|
1426 } |
|
1427 |
|
1428 // |
|
1429 // DRM_DebugChannel::HandleException |
|
1430 // |
|
1431 TBool DRM_DebugChannel::HandleInvalidOpCodeException(TDriverEventInfo& aEventInfo, DThread* aCurrentThread) |
|
1432 { |
|
1433 LOG_EVENT_MSG("DRM_DebugChannel::HandleInvalidOpCodeException()"); |
|
1434 |
|
1435 TInt err = KErrNone; |
|
1436 |
|
1437 TUint32 inst = KArmBreakPoint; |
|
1438 TInt instSize = 4; |
|
1439 |
|
1440 // change these for thumb mode |
|
1441 TUint32 regValue; |
|
1442 err = ReadKernelRegisterValue(aCurrentThread, STATUS_REGISTER, regValue); |
|
1443 if(err != KErrNone) |
|
1444 { |
|
1445 LOG_EVENT_MSG2("DRM_DebugChannel::HandleInvalidOpCodeException - Non-zero error code discarded: %d", err); |
|
1446 } |
|
1447 |
|
1448 if (regValue & ECpuThumb) |
|
1449 { |
|
1450 inst = KThumbBreakPoint; |
|
1451 instSize = 2; |
|
1452 } |
|
1453 |
|
1454 TUint32 instruction = 0; |
|
1455 err = Kern::ThreadRawRead(aCurrentThread, (TUint32 *)aEventInfo.iRmdArmExcInfo.iR15, (TUint8 *)&instruction, instSize); |
|
1456 |
|
1457 if (KErrNone != err) |
|
1458 LOG_MSG2("Error reading instruction at currentpc: %d", err); |
|
1459 |
|
1460 if (!memcompare((TUint8 *)&inst, instSize, (TUint8 *)&instruction, instSize)) |
|
1461 { |
|
1462 TInt err = DoSuspendThread(aCurrentThread); |
|
1463 if(! ((KErrNone == err) || (KErrAlreadyExists == err)) ) |
|
1464 { |
|
1465 LOG_MSG2("DRM_DebugChannel::HandleInvalidOpCodeException() Thread with id 0x%08x could not be suspended.", aCurrentThread->iId); |
|
1466 return EFalse; |
|
1467 } |
|
1468 |
|
1469 // the exception was a breakpoint instruction. see if we have a breakpoint at that address |
|
1470 TBreakEntry* breakEntry = NULL; |
|
1471 do |
|
1472 { |
|
1473 breakEntry = iBreakManager->GetNextBreak(breakEntry); |
|
1474 if (breakEntry && ((breakEntry->iThreadSpecific && breakEntry->iId == aEventInfo.iThreadId) || (!breakEntry->iThreadSpecific && breakEntry->iId == aEventInfo.iProcessId)) && breakEntry->iAddress == aEventInfo.iRmdArmExcInfo.iR15) |
|
1475 { |
|
1476 LOG_EVENT_MSG2("Breakpoint with Id %d has been hit", breakEntry->iBreakId); |
|
1477 |
|
1478 TBreakEntry tempBreakEntry = *breakEntry; |
|
1479 |
|
1480 //change the event type to breakpoint type |
|
1481 aEventInfo.iEventType = breakEntry->iThreadSpecific ? EEventsBreakPoint : EEventsProcessBreakPoint; |
|
1482 |
|
1483 // enable any breakpoints we had to disable for this thread |
|
1484 err = iBreakManager->DoEnableDisabledBreak(aEventInfo.iThreadId); |
|
1485 if (KErrNone != err) |
|
1486 LOG_MSG2("Error %d enabling disabled breakpoints", err); |
|
1487 |
|
1488 // see if this is a temp breakpoint |
|
1489 if (iBreakManager->IsTemporaryBreak(*breakEntry)) |
|
1490 { |
|
1491 // this was a temp breakpoint, so we need to clear it now |
|
1492 err = iBreakManager->DoClearBreak(breakEntry->iBreakId); |
|
1493 if (KErrNone != err) |
|
1494 LOG_MSG2("Error %d clearing temp breakpoint", err); |
|
1495 |
|
1496 // Find out how many steps remain to be done |
|
1497 |
|
1498 // reduce the number of steps to complete by 1 |
|
1499 tempBreakEntry.iNumSteps--; |
|
1500 |
|
1501 LOG_EVENT_MSG2("There are %d steps remaining\n", tempBreakEntry.iNumSteps); |
|
1502 |
|
1503 // New. If we have not finished do all the steps, continue stepping and don't notify event |
|
1504 if (tempBreakEntry.iNumSteps) |
|
1505 { |
|
1506 LOG_EVENT_MSG("Continuing stepping...not telling the agent yet\n"); |
|
1507 err = DoStepRange(aCurrentThread, aEventInfo.iRmdArmExcInfo.iR15, aEventInfo.iRmdArmExcInfo.iR15, ETrue, tempBreakEntry.iResumeOnceOutOfRange /*EFalse*/, tempBreakEntry.iNumSteps, ETrue); |
|
1508 if (err != KErrNone) |
|
1509 { |
|
1510 LOG_EVENT_MSG("Failed to continue stepping\n"); |
|
1511 |
|
1512 // what do we do? might as well stop here and tell the user |
|
1513 NotifyEvent(aEventInfo); |
|
1514 |
|
1515 return ETrue; |
|
1516 } |
|
1517 |
|
1518 // continue as though no event occured. No need to suspend/resume anything... |
|
1519 LOG_EVENT_MSG("Continuing to step\n"); |
|
1520 return ETrue; |
|
1521 } |
|
1522 |
|
1523 // Is this a case where we just want to continue? |
|
1524 if (tempBreakEntry.iResumeOnceOutOfRange) |
|
1525 { |
|
1526 LOG_EVENT_MSG("PC is out of range, continuing thread"); |
|
1527 DoResumeThread(aCurrentThread); |
|
1528 |
|
1529 return ETrue; |
|
1530 } |
|
1531 } |
|
1532 |
|
1533 // if the breakpoint is thread specific, make sure it's the right thread |
|
1534 // if not, just continue the thread. take special care if it's the debugger |
|
1535 // thread. if it hits a regular breakpoint, we NEVER want to stop at it. if |
|
1536 // it hits a temp breakpoint, we're probably just stepping past a real breakpoint |
|
1537 // and we do need to handle it. |
|
1538 TBool needToResume = (tempBreakEntry.iThreadSpecific && tempBreakEntry.iId != aEventInfo.iThreadId) || |
|
1539 (!tempBreakEntry.iThreadSpecific && tempBreakEntry.iId != aEventInfo.iProcessId); |
|
1540 |
|
1541 if (needToResume) |
|
1542 { |
|
1543 LOG_EVENT_MSG("breakpoint does not match threadId, calling DoResumeThread"); |
|
1544 err = DoResumeThread(aCurrentThread); |
|
1545 if (KErrNone != err) |
|
1546 LOG_MSG2("Error in DoResumeThread: %d", err); |
|
1547 |
|
1548 return EFalse; |
|
1549 } |
|
1550 |
|
1551 //normal user break point, just notify the event |
|
1552 break; |
|
1553 } |
|
1554 } while(breakEntry); |
|
1555 } |
|
1556 |
|
1557 NotifyEvent(aEventInfo); |
|
1558 |
|
1559 return (aEventInfo.iEventType == EEventsBreakPoint) || (aEventInfo.iEventType == EEventsProcessBreakPoint); |
|
1560 } |
|
1561 |
|
1562 // |
|
1563 // DRM_DebugChannel::SetBreak |
|
1564 // |
|
1565 TInt DRM_DebugChannel::SetBreak(TSetBreakInfo* aBreakInfo) |
|
1566 { |
|
1567 LOG_MSG("DRM_DebugChannel::SetBreak()"); |
|
1568 |
|
1569 TInt err = KErrNone; |
|
1570 |
|
1571 if (!aBreakInfo) |
|
1572 { |
|
1573 LOG_MSG("DRM_DebugChannel::SetBreak() was passed a NULL argument"); |
|
1574 return KErrArgument; |
|
1575 } |
|
1576 |
|
1577 //User side memory is not accessible directly |
|
1578 TSetBreakInfo info; |
|
1579 err = Kern::ThreadRawRead(iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TSetBreakInfo)); |
|
1580 if (err != KErrNone) |
|
1581 { |
|
1582 LOG_MSG("DRM_DebugChannel::SetBreak() was passed a bad argument"); |
|
1583 return err; |
|
1584 } |
|
1585 |
|
1586 DProcess* process = NULL; |
|
1587 if(info.iThreadSpecific) |
|
1588 { |
|
1589 // if the target thread is not suspended then return KErrInUse |
|
1590 if(!TheDProcessTracker.CheckSuspended(info.iId)) |
|
1591 { |
|
1592 LOG_MSG2("DRM_DebugChannel::SetBreak() Thread with id 0x%08x not suspended.", info.iId); |
|
1593 return KErrInUse; |
|
1594 } |
|
1595 DThread* thread = DebugUtils::OpenThreadHandle(info.iId); |
|
1596 if(!thread) |
|
1597 { |
|
1598 LOG_MSG2("DRM_DebugChannel::SetBreak() Thread with id 0x%08x not found", info.iId); |
|
1599 return KErrNotFound; |
|
1600 } |
|
1601 process = DebugUtils::OpenProcessHandle(thread->iOwningProcess->iId); |
|
1602 thread->Close(NULL); |
|
1603 } |
|
1604 else |
|
1605 { |
|
1606 process = DebugUtils::OpenProcessHandle(info.iId); |
|
1607 } |
|
1608 |
|
1609 if(!process) |
|
1610 { |
|
1611 LOG_MSG2("DRM_DebugChannel::SetBreak() Process with id 0x%08x not found", process->iId); |
|
1612 return KErrNotFound; |
|
1613 } |
|
1614 |
|
1615 TBool found = EFalse; |
|
1616 for(TInt i=0; i<iDebugProcessList.Count(); i++) |
|
1617 { |
|
1618 if(process->iId == iDebugProcessList[i].iId) |
|
1619 { |
|
1620 found = ETrue; |
|
1621 } |
|
1622 } |
|
1623 |
|
1624 if(!found) |
|
1625 { |
|
1626 DCodeSeg* codeSeg = process->iCodeSeg; |
|
1627 if (!codeSeg) |
|
1628 { |
|
1629 LOG_MSG2("DRM_DebugChannel::SetBreak() Code seg for process with id 0x%08x not found", process->iId); |
|
1630 return KErrNotFound; |
|
1631 } |
|
1632 |
|
1633 TModuleMemoryInfo memoryInfo; |
|
1634 TInt err = codeSeg->GetMemoryInfo(memoryInfo, process); |
|
1635 if (err != KErrNone) |
|
1636 { |
|
1637 LOG_MSG2("DRM_DebugChannel::SetBreak() Error getting memory info for process with id 0x%08x", process->iId); |
|
1638 return err; |
|
1639 } |
|
1640 |
|
1641 //add this process to the list of processes that we are debugging |
|
1642 TProcessInfo processInfo(process->iId, memoryInfo.iCodeBase, memoryInfo.iCodeSize, memoryInfo.iInitialisedDataBase); |
|
1643 iDebugProcessList.Append(processInfo); |
|
1644 process->Close(NULL); |
|
1645 } |
|
1646 |
|
1647 if (!info.iBreakId) //first check if the iId address is valid |
|
1648 return KErrArgument; |
|
1649 |
|
1650 if (err == KErrNone) |
|
1651 { |
|
1652 TInt32 iBreakId; |
|
1653 |
|
1654 err = iBreakManager->DoSetBreak(iBreakId, info.iId, info.iThreadSpecific, info.iAddress, info.iMode ); |
|
1655 |
|
1656 if (err == KErrNone) |
|
1657 { |
|
1658 err = Kern::ThreadRawWrite(iClientThread, (TUint8 *)info.iBreakId, &iBreakId, sizeof(TInt32), iClientThread); |
|
1659 } |
|
1660 } |
|
1661 |
|
1662 return err; |
|
1663 } |
|
1664 |
|
1665 // |
|
1666 // DRM_DebugChannel::StepRange |
|
1667 // |
|
1668 TInt DRM_DebugChannel::StepRange(DThread* aThread, TRM_DebugStepInfo* aStepInfo) |
|
1669 { |
|
1670 LOG_MSG("DRM_DebugChannel::StepRange()"); |
|
1671 |
|
1672 TInt err = KErrNone; |
|
1673 |
|
1674 if(!TheDProcessTracker.CheckSuspended(aThread)) |
|
1675 { |
|
1676 LOG_MSG2("DRM_DebugChannel::StepRange() Thread with id 0x%08x not suspended.", aThread->iId); |
|
1677 return KErrInUse; |
|
1678 } |
|
1679 |
|
1680 if (!aStepInfo) |
|
1681 return KErrArgument; |
|
1682 |
|
1683 TRM_DebugStepInfo info(0, 0, 0); |
|
1684 err = Kern::ThreadRawRead(iClientThread, aStepInfo, (TUint8*)&info, sizeof(TRM_DebugStepInfo)); |
|
1685 |
|
1686 if (err != KErrNone) |
|
1687 return err; |
|
1688 |
|
1689 err = DoStepRange(aThread, info.iStartAddress, info.iStopAddress, info.iStepInto, EFalse, ETrue); |
|
1690 |
|
1691 return err; |
|
1692 } |
|
1693 |
|
1694 /** |
|
1695 Read memory from a target thread and return the data to the client. If the |
|
1696 memory block has breakpoints in it then the correct values are placed in the |
|
1697 returned data |
|
1698 |
|
1699 @param aThread pointer to thread whose memory space the memory is to be read from |
|
1700 @param aMemoryInfo information about what memory to read |
|
1701 |
|
1702 @return KErrNone if memory read successfully, |
|
1703 KErrArgument if aMemoryInfo is not initialised correctly, |
|
1704 KErrNoMemory if a temporary buffer could not be allocated, |
|
1705 KErrBadHandle if aThread is invalid, |
|
1706 or another of the system wide error codes |
|
1707 */ |
|
1708 TInt DRM_DebugChannel::ReadMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo) |
|
1709 { |
|
1710 LOG_MSG("DRM_DebugChannel::ReadMemory()"); |
|
1711 |
|
1712 TInt err = KErrNone; |
|
1713 |
|
1714 if (!aMemoryInfo) |
|
1715 return KErrArgument; |
|
1716 |
|
1717 TRM_DebugMemoryInfo info(0, 0, 0); |
|
1718 err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TRM_DebugMemoryInfo)); |
|
1719 if (err != KErrNone) |
|
1720 return err; |
|
1721 |
|
1722 if (!info.iData) |
|
1723 return KErrArgument; |
|
1724 |
|
1725 NKern::ThreadEnterCS(); |
|
1726 TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); |
|
1727 NKern::ThreadLeaveCS(); |
|
1728 if (!data) |
|
1729 { |
|
1730 return KErrNoMemory; |
|
1731 } |
|
1732 |
|
1733 TPtr8 dataDes(data, info.iLength); |
|
1734 |
|
1735 err = DoReadMemory(aThread, info.iAddress, info.iLength, dataDes); |
|
1736 if (err == KErrNone) |
|
1737 { |
|
1738 err = Kern::ThreadDesWrite(iClientThread, info.iData, dataDes, 0, KChunkShiftBy0, iClientThread); |
|
1739 } |
|
1740 |
|
1741 NKern::ThreadEnterCS(); |
|
1742 Kern::Free(data); |
|
1743 NKern::ThreadLeaveCS(); |
|
1744 |
|
1745 return err; |
|
1746 } |
|
1747 |
|
1748 /** |
|
1749 Attempt to write memory to aThread's address space |
|
1750 |
|
1751 @param aThread thread to whose address space memory is to be written |
|
1752 @param aMemoryInfo memory info object representing the data to write |
|
1753 |
|
1754 @return KErrNone if memory written successfully, |
|
1755 KErrNoMemory if memory could not be allocated |
|
1756 KErrArgument if aMemoryInfo is NULL, if aMemoryInfo.iData is NULL, |
|
1757 if aMemoryInfo.iLength is greater than than the length of the passed |
|
1758 in descrptor |
|
1759 KErrBadHandle if aThread is invalid, |
|
1760 or another of the system wide error codes |
|
1761 */ |
|
1762 TInt DRM_DebugChannel::WriteMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo) |
|
1763 { |
|
1764 LOG_MSG("DRM_DebugChannel::WriteMemory()"); |
|
1765 |
|
1766 TInt err = KErrNone; |
|
1767 |
|
1768 if (!aMemoryInfo) |
|
1769 return KErrArgument; |
|
1770 |
|
1771 TRM_DebugMemoryInfo info(0, 0, 0); |
|
1772 err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TRM_DebugMemoryInfo)); |
|
1773 if (err != KErrNone) |
|
1774 return err; |
|
1775 |
|
1776 if (!info.iData) |
|
1777 return KErrArgument; |
|
1778 |
|
1779 NKern::ThreadEnterCS(); |
|
1780 TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); |
|
1781 NKern::ThreadLeaveCS(); |
|
1782 if (!data) |
|
1783 { |
|
1784 return KErrNoMemory; |
|
1785 } |
|
1786 |
|
1787 TPtr8 dataDes(data, info.iLength); |
|
1788 |
|
1789 err = Kern::ThreadDesRead(iClientThread, info.iData, dataDes, 0); |
|
1790 if (err == KErrNone) |
|
1791 { |
|
1792 err = DoWriteMemory(aThread, info.iAddress, info.iLength, dataDes); |
|
1793 } |
|
1794 |
|
1795 NKern::ThreadEnterCS(); |
|
1796 Kern::Free(data); |
|
1797 NKern::ThreadLeaveCS(); |
|
1798 |
|
1799 return err; |
|
1800 } |
|
1801 |
|
1802 // |
|
1803 // DRM_DebugChannel::ReadRegisters |
|
1804 // |
|
1805 TInt DRM_DebugChannel::ReadRegistersLegacy(DThread* aThread, TRM_DebugRegisterInfo* aRegisterInfo) |
|
1806 { |
|
1807 LOG_MSG("DRM_DebugChannel::ReadRegistersLegacy()"); |
|
1808 |
|
1809 TInt err = KErrNone; |
|
1810 |
|
1811 if (!aRegisterInfo) |
|
1812 return KErrArgument; |
|
1813 |
|
1814 TRM_DebugRegisterInfo info(0, 0, 0); |
|
1815 err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInfo)); |
|
1816 if (err != KErrNone) |
|
1817 return err; |
|
1818 |
|
1819 if (!info.iValues) |
|
1820 return KErrArgument; |
|
1821 |
|
1822 TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; |
|
1823 |
|
1824 NKern::ThreadEnterCS(); |
|
1825 TUint8 *values = (TUint8*)Kern::Alloc(length); |
|
1826 NKern::ThreadLeaveCS(); |
|
1827 if (!values) |
|
1828 { |
|
1829 return KErrNoMemory; |
|
1830 } |
|
1831 |
|
1832 TPtr8 valuesDes(values, length); |
|
1833 |
|
1834 err = DoReadRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); |
|
1835 if (err == KErrNone) |
|
1836 { |
|
1837 err = Kern::ThreadDesWrite(iClientThread, info.iValues, valuesDes, 0, KChunkShiftBy0, iClientThread); |
|
1838 } |
|
1839 |
|
1840 NKern::ThreadEnterCS(); |
|
1841 Kern::Free(values); |
|
1842 NKern::ThreadLeaveCS(); |
|
1843 |
|
1844 return err; |
|
1845 } |
|
1846 |
|
1847 /** |
|
1848 Get listing information. |
|
1849 |
|
1850 @param aListInformation pointer to a TListInformation object containing the |
|
1851 user specified listings information |
|
1852 |
|
1853 @return KErrNone on success, |
|
1854 KErrTooBig if the kernel's data is too big to fit in the passed buffer, |
|
1855 KErrArgument if aListInformation is NULL, |
|
1856 or one of the other system-wide error codes |
|
1857 */ |
|
1858 TInt DRM_DebugChannel::GetList(TListInformation* aListInformation) const |
|
1859 { |
|
1860 LOG_MSG("DRM_DebugChannel::GetList()"); |
|
1861 |
|
1862 TInt err = KErrNone; |
|
1863 |
|
1864 if(aListInformation == NULL) |
|
1865 { |
|
1866 return KErrArgument; |
|
1867 } |
|
1868 |
|
1869 //read DSS' data into local structure |
|
1870 TListInformation info; |
|
1871 err = Kern::ThreadRawRead(iClientThread, aListInformation, (TUint8*)&info, sizeof(TListInformation)); |
|
1872 if(err != KErrNone) |
|
1873 { |
|
1874 return err; |
|
1875 } |
|
1876 |
|
1877 //check arguments |
|
1878 TPtr8 buffer(NULL, 0); |
|
1879 err = AllocAndReadDes(iClientThread, *info.iBuffer, buffer); |
|
1880 if(err != KErrNone) |
|
1881 { |
|
1882 //need to free the buffer if it was allocated |
|
1883 if(err != KErrNoMemory) |
|
1884 { |
|
1885 NKern::ThreadEnterCS(); |
|
1886 Kern::Free((TAny*)buffer.Ptr()); |
|
1887 NKern::ThreadLeaveCS(); |
|
1888 } |
|
1889 return err; |
|
1890 } |
|
1891 |
|
1892 //get the list |
|
1893 TUint32 dataSize = 0; |
|
1894 TListManager manager; |
|
1895 err = KErrArgument; |
|
1896 switch(info.iType) |
|
1897 { |
|
1898 case EXipLibraries: |
|
1899 if(Debug::EScopeGlobal == info.iListScope) |
|
1900 { |
|
1901 err = manager.GetXipLibrariesList(buffer, dataSize); |
|
1902 } |
|
1903 break; |
|
1904 |
|
1905 case EThreads: |
|
1906 if(Debug::EScopeGlobal == info.iListScope) |
|
1907 { |
|
1908 err = manager.GetGlobalThreadList(buffer, dataSize); |
|
1909 } |
|
1910 else if(Debug::EScopeProcessSpecific == info.iListScope) |
|
1911 { |
|
1912 err = manager.GetThreadListForProcess(buffer, dataSize, info.iTargetId); |
|
1913 } |
|
1914 else if(Debug::EScopeThreadSpecific == info.iListScope) |
|
1915 { |
|
1916 err = manager.GetThreadListForThread(buffer, dataSize, info.iTargetId); |
|
1917 } |
|
1918 break; |
|
1919 |
|
1920 case EProcesses: |
|
1921 if(Debug::EScopeGlobal == info.iListScope) |
|
1922 { |
|
1923 err = manager.GetProcessList(buffer, dataSize); |
|
1924 } |
|
1925 break; |
|
1926 |
|
1927 case ECodeSegs: |
|
1928 if(Debug::EScopeGlobal == info.iListScope) |
|
1929 { |
|
1930 err = manager.GetGlobalCodeSegList(buffer, dataSize); |
|
1931 } |
|
1932 else if(Debug::EScopeProcessSpecific == info.iListScope) |
|
1933 { |
|
1934 err = manager.GetCodeSegListForProcess(buffer, dataSize, info.iTargetId); |
|
1935 } |
|
1936 else if(Debug::EScopeThreadSpecific == info.iListScope) |
|
1937 { |
|
1938 err = manager.GetCodeSegListForThread(buffer, dataSize, info.iTargetId); |
|
1939 } |
|
1940 break; |
|
1941 |
|
1942 default: |
|
1943 err = KErrNotSupported; |
|
1944 } |
|
1945 |
|
1946 if(err == KErrNone) |
|
1947 { |
|
1948 //if no error then write the buffer back |
|
1949 err = Kern::ThreadDesWrite(iClientThread, info.iBuffer, buffer, 0, KChunkShiftBy0, iClientThread); |
|
1950 } |
|
1951 |
|
1952 //write back the size of the data regardless of any error |
|
1953 TInt writeErr = Kern::ThreadRawWrite(iClientThread, info.iDataSize, (TUint8*)&dataSize, sizeof(TUint32), iClientThread); |
|
1954 if(writeErr != KErrNone) |
|
1955 { |
|
1956 //if there was an error writing the size return that error instead |
|
1957 err = writeErr; |
|
1958 } |
|
1959 |
|
1960 //free the buffer |
|
1961 NKern::ThreadEnterCS(); |
|
1962 Kern::Free((TAny*)buffer.Ptr()); |
|
1963 NKern::ThreadLeaveCS(); |
|
1964 |
|
1965 return err; |
|
1966 } |
|
1967 |
|
1968 /** |
|
1969 Read registers and store register data in aRegisterInfo |
|
1970 |
|
1971 @param aThread thread to read registers from |
|
1972 @param aRegisterInfo structure specifying which registers to read and providing |
|
1973 descriptors to write the register data into |
|
1974 |
|
1975 @return KErrNone if registers were read successfully. Note that this does not |
|
1976 mean that all the registers could be read, the |
|
1977 aRegisterInfo.iRegisterFlags array should be checked as to whether each |
|
1978 individual register could be read, |
|
1979 KErrArgument if aRegisterInfo is NULL, or if any of the pointers that |
|
1980 are members of aRegisterInfo are NULL, if an unknown register is |
|
1981 specified or if the passed in register values buffer is too small |
|
1982 KErrNoMemory if there is insufficient memory, |
|
1983 KErrDied, if the thread with thread ID aThreadId is dead |
|
1984 */ |
|
1985 TInt DRM_DebugChannel::ReadRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const |
|
1986 { |
|
1987 LOG_MSG("DRM_DebugChannel::ReadRegisters()"); |
|
1988 |
|
1989 TInt err = KErrNone; |
|
1990 |
|
1991 if (!aRegisterInfo) |
|
1992 return KErrArgument; |
|
1993 |
|
1994 TRM_DebugRegisterInformation info; |
|
1995 err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInformation)); |
|
1996 if (err != KErrNone) |
|
1997 return err; |
|
1998 |
|
1999 if ((!info.iRegisterIds) || (!info.iRegisterValues) || (!info.iRegisterFlags)) |
|
2000 return KErrArgument; |
|
2001 |
|
2002 //read ids from client thread |
|
2003 TPtr8 ids(NULL, 0); |
|
2004 err = AllocAndReadDes(iClientThread, *info.iRegisterIds, ids); |
|
2005 if(err != KErrNone) |
|
2006 { |
|
2007 if(err == KErrNoMemory) |
|
2008 { |
|
2009 NKern::ThreadEnterCS(); |
|
2010 Kern::Free((TAny*)ids.Ptr()); |
|
2011 NKern::ThreadLeaveCS(); |
|
2012 } |
|
2013 return err; |
|
2014 } |
|
2015 |
|
2016 //read values from client thread |
|
2017 TPtr8 values(NULL, 0); |
|
2018 err = AllocAndReadDes(iClientThread, *info.iRegisterValues, values, EFalse); |
|
2019 if(err != KErrNone) |
|
2020 { |
|
2021 if(err == KErrNoMemory) |
|
2022 { |
|
2023 NKern::ThreadEnterCS(); |
|
2024 Kern::Free((TAny*)values.Ptr()); |
|
2025 NKern::ThreadLeaveCS(); |
|
2026 } |
|
2027 |
|
2028 NKern::ThreadEnterCS(); |
|
2029 Kern::Free((TAny*)ids.Ptr()); |
|
2030 NKern::ThreadLeaveCS(); |
|
2031 return err; |
|
2032 } |
|
2033 |
|
2034 //read flags from client thread |
|
2035 TPtr8 flags(NULL, 0); |
|
2036 err = AllocAndReadDes(iClientThread, *info.iRegisterFlags, flags, EFalse); |
|
2037 if(err != KErrNone) |
|
2038 { |
|
2039 if(err == KErrNoMemory) |
|
2040 { |
|
2041 NKern::ThreadEnterCS(); |
|
2042 Kern::Free((TAny*)flags.Ptr()); |
|
2043 NKern::ThreadLeaveCS(); |
|
2044 } |
|
2045 NKern::ThreadEnterCS(); |
|
2046 Kern::Free((TAny*)ids.Ptr()); |
|
2047 Kern::Free((TAny*)values.Ptr()); |
|
2048 NKern::ThreadLeaveCS(); |
|
2049 return err; |
|
2050 } |
|
2051 |
|
2052 err = DoReadRegisters(aThread, ids, values, flags); |
|
2053 if (err == KErrNone) |
|
2054 { |
|
2055 err = Kern::ThreadDesWrite(iClientThread, info.iRegisterValues, values, 0, KChunkShiftBy0, iClientThread); |
|
2056 if(err == KErrNone) |
|
2057 { |
|
2058 err = Kern::ThreadDesWrite(iClientThread, info.iRegisterFlags, flags, 0, KChunkShiftBy0, iClientThread); |
|
2059 } |
|
2060 } |
|
2061 |
|
2062 NKern::ThreadEnterCS(); |
|
2063 Kern::Free((TAny*)ids.Ptr()); |
|
2064 Kern::Free((TAny*)values.Ptr()); |
|
2065 Kern::Free((TAny*)flags.Ptr()); |
|
2066 NKern::ThreadLeaveCS(); |
|
2067 |
|
2068 return err; |
|
2069 } |
|
2070 |
|
2071 /** |
|
2072 @deprecated use DRM_DebugChannel::WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) instead |
|
2073 */ |
|
2074 TInt DRM_DebugChannel::WriteRegistersLegacy(DThread* aThread, const TRM_DebugRegisterInfo* aRegisterInfo) |
|
2075 { |
|
2076 LOG_MSG("DRM_DebugChannel::WriteRegistersLegacy()"); |
|
2077 |
|
2078 TInt err = KErrNone; |
|
2079 |
|
2080 if (!aRegisterInfo) |
|
2081 return KErrArgument; |
|
2082 |
|
2083 TRM_DebugRegisterInfo info(0, 0, 0); |
|
2084 err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInfo)); |
|
2085 if (err != KErrNone) |
|
2086 return err; |
|
2087 |
|
2088 if (!info.iValues) |
|
2089 return KErrArgument; |
|
2090 |
|
2091 TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; |
|
2092 |
|
2093 NKern::ThreadEnterCS(); |
|
2094 TUint8 *values = (TUint8*)Kern::Alloc(length); |
|
2095 NKern::ThreadLeaveCS(); |
|
2096 if (!values) |
|
2097 { |
|
2098 return KErrNoMemory; |
|
2099 } |
|
2100 |
|
2101 TPtr8 valuesDes(values, length); |
|
2102 |
|
2103 err = Kern::ThreadDesRead(iClientThread, info.iValues, valuesDes, 0); |
|
2104 if (err == KErrNone) |
|
2105 { |
|
2106 err = DoWriteRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); |
|
2107 } |
|
2108 |
|
2109 NKern::ThreadEnterCS(); |
|
2110 Kern::Free(values); |
|
2111 NKern::ThreadLeaveCS(); |
|
2112 |
|
2113 return err; |
|
2114 } |
|
2115 |
|
2116 /** |
|
2117 Write registers and store flags data in aRegisterInfo |
|
2118 |
|
2119 @param aThread thread to write registers to |
|
2120 @param aRegisterInfo structure specifying which registers to write and providing |
|
2121 descriptors to write the register flags data into |
|
2122 |
|
2123 @return KErrNone if registers were written successfully. Note that this does not |
|
2124 mean that all the registers could be written, the flags array |
|
2125 should be checked as to whether each individual register could be read, |
|
2126 KErrArgument if aRegisterInfo is NULL, or if any of the pointers that |
|
2127 are members of aRegisterInfo are NULL, if an unknown register is |
|
2128 specified or if the passed in register values buffer is too small, or |
|
2129 if aThread is NULL, |
|
2130 KErrGeneral if there was a problem initialising the register set, |
|
2131 KErrNoMemory if there is insufficient memory, |
|
2132 KErrDied, if the thread with thread ID aThreadId is dead |
|
2133 */ |
|
2134 TInt DRM_DebugChannel::WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const |
|
2135 { |
|
2136 LOG_MSG("DRM_DebugChannel::WriteRegisters()"); |
|
2137 |
|
2138 TInt err = KErrNone; |
|
2139 |
|
2140 if (!aRegisterInfo) |
|
2141 return KErrArgument; |
|
2142 |
|
2143 TRM_DebugRegisterInformation info; |
|
2144 err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInformation)); |
|
2145 if (err != KErrNone) |
|
2146 return err; |
|
2147 |
|
2148 if ((!info.iRegisterIds) || (!info.iRegisterValues) ||(!info.iRegisterFlags)) |
|
2149 return KErrArgument; |
|
2150 |
|
2151 //read ids from client thread |
|
2152 TPtr8 ids(NULL, 0); |
|
2153 err = AllocAndReadDes(iClientThread, *info.iRegisterIds, ids); |
|
2154 if(err != KErrNone) |
|
2155 { |
|
2156 if(err == KErrNoMemory) |
|
2157 { |
|
2158 NKern::ThreadEnterCS(); |
|
2159 Kern::Free((TAny*)ids.Ptr()); |
|
2160 NKern::ThreadLeaveCS(); |
|
2161 } |
|
2162 return err; |
|
2163 } |
|
2164 |
|
2165 //read values from client thread |
|
2166 TPtr8 values(NULL, 0); |
|
2167 err = AllocAndReadDes(iClientThread, *info.iRegisterValues, values); |
|
2168 if(err != KErrNone) |
|
2169 { |
|
2170 if(err == KErrNoMemory) |
|
2171 { |
|
2172 NKern::ThreadEnterCS(); |
|
2173 Kern::Free((TAny*)values.Ptr()); |
|
2174 NKern::ThreadLeaveCS(); |
|
2175 } |
|
2176 NKern::ThreadEnterCS(); |
|
2177 Kern::Free((TAny*)ids.Ptr()); |
|
2178 NKern::ThreadLeaveCS(); |
|
2179 return err; |
|
2180 } |
|
2181 |
|
2182 //read flags from client thread |
|
2183 TPtr8 flags(NULL, 0); |
|
2184 err = AllocAndReadDes(iClientThread, *info.iRegisterFlags, flags, EFalse); |
|
2185 if(err != KErrNone) |
|
2186 { |
|
2187 if(err == KErrNoMemory) |
|
2188 { |
|
2189 NKern::ThreadEnterCS(); |
|
2190 Kern::Free((TAny*)flags.Ptr()); |
|
2191 NKern::ThreadLeaveCS(); |
|
2192 } |
|
2193 NKern::ThreadEnterCS(); |
|
2194 Kern::Free((TAny*)ids.Ptr()); |
|
2195 Kern::Free((TAny*)values.Ptr()); |
|
2196 NKern::ThreadLeaveCS(); |
|
2197 return err; |
|
2198 } |
|
2199 |
|
2200 err = DoWriteRegisters(aThread, ids, values, flags); |
|
2201 if(err == KErrNone) |
|
2202 { |
|
2203 err = Kern::ThreadDesWrite(iClientThread, info.iRegisterFlags, flags, 0, KChunkShiftBy0, iClientThread); |
|
2204 } |
|
2205 |
|
2206 NKern::ThreadEnterCS(); |
|
2207 Kern::Free((TAny*)ids.Ptr()); |
|
2208 Kern::Free((TAny*)values.Ptr()); |
|
2209 Kern::Free((TAny*)flags.Ptr()); |
|
2210 NKern::ThreadLeaveCS(); |
|
2211 |
|
2212 return err; |
|
2213 } |
|
2214 |
|
2215 /** |
|
2216 Suspends execution of the specified thread. |
|
2217 |
|
2218 @param aThread thread to resume |
|
2219 |
|
2220 @return KErrNone if there were no problems or KErrArgument if aThread is NULL |
|
2221 */ |
|
2222 TInt DRM_DebugChannel::DoSuspendThread(DThread *aThread) |
|
2223 { |
|
2224 LOG_MSG("DRM_DebugChannel::DoSuspendThread()"); |
|
2225 |
|
2226 if (!aThread) |
|
2227 { |
|
2228 LOG_MSG("Invalid dthread object"); |
|
2229 return KErrArgument; |
|
2230 } |
|
2231 |
|
2232 return TheDProcessTracker.SuspendThread(aThread); |
|
2233 } |
|
2234 |
|
2235 /** |
|
2236 Resumes execution of the specified thread. |
|
2237 |
|
2238 @param aThread thread to resume |
|
2239 |
|
2240 @return KErrNone if there were no problems, KErrArgument if aThread is NULL |
|
2241 or an error value returned from DoStepRange() |
|
2242 */ |
|
2243 TInt DRM_DebugChannel::DoResumeThread(DThread *aThread) |
|
2244 { |
|
2245 LOG_MSG("DRM_DebugChannel::DoResumeThread()"); |
|
2246 |
|
2247 if (!aThread) |
|
2248 return KErrArgument; |
|
2249 |
|
2250 // get the current PC |
|
2251 TUint32 currentPC; |
|
2252 TInt err = ReadKernelRegisterValue(aThread, PC_REGISTER, currentPC); |
|
2253 if(err != KErrNone) |
|
2254 { |
|
2255 LOG_MSG2("DRM_DebugChannel::DoResumeThread - Non-zero error code discarded: %d", err); |
|
2256 } |
|
2257 |
|
2258 // if there is a breakpoint at the current PC, we need to single step past it |
|
2259 TBreakEntry* breakEntry = NULL; |
|
2260 do |
|
2261 { |
|
2262 breakEntry = iBreakManager->GetNextBreak(breakEntry); |
|
2263 if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) |
|
2264 { |
|
2265 if (breakEntry->iAddress == currentPC) |
|
2266 { |
|
2267 return DoStepRange(aThread, currentPC, currentPC+1, ETrue, 1, ETrue); |
|
2268 } |
|
2269 } |
|
2270 } while(breakEntry); |
|
2271 |
|
2272 return TheDProcessTracker.ResumeThread(aThread); |
|
2273 } |
|
2274 |
|
2275 // |
|
2276 // DRM_DebugChannel::DoStepRange |
|
2277 // |
|
2278 TInt DRM_DebugChannel::DoStepRange(DThread *aThread, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto, TBool aResumeOnceOutOfRange, const TUint32 aNumSteps, TBool aUserRequest) |
|
2279 { |
|
2280 LOG_MSG("DRM_DebugChannel::DoStepRange()"); |
|
2281 |
|
2282 if (!aThread) |
|
2283 return KErrArgument; |
|
2284 |
|
2285 //check that the thread is suspended |
|
2286 if(!TheDProcessTracker.CheckSuspended(aThread)) |
|
2287 { |
|
2288 LOG_MSG2("DRM_DebugChannel::DoStepRange() Thread with id 0x%08x not suspended.", aThread->iId); |
|
2289 return KErrInUse; |
|
2290 } |
|
2291 |
|
2292 TUint32 startAddress = (aStartAddress & 0x1) ? aStartAddress + 1 : aStartAddress; |
|
2293 TUint32 stopAddress = (aStopAddress & 0x1) ? aStopAddress + 1 : aStopAddress;; |
|
2294 |
|
2295 // don't allow the user to step in the excluded ROM region. this could be called |
|
2296 // internally however. for example, the the special breakpoints we set to handle |
|
2297 // panics, exceptions, and library loaded events are in the user library, and we |
|
2298 // will need to step past the breakpoint before continuing the thread. |
|
2299 //if (aUserRequest && (startAddress >= iExcludedROMAddressStart) && (startAddress < iExcludedROMAddressEnd)) |
|
2300 //{ |
|
2301 // return KErrNotSupported; |
|
2302 //} |
|
2303 |
|
2304 // set the temp breakpoint, and disable the breakpoint at the current PC if necessary |
|
2305 // if its not a user request, and we are just trying to resume from a breakpoint, |
|
2306 // then we don't need to check for stubs. The last parameter aUserRequest tells |
|
2307 // ModifyBreaksForStep to check for stubs or not. In some cases, the check for stubs |
|
2308 // is true even if its not a user request.For example, this is true in cases where |
|
2309 // we are doing a step range and the instruction in the range modified PC. |
|
2310 // in this case, DoStepRange will be called from the exception handler where |
|
2311 // we need to check for the stubs for the valid behavior. So truly, we don't need to check |
|
2312 // for stubs only when resuming from a breakpoint. |
|
2313 ReturnIfError(iStepper->ModifyBreaksForStep(aThread, startAddress, stopAddress, aResumeOnceOutOfRange, aUserRequest, aNumSteps)); |
|
2314 |
|
2315 LOG_MSG("DRM_DebugChannel::DoStepRange() - resuming thread\n"); |
|
2316 |
|
2317 return TheDProcessTracker.ResumeThread(aThread); |
|
2318 } |
|
2319 |
|
2320 /** |
|
2321 Read memory from the specified addres into the aData descriptor. If there is a |
|
2322 breakpoint set in the region of memory returned then the correct data value is |
|
2323 inserted into the descriptor |
|
2324 |
|
2325 @param aThread pointer to thread whose address space memory is to be read from |
|
2326 @param aAddress address to start reading memory from |
|
2327 @param aLength length of memory block to read |
|
2328 @param aData descriptor to read memory into |
|
2329 |
|
2330 @return KErrNone if memory read successfully, |
|
2331 KErrNotSupported if reading from the rom section is not supported, |
|
2332 KErrBadHandle if aThread is invalid, |
|
2333 or one of the other system wide error codes |
|
2334 */ |
|
2335 TInt DRM_DebugChannel::DoReadMemory(const DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) const |
|
2336 { |
|
2337 LOG_MSG("DRM_DebugChannel::DoReadMemory()"); |
|
2338 |
|
2339 // make sure the parameters are valid |
|
2340 if (aLength > aData.MaxSize()) |
|
2341 return KErrArgument; |
|
2342 |
|
2343 TInt err = KErrNone; |
|
2344 |
|
2345 // trap exceptions in case the address is invalid |
|
2346 XTRAPD(r, XT_DEFAULT, err = TryToReadMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); |
|
2347 |
|
2348 err = (KErrNone == r) ? err : r; |
|
2349 |
|
2350 if (KErrNone == err) |
|
2351 { |
|
2352 aData.SetLength(aLength); |
|
2353 |
|
2354 TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); |
|
2355 |
|
2356 // if we have any breakpoints in this range, put the actual instruction in the buffer |
|
2357 TBreakEntry* breakEntry = NULL; |
|
2358 do |
|
2359 { |
|
2360 breakEntry = iBreakManager->GetNextBreak(breakEntry); |
|
2361 if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) |
|
2362 { |
|
2363 if ((breakEntry->iAddress >= aAddress) && (breakEntry->iAddress < (aAddress + aLength))) |
|
2364 { |
|
2365 TInt instSize; |
|
2366 |
|
2367 switch(breakEntry->iMode) |
|
2368 { |
|
2369 case EArmMode: |
|
2370 instSize = 4; |
|
2371 break; |
|
2372 |
|
2373 case EThumbMode: |
|
2374 instSize = 2; |
|
2375 break; |
|
2376 |
|
2377 case EThumb2EEMode: |
|
2378 default: |
|
2379 LOG_MSG("DRM_DebugChannel::DoReadMemory() cannot fixup breakpoints with unsupported architecture"); |
|
2380 return KErrNotSupported; |
|
2381 } |
|
2382 memcpy((TAny*)&data[breakEntry->iAddress - aAddress], (TAny *)breakEntry->iInstruction.Ptr(), instSize); |
|
2383 } |
|
2384 } |
|
2385 } while(breakEntry); |
|
2386 } |
|
2387 |
|
2388 return err; |
|
2389 } |
|
2390 |
|
2391 /** |
|
2392 Attempt to write memory to aThread's address space |
|
2393 |
|
2394 @param aThread thread to whose address space memory is to be written |
|
2395 @param aAddress memory location to write memory to |
|
2396 @param aLength number of bytes of data to write |
|
2397 @param aData descriptor containing memory to write |
|
2398 |
|
2399 @return KErrNone if memory written successfully, |
|
2400 KErrArgument if aLength is greater than than the length of the aData |
|
2401 KErrBadHandle if aThread is invalid, |
|
2402 or another of the system wide error codes |
|
2403 */ |
|
2404 TInt DRM_DebugChannel::DoWriteMemory(DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) |
|
2405 { |
|
2406 LOG_MSG("DRM_DebugChannel::DoWriteMemory()"); |
|
2407 |
|
2408 // make sure the parameters are valid |
|
2409 if (aLength > aData.Length()) |
|
2410 return KErrArgument; |
|
2411 |
|
2412 TInt err = KErrNone; |
|
2413 |
|
2414 // trap exceptions in case the address is invalid |
|
2415 XTRAPD(r, XT_DEFAULT, err = TryToWriteMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); |
|
2416 |
|
2417 err = (KErrNone == r) ? err : r; |
|
2418 |
|
2419 // reset any breakpoints we may have just overwritten |
|
2420 if (KErrNone == err) |
|
2421 { |
|
2422 TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); |
|
2423 |
|
2424 TBreakEntry* breakEntry = NULL; |
|
2425 do |
|
2426 { |
|
2427 breakEntry = iBreakManager->GetNextBreak(breakEntry); |
|
2428 if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) |
|
2429 { |
|
2430 if ((breakEntry->iAddress >= aAddress) && (breakEntry->iAddress < (aAddress + aLength))) |
|
2431 { |
|
2432 // default to arm mode |
|
2433 TUint32 inst; |
|
2434 TInt instSize; |
|
2435 |
|
2436 switch (breakEntry->iMode) |
|
2437 { |
|
2438 case EArmMode: |
|
2439 inst = KArmBreakPoint; |
|
2440 instSize = 4; |
|
2441 break; |
|
2442 |
|
2443 case EThumbMode: |
|
2444 inst = KThumbBreakPoint; |
|
2445 instSize = 2; |
|
2446 break; |
|
2447 |
|
2448 case EThumb2EEMode: |
|
2449 default: |
|
2450 LOG_MSG("DRM_DebugChannel::DoWriteMemory() cannot fixup breakpoints of unsupported architecture type"); |
|
2451 |
|
2452 return KErrNotSupported; |
|
2453 } |
|
2454 |
|
2455 breakEntry->iInstruction.Copy(&data[breakEntry->iAddress - aAddress], instSize); |
|
2456 memcpy((TAny*)breakEntry->iAddress, (TAny *)&inst, instSize); |
|
2457 } |
|
2458 } |
|
2459 |
|
2460 } while(breakEntry); |
|
2461 } |
|
2462 return err; |
|
2463 } |
|
2464 |
|
2465 // |
|
2466 // DRM_DebugChannel::DoReadRegisters |
|
2467 // |
|
2468 TInt DRM_DebugChannel::DoReadRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDes8 &aValues) |
|
2469 { |
|
2470 LOG_EVENT_MSG("DRM_DebugChannel::DoReadRegisters()"); |
|
2471 |
|
2472 // make sure the parameters are valid |
|
2473 if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) |
|
2474 return KErrArgument; |
|
2475 |
|
2476 // make sure the descriptor is big enough to hold the requested data |
|
2477 if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.MaxSize())) |
|
2478 return KErrArgument; |
|
2479 |
|
2480 TArmRegSet regSet; |
|
2481 TUint32 unused; |
|
2482 |
|
2483 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); |
|
2484 |
|
2485 LOG_MSG2( "DRM_DebugChannel::DoReadRegistersLegacy() : unused = 0x%X\n", unused ); |
|
2486 |
|
2487 TArmReg *reg = ®Set.iR0; |
|
2488 |
|
2489 if (!reg) |
|
2490 return KErrGeneral; |
|
2491 |
|
2492 for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) |
|
2493 aValues.Append((TUint8 *)®[i], sizeof(TArmReg)); |
|
2494 |
|
2495 return KErrNone; |
|
2496 } |
|
2497 |
|
2498 /** |
|
2499 @prototype |
|
2500 |
|
2501 Experimental function for determining whether a thread is suspended. |
|
2502 |
|
2503 @param aThread thread to check if suspended |
|
2504 |
|
2505 @return ETrue if the thread is suspended, EFalse if it isn't or does not exist |
|
2506 */ |
|
2507 TBool DRM_DebugChannel::CheckSuspended(const DThread *aThread) const |
|
2508 { |
|
2509 if(!aThread) |
|
2510 { |
|
2511 return EFalse; |
|
2512 } |
|
2513 |
|
2514 if( (aThread->iNThread.iCsCount>0) && (aThread->iNThread.iCsFunction>0) ) |
|
2515 { |
|
2516 return ETrue; |
|
2517 } |
|
2518 |
|
2519 if(aThread->iNThread.iSuspendCount > 0) |
|
2520 { |
|
2521 return ETrue; |
|
2522 } |
|
2523 return EFalse; |
|
2524 } |
|
2525 |
|
2526 /** |
|
2527 Read registers and store register values in aRegisterValues and the flags |
|
2528 indicating which registers could be read in aRegisterFlags |
|
2529 |
|
2530 @param aThread thread to read registers from |
|
2531 @param aRegisterIds array containing register IDs to read |
|
2532 @param aRegisterValues array to store register values in |
|
2533 @param aRegisterFlags array to store flags in |
|
2534 |
|
2535 @return KErrNone if registers were read successfully. Note that this does not |
|
2536 mean that all the registers could be read, the aRegisterFlags array |
|
2537 should be checked as to whether each individual register could be read, |
|
2538 KErrArgument if aThread is NULL, if an unknown register is specified in |
|
2539 aRegisterValues or if aRegisterValues is too small |
|
2540 KErrGeneral if there was a problem initialising the register set |
|
2541 */ |
|
2542 TInt DRM_DebugChannel::DoReadRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDes8 &aRegisterValues, TDes8& aRegisterFlags) const |
|
2543 { |
|
2544 LOG_MSG("DRM_DebugChannel::DoReadRegisters()"); |
|
2545 |
|
2546 // make sure the parameters are valid |
|
2547 if (!aThread) |
|
2548 return KErrArgument; |
|
2549 |
|
2550 //Need to revisit this to determine whether there is a way to validate this |
|
2551 #if 0 |
|
2552 if ( !CheckSuspended(aThread) ) |
|
2553 { |
|
2554 LOG_MSG2("DRM_DebugChannel::DoReadRegisters() thread with id 0x%08x is not suspended", aThread->iId); |
|
2555 return KErrInUse; |
|
2556 } |
|
2557 #endif |
|
2558 |
|
2559 //set lengths of output descriptors to 0 prior to filling |
|
2560 aRegisterValues.SetLength(0); |
|
2561 aRegisterFlags.SetLength(0); |
|
2562 |
|
2563 TArmRegSet regSet; |
|
2564 TUint32 flags; |
|
2565 |
|
2566 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, flags); |
|
2567 |
|
2568 LOG_MSG2( "DRM_DebugChannel::DoReadRegisters() : flags = 0x%X\n", flags ); |
|
2569 |
|
2570 TArmReg *regPtr = ®Set.iR0; |
|
2571 |
|
2572 if (!regPtr) |
|
2573 return KErrGeneral; |
|
2574 |
|
2575 TUint numberOfRegisters = aRegisterIds.Length() / sizeof(TRegisterInfo); |
|
2576 |
|
2577 //iterate through registers setting the relevant aFlags value |
|
2578 for(TUint i=0; i<numberOfRegisters; i++) |
|
2579 { |
|
2580 //get current register id |
|
2581 TRegisterInfo reg; |
|
2582 TInt err = GetTRegisterInfo(aRegisterIds, i, reg); |
|
2583 //exit with the error value if there was an error |
|
2584 if(err != KErrNone) |
|
2585 return err; |
|
2586 |
|
2587 //if unknown register then exit as can't know how many bytes this entry will |
|
2588 //represent in aRegisterValues |
|
2589 TTag registerTag; |
|
2590 TDebugFunctionality::GetRegister(reg, registerTag); |
|
2591 if(registerTag.iValue == EAccessUnknown) |
|
2592 { |
|
2593 return KErrArgument; |
|
2594 } |
|
2595 |
|
2596 //get the current register id as a kernel register |
|
2597 TArmReg armReg; |
|
2598 err = GetKernelRegisterId(reg, armReg); |
|
2599 if((err == KErrNotSupported) || (registerTag.iValue == EAccessNone) || (registerTag.iValue == EAccessWriteOnly)) |
|
2600 { |
|
2601 //reading this register is not supported |
|
2602 aRegisterFlags.Append(ENotSupported); |
|
2603 //just skip over this entry in the values buffer |
|
2604 if(aRegisterValues.Length() + registerTag.iSize > aRegisterValues.MaxLength()) |
|
2605 { |
|
2606 //writing this value would cause overflow so exit |
|
2607 return KErrArgument; |
|
2608 } |
|
2609 aRegisterValues.SetLength(aRegisterValues.Length() + registerTag.iSize); |
|
2610 } |
|
2611 else |
|
2612 { |
|
2613 if(registerTag.iSize == sizeof(TArmReg)) |
|
2614 { |
|
2615 if(GetFlagAtOffset(flags, armReg)) |
|
2616 { |
|
2617 //set flag as valid |
|
2618 aRegisterFlags.Append(EValid); |
|
2619 } |
|
2620 else |
|
2621 { |
|
2622 // Even though the flag is invalid, we can return the value of the register |
|
2623 // and let the user decide what to do |
|
2624 aRegisterFlags.Append(EInValid); |
|
2625 } |
|
2626 |
|
2627 if(aRegisterValues.Length() + sizeof(TArmReg) > aRegisterValues.MaxLength()) |
|
2628 { |
|
2629 //writing this value would cause overflow so exit |
|
2630 return KErrArgument; |
|
2631 } |
|
2632 //write value into register into regSet |
|
2633 aRegisterValues.Append((TUint8 *)®Ptr[armReg], registerTag.iSize); |
|
2634 } |
|
2635 else |
|
2636 { |
|
2637 //currently all kernel supported registers are 4 bytes so |
|
2638 //return EBadSize. Would need updating if/when other register |
|
2639 //value sizes are supported |
|
2640 aRegisterFlags.Append(EBadSize); |
|
2641 aRegisterValues.SetLength(aRegisterValues.Length() + registerTag.iSize); |
|
2642 } |
|
2643 } |
|
2644 } |
|
2645 return KErrNone; |
|
2646 } |
|
2647 |
|
2648 // |
|
2649 // DRM_DebugChannel::DoWriteRegisters |
|
2650 // |
|
2651 TInt DRM_DebugChannel::DoWriteRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDesC8 &aValues) |
|
2652 { |
|
2653 LOG_MSG("DRM_DebugChannel::DoWriteRegisters()"); |
|
2654 |
|
2655 // make sure the parameters are valid |
|
2656 if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) |
|
2657 return KErrArgument; |
|
2658 |
|
2659 // make sure the descriptor is big enough to hold the data to write |
|
2660 if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.Length())) |
|
2661 return KErrArgument; |
|
2662 |
|
2663 TArmRegSet regSet; |
|
2664 TUint32 unused; |
|
2665 |
|
2666 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); |
|
2667 |
|
2668 TArmReg *reg = ®Set.iR0; |
|
2669 |
|
2670 for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) |
|
2671 reg[i] = *(TUint32 *)&aValues[(i-aFirstRegister)*sizeof(TArmReg)]; |
|
2672 |
|
2673 NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); |
|
2674 |
|
2675 return KErrNone; |
|
2676 } |
|
2677 |
|
2678 /** |
|
2679 Write registers and store flags indicating which registers could be read in |
|
2680 aRegisterFlags |
|
2681 |
|
2682 @param aThread thread to write registers to |
|
2683 @param aRegisterIds array containing register IDs to write |
|
2684 @param aRegisterValues array containing register values to write |
|
2685 @param aRegisterFlags array to store flags in |
|
2686 |
|
2687 @return KErrNone if registers were written successfully. Note that this does not |
|
2688 mean that all the registers could be written, the aRegisterFlags array |
|
2689 should be checked as to whether each individual register could be read, |
|
2690 KErrArgument if aThread is NULL, if the buffer passed in as |
|
2691 aRegisterValue is too small, or if an unknown register is requested, |
|
2692 KErrGeneral if there was a problem initialising the register set |
|
2693 */ |
|
2694 TInt DRM_DebugChannel::DoWriteRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDesC8 &aRegisterValues, TDes8 &aRegisterFlags) const |
|
2695 { |
|
2696 LOG_MSG("DRM_DebugChannel::DoWriteRegisters()"); |
|
2697 |
|
2698 // make sure the parameters are valid |
|
2699 if (!aThread) |
|
2700 return KErrArgument; |
|
2701 |
|
2702 //check that the thread is suspended before reading the registers |
|
2703 if(!TheDProcessTracker.CheckSuspended(aThread)) |
|
2704 { |
|
2705 LOG_MSG2("DRM_DebugChannel::DoWriteRegisters() thread with id 0x%08x is not suspended", aThread->iId); |
|
2706 return KErrInUse; |
|
2707 } |
|
2708 |
|
2709 //get register values from kernel |
|
2710 TArmRegSet regSet; |
|
2711 TUint32 flags; |
|
2712 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, flags); |
|
2713 |
|
2714 //set lengths of output descriptors to 0 prior to filling |
|
2715 aRegisterFlags.SetLength(0); |
|
2716 |
|
2717 //pointer to first kernel register |
|
2718 TArmReg *regPtr = ®Set.iR0; |
|
2719 |
|
2720 if (!regPtr) |
|
2721 return KErrGeneral; |
|
2722 |
|
2723 //calculate number of registers |
|
2724 TUint numberOfRegisters = aRegisterIds.Length() / sizeof(TRegisterInfo); |
|
2725 |
|
2726 //iterate through registers setting the relevant aRegisterFlags value and |
|
2727 //setting the necessary value in regSet ready to write to kernel |
|
2728 for(TUint i=0, offset = 0; i<numberOfRegisters; i++) |
|
2729 { |
|
2730 //get current register id |
|
2731 TRegisterInfo reg; |
|
2732 TInt err = GetTRegisterInfo(aRegisterIds, i, reg); |
|
2733 //exit with the error value if there was an error |
|
2734 if(err != KErrNone) |
|
2735 { |
|
2736 return err; |
|
2737 } |
|
2738 |
|
2739 //if unknown register then exit as can't know how many bytes this entry will |
|
2740 //represent in aRegisterValues |
|
2741 TTag registerTag; |
|
2742 TDebugFunctionality::GetRegister(reg, registerTag); |
|
2743 if(registerTag.iValue == EAccessUnknown) |
|
2744 { |
|
2745 return KErrArgument; |
|
2746 } |
|
2747 |
|
2748 //get the current register id as a kernel register |
|
2749 TArmReg armReg; |
|
2750 err = GetKernelRegisterId(reg, armReg); |
|
2751 if((err == KErrNotSupported) || (registerTag.iValue == EAccessNone) || (registerTag.iValue == EAccessReadOnly)) |
|
2752 { |
|
2753 //writing to this register is not supported |
|
2754 aRegisterFlags.Append(ENotSupported); |
|
2755 } |
|
2756 else if(GetFlagAtOffset(flags, armReg)) |
|
2757 { |
|
2758 if(registerTag.iSize == sizeof(TArmReg)) |
|
2759 { |
|
2760 //set flag as valid |
|
2761 aRegisterFlags.Append(EValid); |
|
2762 if(offset + sizeof(TArmReg) > aRegisterValues.Length()) |
|
2763 { |
|
2764 //getting this value would cause overflow so exit |
|
2765 return KErrArgument; |
|
2766 } |
|
2767 //write value into register into regSet |
|
2768 regPtr[armReg] = *(TUint32 *)&aRegisterValues[offset]; |
|
2769 } |
|
2770 else |
|
2771 { |
|
2772 //currently all kernel supported registers are 4 bytes so |
|
2773 //return EBadSize. Would need updating if/when other register |
|
2774 //value sizes are supported |
|
2775 aRegisterFlags.Append(EBadSize); |
|
2776 } |
|
2777 |
|
2778 } |
|
2779 else |
|
2780 { |
|
2781 //set flag as invalid as register value couldn't be read |
|
2782 aRegisterFlags.Append(EInValid); |
|
2783 } |
|
2784 offset+=registerTag.iSize; |
|
2785 } |
|
2786 |
|
2787 //write the input data into the registers |
|
2788 NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); |
|
2789 |
|
2790 //return normally |
|
2791 return KErrNone; |
|
2792 } |
|
2793 |
|
2794 // |
|
2795 // DRM_DebugChannel::DoSecurityCheck |
|
2796 // |
|
2797 TBool DRM_DebugChannel::DoSecurityCheck() |
|
2798 { |
|
2799 LOG_MSG("DRM_DebugChannel::DoSecurityCheck"); |
|
2800 DProcess* clientProcess = iClientThread->iOwningProcess; |
|
2801 if (clientProcess) |
|
2802 { |
|
2803 SSecurityInfo secureInfo = clientProcess->iS; |
|
2804 |
|
2805 LOG_MSG2("DoSecurityCheck - client secure id is 0x%08x",secureInfo.iSecureId); |
|
2806 |
|
2807 // Ensure we really are communicating with the Debug Security Server |
|
2808 if (secureInfo.iSecureId == KUidDebugSecurityServer.iUid ) |
|
2809 { |
|
2810 return ETrue; |
|
2811 } |
|
2812 } |
|
2813 return EFalse; |
|
2814 } |
|
2815 |
|
2816 /** |
|
2817 Attempt to read memory from aThread's address space |
|
2818 |
|
2819 @param aThread thread from whose address space memory is to be read |
|
2820 @param aSrc pointer to memory location to read memory from |
|
2821 @param aDest pointer to memory location to write memory to |
|
2822 @param aLength number of bytes of data to read |
|
2823 |
|
2824 @return KErrNone if memory read successfully, |
|
2825 or another of the system wide error codes |
|
2826 */ |
|
2827 TInt DRM_DebugChannel::TryToReadMemory(const DThread *aThread, const TAny *aSrc, TAny *aDest, const TUint32 aLength) const |
|
2828 { |
|
2829 LOG_MSG("DRM_DebugChannel::TryToReadMemory()"); |
|
2830 |
|
2831 // make sure the parameters are valid |
|
2832 if (!aThread) |
|
2833 return KErrArgument; |
|
2834 |
|
2835 //Need to revisit this to determine whether there is a way to validate this |
|
2836 #if 0 |
|
2837 //check that the thread is suspended before reading the memory |
|
2838 if ( !CheckSuspended(aThread) ) |
|
2839 { |
|
2840 LOG_MSG2("DRM_DebugChannel::TryToReadMemory() thread with id 0x%08x is not suspended", aThread->iId); |
|
2841 return KErrInUse; |
|
2842 } |
|
2843 #endif |
|
2844 |
|
2845 LOG_MSG2("Using Kern::ThreadRawRead to read memory at address %x", aSrc); |
|
2846 return Kern::ThreadRawRead((DThread *)aThread, aSrc, aDest, aLength); |
|
2847 } |
|
2848 |
|
2849 /** |
|
2850 Attempt to write memory to aThread's address space |
|
2851 |
|
2852 @param aThread thread to whose address space memory is to be written |
|
2853 @param aDest pointer to memory location to write memory to |
|
2854 @param aSrc pointer to memory location to read memory from |
|
2855 @param aLength number of bytes of data to write |
|
2856 |
|
2857 @return KErrNone if memory written successfully, or another of the system wide |
|
2858 error codes |
|
2859 */ |
|
2860 TInt DRM_DebugChannel::TryToWriteMemory(const DThread *aThread, TAny *aDest, const TAny *aSrc, const TUint32 aLength) |
|
2861 { |
|
2862 LOG_MSG("DRM_DebugChannel::TryToWriteMemory()"); |
|
2863 |
|
2864 //check that the thread is suspended before writing the memory |
|
2865 if(!TheDProcessTracker.CheckSuspended((DThread*)aThread)) |
|
2866 { |
|
2867 LOG_MSG2("DRM_DebugChannel::TryToWriteMemory() thread with id 0x%08x is not suspended", aThread->iId); |
|
2868 return KErrInUse; |
|
2869 } |
|
2870 |
|
2871 LOG_MSG2("Using Kern::ThreadRawWrite to write memory at address %x", (TUint32)aDest); |
|
2872 return Kern::ThreadRawWrite((DThread *)aThread, aDest, aSrc, aLength, iClientThread); |
|
2873 } |
|
2874 |
|
2875 /** |
|
2876 @deprecated use DRM_DebugChannel::ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) instead |
|
2877 */ |
|
2878 TInt32 DRM_DebugChannel::ReadRegister(DThread *aThread, TInt aNum) |
|
2879 { |
|
2880 LOG_MSG("DRM_DebugChannel::ReadRegister()"); |
|
2881 |
|
2882 if (!aThread || (aNum < 0) || (aNum >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) |
|
2883 { |
|
2884 LOG_MSG2("Invalid register number (%d) passed to ReadRegister", aNum); |
|
2885 return 0; |
|
2886 } |
|
2887 |
|
2888 TArmRegSet regSet; |
|
2889 TUint32 unused; |
|
2890 |
|
2891 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); |
|
2892 |
|
2893 TArmReg *reg = ®Set.iR0; |
|
2894 |
|
2895 return ((TUint32 *)reg)[aNum]; |
|
2896 } |
|
2897 |
|
2898 /** |
|
2899 Given a TArmReg register ID, read the value of the register. The register value |
|
2900 will be stored in aValue if the register could be read. |
|
2901 |
|
2902 @param aThread thread to read register from |
|
2903 @param aKernelRegisterId ID of register to read from |
|
2904 @param aValue value read from register |
|
2905 |
|
2906 @return KErrNone if value was successfully stored in aValue, |
|
2907 KErrNotSupported if aKernelRegister is not supported by the debug |
|
2908 security server, |
|
2909 or a return value from DRM_DebugChannel::ReadDebugRegisterValue() |
|
2910 */ |
|
2911 TInt32 DRM_DebugChannel::ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) const |
|
2912 { |
|
2913 //get register ID as a TRegisterInfo ID |
|
2914 TRegisterInfo regId; |
|
2915 TInt err = GetDebugRegisterId(aKernelRegisterId, regId); |
|
2916 if(err != KErrNone) |
|
2917 return err; |
|
2918 |
|
2919 //get the value for the register |
|
2920 err = ReadDebugRegisterValue(aThread, regId, aValue); |
|
2921 return err; |
|
2922 } |
|
2923 |
|
2924 /** |
|
2925 Given a TRegisterInfo register ID, read the value of this register. The |
|
2926 register value will be stored in aValue if the register could be read. |
|
2927 |
|
2928 @param aThread thread to read register from |
|
2929 @param aDebugRegisterId ID of register to read from |
|
2930 @param aValue value read from register |
|
2931 |
|
2932 @return KErrNone if value was successfully stored in aValue, |
|
2933 TRegisterFlag::EInValid if value could not be read from the register, |
|
2934 TRegisterFlag::ENotSupported if the register is not supported, |
|
2935 KErrNoMemory if temporary memory could not be allocated, |
|
2936 or a return value from DRM_DebugChannel::DoReadRegisters |
|
2937 */ |
|
2938 TInt32 DRM_DebugChannel::ReadDebugRegisterValue(DThread *aThread, const TRegisterInfo aDebugRegisterId, T4ByteRegisterValue &aValue) const |
|
2939 { |
|
2940 //allocate temporary buffers to store data |
|
2941 NKern::ThreadEnterCS(); |
|
2942 TUint8* id = (TUint8*)Kern::Alloc(sizeof(TRegisterInfo)); |
|
2943 NKern::ThreadLeaveCS(); |
|
2944 if(id == NULL) |
|
2945 { |
|
2946 return KErrNoMemory; |
|
2947 } |
|
2948 |
|
2949 TPtr8 idPtr(id, sizeof(TRegisterInfo)); |
|
2950 |
|
2951 NKern::ThreadEnterCS(); |
|
2952 TUint8* value = (TUint8*)Kern::Alloc(sizeof(T4ByteRegisterValue)); |
|
2953 NKern::ThreadLeaveCS(); |
|
2954 if(value == NULL) |
|
2955 { |
|
2956 return KErrNoMemory; |
|
2957 } |
|
2958 TPtr8 valuePtr(value, sizeof(T4ByteRegisterValue)); |
|
2959 |
|
2960 NKern::ThreadEnterCS(); |
|
2961 TUint8* flag = (TUint8*)Kern::Alloc(sizeof(TUint8)); |
|
2962 NKern::ThreadLeaveCS(); |
|
2963 if(flag == NULL) |
|
2964 { |
|
2965 return KErrNoMemory; |
|
2966 } |
|
2967 TPtr8 flagPtr(flag, sizeof(TUint8)); |
|
2968 |
|
2969 //store register id in buffer |
|
2970 idPtr.Append((TUint8*)&aDebugRegisterId, sizeof(TRegisterInfo)); |
|
2971 |
|
2972 //read registers |
|
2973 TInt err = DoReadRegisters(aThread, idPtr, valuePtr, flagPtr); |
|
2974 if(err == KErrNone) |
|
2975 { |
|
2976 if(*flag == EValid) |
|
2977 { |
|
2978 //register could be read so store value |
|
2979 aValue = *(T4ByteRegisterValue*)value; |
|
2980 } |
|
2981 else |
|
2982 { |
|
2983 //register couldn't be read for some reason |
|
2984 err = *flag; |
|
2985 } |
|
2986 } |
|
2987 |
|
2988 //free memory |
|
2989 NKern::ThreadEnterCS(); |
|
2990 Kern::Free(id); |
|
2991 Kern::Free(value); |
|
2992 Kern::Free(flag); |
|
2993 NKern::ThreadLeaveCS(); |
|
2994 |
|
2995 return err; |
|
2996 } |
|
2997 |
|
2998 // |
|
2999 // DRM_DebugChannel::NotifyEvent |
|
3000 // |
|
3001 void DRM_DebugChannel::NotifyEvent(const TDriverEventInfo& aEventInfo) |
|
3002 { |
|
3003 LOG_EVENT_MSG("DRM_DebugChannel::NotifyEvent()"); |
|
3004 |
|
3005 // Look for the relevant DTargetProcess |
|
3006 // We can find out the relevant process id from aEventInfo |
|
3007 TUint32 pid = aEventInfo.iProcessId; |
|
3008 |
|
3009 //opening handle to process |
|
3010 DProcess* targetProcess = DebugUtils::OpenProcessHandle(pid); |
|
3011 |
|
3012 if(!targetProcess) |
|
3013 { |
|
3014 LOG_EVENT_MSG("DRM_DebugChannel::NotifyEvent - process does not exist!"); |
|
3015 return; |
|
3016 } |
|
3017 |
|
3018 // Are we debugging this process - decide based on iFileName |
|
3019 DCodeSeg* p = targetProcess->iCodeSeg; |
|
3020 DTargetProcess* foundProcess; |
|
3021 if (p) |
|
3022 { |
|
3023 foundProcess = TheDProcessTracker.FindProcess(*(p->iFileName)); |
|
3024 } |
|
3025 else |
|
3026 { |
|
3027 // special case: may not have a code seg in some cases. in which case we tell everyone! |
|
3028 if (targetProcess->iName) |
|
3029 { |
|
3030 // copy the name of the process |
|
3031 foundProcess = TheDProcessTracker.FindProcess(*(targetProcess->iName)); |
|
3032 } |
|
3033 else |
|
3034 { |
|
3035 foundProcess = NULL; |
|
3036 } |
|
3037 } |
|
3038 |
|
3039 //close the handle |
|
3040 targetProcess->Close(NULL); |
|
3041 |
|
3042 if (!foundProcess) |
|
3043 { |
|
3044 // No: just ignore this exception |
|
3045 LOG_EVENT_MSG("DRM_DebugChannel::NotifyEvent - we are not debugging this process!"); |
|
3046 return; |
|
3047 } |
|
3048 |
|
3049 foundProcess->NotifyEvent(aEventInfo); |
|
3050 } |
|
3051 |
|
3052 #ifndef __LAUNCH_AS_EXTENSION__ |
|
3053 DECLARE_STANDARD_LDD() |
|
3054 { |
|
3055 return new DRM_DebugDriverFactory; |
|
3056 } |
|
3057 #else |
|
3058 |
|
3059 DStopModeExtension* TheStopModeExtension = NULL; |
|
3060 |
|
3061 DECLARE_EXTENSION_LDD() |
|
3062 { |
|
3063 return new DRM_DebugDriverFactory; |
|
3064 } |
|
3065 |
|
3066 /** |
|
3067 This value is used as an initialiser for the size of the Stop-Mode Debug API's |
|
3068 default request buffer. |
|
3069 */ |
|
3070 const TInt KRequestBufferSize = 0x200; |
|
3071 /** |
|
3072 This value is used as an initialiser for the size of the Stop-Mode Debug API's |
|
3073 default response buffer. |
|
3074 */ |
|
3075 const TInt KResponseBufferSize = 0x1000; |
|
3076 |
|
3077 DECLARE_STANDARD_EXTENSION() |
|
3078 { |
|
3079 __KTRACE_OPT(KBOOT,Kern::Printf("Starting RM_DEBUG extension")); |
|
3080 |
|
3081 // get a reference to the DDebuggerInfo and to the DStopModeExtension |
|
3082 TSuperPage& superPage = Kern::SuperPage(); |
|
3083 |
|
3084 if(!superPage.iDebuggerInfo) |
|
3085 { |
|
3086 //kdebug has not been installed so create DDebuggerInfo using our stub constructor |
|
3087 superPage.iDebuggerInfo = new DDebuggerInfo(); |
|
3088 } |
|
3089 |
|
3090 if(!TheStopModeExtension) |
|
3091 { |
|
3092 TheStopModeExtension = new DStopModeExtension(); |
|
3093 } |
|
3094 |
|
3095 // create the request buffer and store a reference to it |
|
3096 TTag tag; |
|
3097 tag.iTagId = EBuffersRequest; |
|
3098 tag.iType = ETagTypePointer; |
|
3099 tag.iSize = KRequestBufferSize; |
|
3100 TInt err = TheDBufferManager.CreateBuffer(tag); |
|
3101 if(KErrNone != err) |
|
3102 { |
|
3103 return KErrNone; |
|
3104 } |
|
3105 |
|
3106 // create the response buffer and store a reference to it |
|
3107 tag.iTagId = EBuffersResponse; |
|
3108 tag.iSize = KResponseBufferSize; |
|
3109 err = TheDBufferManager.CreateBuffer(tag); |
|
3110 if(KErrNone != err) |
|
3111 { |
|
3112 return KErrNone; |
|
3113 } |
|
3114 // create the debug functionality buffer and store a reference to it |
|
3115 TDebugFunctionality df; |
|
3116 TUint dfSize = df.GetStopModeFunctionalityBufSize(); |
|
3117 tag.iTagId = EBuffersFunctionality; |
|
3118 tag.iSize = dfSize; |
|
3119 err = TheDBufferManager.CreateBuffer(tag); |
|
3120 if(KErrNone != err) |
|
3121 { |
|
3122 return KErrNone; |
|
3123 } |
|
3124 |
|
3125 // fill the functionality buffer with the functionality data and store it in |
|
3126 // the super page |
|
3127 TPtr8 dfBlockPtr((TUint8*)tag.iValue, dfSize); |
|
3128 if(!df.GetStopModeFunctionality(dfBlockPtr)) |
|
3129 { |
|
3130 return KErrNone; |
|
3131 } |
|
3132 TheStopModeExtension->iFunctionalityBlock = (DFunctionalityBlock*)tag.iValue; |
|
3133 |
|
3134 DStopModeExtension::Install(TheStopModeExtension); |
|
3135 |
|
3136 return KErrNone; |
|
3137 } |
|
3138 |
|
3139 /** |
|
3140 * This stub constructor is intended to be used in the case where the old deprecated |
|
3141 * stop mode api, kdebug, is not in place. It will initialise all values to NULL except |
|
3142 * the pointer to the new stop mode api extension. This allows the new stop mode solution |
|
3143 * to both co-exist and exist independantly of the existing one * |
|
3144 */ |
|
3145 DDebuggerInfo::DDebuggerInfo(): |
|
3146 iObjectOffsetTable(NULL), |
|
3147 iObjectOffsetTableCount(NULL), |
|
3148 iThreadContextTable(NULL), |
|
3149 iStopModeExtension(new DStopModeExtension()), |
|
3150 iContainers(NULL), |
|
3151 iCodeSegLock(NULL), |
|
3152 iCodeSegGlobalList(NULL), |
|
3153 iScheduler(NULL), |
|
3154 iShadowPages(NULL), |
|
3155 iShadowPageCount(0), |
|
3156 iCurrentThread(NULL), |
|
3157 iEventMask(), |
|
3158 iEventHandlerBreakpoint(0), |
|
3159 iMemModelObjectOffsetTable(NULL), |
|
3160 iMemModelObjectOffsetTableCount(0) |
|
3161 { |
|
3162 } |
|
3163 |
|
3164 /** |
|
3165 * Installs the stop-mode debugger extension |
|
3166 * Make the stop-mode API visible to a JTAG debugger, by publishing its |
|
3167 * existence in the superpage |
|
3168 */ |
|
3169 void DStopModeExtension::Install(DStopModeExtension* aExt) |
|
3170 { |
|
3171 Kern::SuperPage().iDebuggerInfo->iStopModeExtension = aExt; |
|
3172 } |
|
3173 |
|
3174 #endif |
|
3175 |
|
3176 /** |
|
3177 Helper function |
|
3178 |
|
3179 Allocates memory in current thread with a max length the same as aSrcDes. If |
|
3180 aReadFromClient is true (as it is by default) then the data from aSrdDes is |
|
3181 copied into the allocated aDestDes buffer. |
|
3182 |
|
3183 Use of this function should be followed at a later time by a call such as |
|
3184 Kern::Free(aDestDes.Ptr()) |
|
3185 |
|
3186 @param aThread pointer to thread to read data from |
|
3187 @param aSrcDes descriptor in aThread to read data from |
|
3188 @param aDestDes location to read data to. Memory is allocated at this location, |
|
3189 if memory is already allocated at this location then the function will |
|
3190 return KErrArgument |
|
3191 @param aReadFromClient if false then data is not actually read from the |
|
3192 client, the memory is simply allocated |
|
3193 @param aOffest offset into aSrcDes to start reading from. Default is 0. |
|
3194 |
|
3195 @return KErrNone if there were no problems, |
|
3196 KErrArgument if aDestDes.Ptr() != NULL or aSrcDes has max length 0, |
|
3197 KErrNoMemory if could not allocate memory, |
|
3198 or one of the other system wide error codes |
|
3199 */ |
|
3200 TInt DRM_DebugChannel::AllocAndReadDes(DThread *aThread, const TDesC8& aSrcDes, TPtr8& aDestDes, const TBool aReadFromClient, const TUint aOffset) const |
|
3201 { |
|
3202 |
|
3203 //check thread is not null |
|
3204 if(!aThread) |
|
3205 { |
|
3206 return KErrArgument; |
|
3207 } |
|
3208 |
|
3209 //check aDestDes is empty |
|
3210 if(aDestDes.Ptr() != NULL) |
|
3211 { |
|
3212 return KErrArgument; |
|
3213 } |
|
3214 |
|
3215 //get the source descriptor's max length and exit if 0 |
|
3216 TUint srcMaxLength = Kern::ThreadGetDesMaxLength(aThread, &aSrcDes); |
|
3217 if(srcMaxLength == 0) |
|
3218 { |
|
3219 return KErrNone; |
|
3220 } |
|
3221 |
|
3222 //allocate memory and return if none available |
|
3223 NKern::ThreadEnterCS(); |
|
3224 TUint8 *destPtr = (TUint8*)Kern::Alloc(srcMaxLength); |
|
3225 NKern::ThreadLeaveCS(); |
|
3226 if (!destPtr) |
|
3227 { |
|
3228 return KErrNoMemory; |
|
3229 } |
|
3230 |
|
3231 //point the TPtr8 at the target memory |
|
3232 aDestDes.Set(destPtr, srcMaxLength, srcMaxLength); |
|
3233 |
|
3234 if(aReadFromClient) |
|
3235 { |
|
3236 //read data from the client thread and return status code |
|
3237 return Kern::ThreadDesRead(aThread, &aSrcDes, aDestDes, aOffset); |
|
3238 } |
|
3239 else |
|
3240 { |
|
3241 return KErrNone; |
|
3242 } |
|
3243 } |
|
3244 |
|
3245 /** |
|
3246 Helper function to extract a TRegisterInfo value from a descriptor containing |
|
3247 binary data. |
|
3248 |
|
3249 @param aRegisterIds descriptor containing register IDs |
|
3250 @param aOffset offset in bytes into the descriptor to start reading data from. |
|
3251 If this value is not a multiple of sizeof(TRegisterInfo) then a |
|
3252 KErrArgument error is returned. |
|
3253 @param aValue will contain the returned value |
|
3254 |
|
3255 @return KErrNone if aValue was set correctly, KErrArgument if bad arguments |
|
3256 were passed in |
|
3257 */ |
|
3258 TInt DRM_DebugChannel::GetTRegisterInfo(const TDesC8 &aRegisterIds, const TUint aIndex, TRegisterInfo &aValue) const |
|
3259 { |
|
3260 TUint length = aRegisterIds.Length(); |
|
3261 |
|
3262 TUint size = sizeof(TRegisterInfo); |
|
3263 |
|
3264 //check that not trying to read past end of descriptor |
|
3265 if((aIndex + 1) * size > length) |
|
3266 return KErrArgument; |
|
3267 |
|
3268 //get pointer to descriptor's data |
|
3269 const TUint8 *dataPtr = aRegisterIds.Ptr(); |
|
3270 const TRegisterInfo *registerId = reinterpret_cast<const TRegisterInfo*>(dataPtr + (aIndex * size)); |
|
3271 |
|
3272 aValue = *registerId; |
|
3273 |
|
3274 return KErrNone; |
|
3275 } |
|
3276 |
|
3277 /** |
|
3278 Helper function to get the kernel register ID of the TRegisterInfo defined register. |
|
3279 |
|
3280 @param aDebugRegister the debug register ID to return the kernel ID for |
|
3281 @param aKernelRegister corresponding value of register aDebugRegister |
|
3282 |
|
3283 @return KErrNone if translation occurred without problems |
|
3284 KErrNotSupported if aDebugRegister is not supported by the kernel |
|
3285 */ |
|
3286 TInt DRM_DebugChannel::GetKernelRegisterId(const TRegisterInfo aDebugRegister, TArmReg& aKernelRegister) const |
|
3287 { |
|
3288 if(Register::IsCoreReg(aDebugRegister)) |
|
3289 { |
|
3290 TUint id = Register::GetCoreRegId(aDebugRegister); |
|
3291 //first 17 registers match the first 17 kernel registers |
|
3292 if(id < 17) |
|
3293 { |
|
3294 aKernelRegister = id; |
|
3295 } |
|
3296 else |
|
3297 { |
|
3298 return KErrNotSupported; |
|
3299 } |
|
3300 } |
|
3301 else if(Register::IsCoproReg(aDebugRegister)) |
|
3302 { |
|
3303 TUint32 crn = Register::GetCRn(aDebugRegister); |
|
3304 TUint32 crm = Register::GetCRm(aDebugRegister); |
|
3305 TUint32 opcode1 = Register::GetOpcode1(aDebugRegister); |
|
3306 TUint32 opcode2 = Register::GetOpcode2(aDebugRegister); |
|
3307 TUint32 coproNum = Register::GetCoproNum(aDebugRegister); |
|
3308 |
|
3309 //each coprocessor register has potentially different characteristics |
|
3310 //so need to identify each individually |
|
3311 |
|
3312 //this is the DACR, the ARM ARM specifies that the CRn and the |
|
3313 //Opcodes are not relevant, section B3-24, point 3.7.3 |
|
3314 if((coproNum == 15) && (crm == 3)) |
|
3315 { |
|
3316 aKernelRegister = EArmDacr; |
|
3317 } |
|
3318 else |
|
3319 { |
|
3320 return KErrNotSupported; |
|
3321 } |
|
3322 } |
|
3323 else // might be supported at a later date |
|
3324 { |
|
3325 return KErrNotSupported; |
|
3326 } |
|
3327 |
|
3328 return KErrNone; |
|
3329 } |
|
3330 |
|
3331 /** |
|
3332 Helper function to get the debug register ID of the kernel defined register. |
|
3333 |
|
3334 @param aKernelRegister the kernel register ID to return the debug ID for |
|
3335 @param aDebugRegister corresponding value of register aKernelRegister |
|
3336 |
|
3337 @return KErrNone if translation occured without problems |
|
3338 KErrNotSupported if aKernelRegister is not supported by the debug |
|
3339 security server |
|
3340 */ |
|
3341 TInt DRM_DebugChannel::GetDebugRegisterId(const TArmReg aKernelRegister, TRegisterInfo &aDebugRegister) const |
|
3342 { |
|
3343 |
|
3344 // registers 0 - 15 and the CPSR share the same values as with the debug enums |
|
3345 if(aKernelRegister < 17) |
|
3346 { |
|
3347 TUint32 id = aKernelRegister; |
|
3348 aDebugRegister = id << 8; |
|
3349 } |
|
3350 //the DACR value is special and corresponds to EDF_Register_DACR |
|
3351 else if(aKernelRegister == EArmDacr) |
|
3352 { |
|
3353 aDebugRegister = 0x00300f01; |
|
3354 } |
|
3355 // must be an unsupported register, return an error as such |
|
3356 else |
|
3357 { |
|
3358 return KErrNotSupported; |
|
3359 } |
|
3360 |
|
3361 //found a supported register so return KErrNone |
|
3362 return KErrNone; |
|
3363 } |
|
3364 |
|
3365 /** |
|
3366 Helper function to find out whether the aIndex flag is set. This is equivalent |
|
3367 to the aIndex bit of aFlags being non-zero. |
|
3368 |
|
3369 @param aFlags set of flags |
|
3370 @param aIndex offset into aFlags to get flag from |
|
3371 |
|
3372 @return ETrue if bit is set, EFalse if not |
|
3373 */ |
|
3374 TBool DRM_DebugChannel::GetFlagAtOffset(const TUint32 aFlags, const TArmReg aIndex) const |
|
3375 { |
|
3376 return aFlags & (1<<aIndex); |
|
3377 } |
|
3378 |
|
3379 /* Register the attachment of a debug agent to a process to be debugged |
|
3380 * |
|
3381 * @param a1 - TDes8 target process name |
|
3382 * @param a2 - &TUint64 - Debug Agent Id |
|
3383 * |
|
3384 * @return - KErrNone if successful. KErrArgument if the filepath is not a valid size. |
|
3385 * KErrOutOfMemory if there is insufficient memory. Or one of the other system wide error codes |
|
3386 * if appropriate. |
|
3387 */ |
|
3388 TInt DRM_DebugChannel::AttachProcess(TAny* a1, TAny* a2) |
|
3389 { |
|
3390 LOG_MSG("DRM_DebugChannel::AttachProcess()"); |
|
3391 |
|
3392 // Validate the supplied TDes8 target process name in a1 |
|
3393 TInt length, maxLength; |
|
3394 TUint8* aPtr; |
|
3395 |
|
3396 TInt err = Kern::ThreadGetDesInfo(iClientThread,\ |
|
3397 a1,\ |
|
3398 length,\ |
|
3399 maxLength,\ |
|
3400 aPtr,\ |
|
3401 EFalse); |
|
3402 if (err != KErrNone) |
|
3403 { |
|
3404 // Could not read the descriptor information |
|
3405 return err; |
|
3406 } |
|
3407 |
|
3408 // Check the processname is a valid size for a filepath |
|
3409 if (length < 1 || length >= KMaxPath) |
|
3410 { |
|
3411 return KErrArgument; |
|
3412 } |
|
3413 |
|
3414 if (maxLength < 1 || maxLength >= KMaxPath) |
|
3415 { |
|
3416 return KErrArgument; |
|
3417 } |
|
3418 |
|
3419 // Allocate space to store the target process name in a kernel-side TPtr8 |
|
3420 NKern::ThreadEnterCS(); |
|
3421 TUint8* buffer = (TUint8*)Kern::AllocZ(length); |
|
3422 NKern::ThreadLeaveCS(); |
|
3423 if (buffer==NULL) |
|
3424 { |
|
3425 // Out of memory |
|
3426 return KErrNoMemory; |
|
3427 } |
|
3428 |
|
3429 // A temporary descriptor to store the target process name |
|
3430 TPtr8 targetProcessName(buffer,length,length); |
|
3431 |
|
3432 // Read the user-side data into targetProcessName |
|
3433 err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); |
|
3434 if (err != KErrNone) |
|
3435 { |
|
3436 // Could not read the user-side descriptor containing the target process name |
|
3437 NKern::ThreadEnterCS(); |
|
3438 Kern::Free(buffer); |
|
3439 NKern::ThreadLeaveCS(); |
|
3440 |
|
3441 return err; |
|
3442 } |
|
3443 |
|
3444 // Obtain the Debug Agent Id |
|
3445 TUint64 debugAgentId = 0; |
|
3446 |
|
3447 err = Kern::ThreadRawRead(iClientThread,a2,&debugAgentId,sizeof(debugAgentId)); |
|
3448 if (err != KErrNone) |
|
3449 { |
|
3450 // Something bad happened so free the memory and return |
|
3451 NKern::ThreadEnterCS(); |
|
3452 Kern::Free(buffer); |
|
3453 NKern::ThreadLeaveCS(); |
|
3454 return err; |
|
3455 } |
|
3456 |
|
3457 // Add the target process to our list of tracked processes |
|
3458 err = TheDProcessTracker.AttachProcess(targetProcessName, debugAgentId); |
|
3459 |
|
3460 // Free the kernel-side memory containing targetProcessName data |
|
3461 NKern::ThreadEnterCS(); |
|
3462 Kern::Free(buffer); |
|
3463 NKern::ThreadLeaveCS(); |
|
3464 |
|
3465 return err; |
|
3466 } |
|
3467 |
|
3468 /* Register the detachment of a debug agent to a process to be debugged. |
|
3469 * |
|
3470 * @param - a1 TDes8 target process name in a1 |
|
3471 * @param a2 - &TUint64 - Debug Agent Id |
|
3472 * |
|
3473 * @return - KErrNone if successful. KErrArgument if the filepath is not a valid size. |
|
3474 * KErrOutOfMemory if there is insufficient memory. Or one of the other system wide error codes |
|
3475 * if appropriate. |
|
3476 */ |
|
3477 TInt DRM_DebugChannel::DetachProcess(TAny* a1, TAny* a2) |
|
3478 { |
|
3479 // Validate the supplied TDes8 target process name in a1 |
|
3480 TInt length, maxLength; |
|
3481 TUint8* aPtr; |
|
3482 |
|
3483 TInt err = Kern::ThreadGetDesInfo(iClientThread,\ |
|
3484 a1,\ |
|
3485 length,\ |
|
3486 maxLength,\ |
|
3487 aPtr,\ |
|
3488 EFalse); |
|
3489 if (err != KErrNone) |
|
3490 { |
|
3491 return err; |
|
3492 } |
|
3493 |
|
3494 if (length < 1 || length >= KMaxPath) |
|
3495 { |
|
3496 return KErrArgument; |
|
3497 } |
|
3498 |
|
3499 if (maxLength < 1 || maxLength >= KMaxPath) |
|
3500 { |
|
3501 return KErrArgument; |
|
3502 } |
|
3503 |
|
3504 // Allocate space to store the target process name in a kernel-side TPtr8 |
|
3505 NKern::ThreadEnterCS(); |
|
3506 TUint8* buffer = (TUint8*)Kern::AllocZ(length); |
|
3507 NKern::ThreadLeaveCS(); |
|
3508 if (buffer==NULL) |
|
3509 { |
|
3510 // Out of memory |
|
3511 return KErrNoMemory; |
|
3512 } |
|
3513 |
|
3514 TPtr8 targetProcessName(buffer,length,length); |
|
3515 |
|
3516 // Read the user-side data into targetProcessName |
|
3517 err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); |
|
3518 if (err != KErrNone) |
|
3519 { |
|
3520 // Something bad happened so free the memory and return |
|
3521 NKern::ThreadEnterCS(); |
|
3522 Kern::Free(buffer); |
|
3523 NKern::ThreadLeaveCS(); |
|
3524 |
|
3525 return err; |
|
3526 } |
|
3527 |
|
3528 // Obtain the AgentId |
|
3529 TUint64 debugAgentId = 0; |
|
3530 |
|
3531 err = Kern::ThreadRawRead(iClientThread,a2,&debugAgentId,sizeof(debugAgentId)); |
|
3532 if (err != KErrNone) |
|
3533 { |
|
3534 // Something bad happened so free the memory and return |
|
3535 NKern::ThreadEnterCS(); |
|
3536 Kern::Free(buffer); |
|
3537 NKern::ThreadLeaveCS(); |
|
3538 |
|
3539 return err; |
|
3540 } |
|
3541 |
|
3542 // Remove the process from our list of tracked processes |
|
3543 err = TheDProcessTracker.DetachProcess(targetProcessName, debugAgentId); |
|
3544 |
|
3545 // Free the kernel-side memory containing targetProcessName data |
|
3546 NKern::ThreadEnterCS(); |
|
3547 Kern::Free(buffer); |
|
3548 NKern::ThreadLeaveCS(); |
|
3549 |
|
3550 return err; |
|
3551 } |
|
3552 |
|
3553 /* Register the detachment of a debug agent from all processes being debugged. |
|
3554 * |
|
3555 * @param - a1 - &TUint64 Debug Agent Id. |
|
3556 * @return - KErrNone if successful. One of the system-wide error codes otherwise. |
|
3557 */ |
|
3558 TInt DRM_DebugChannel::DetachAgent(TAny* a1, TAny* a2) |
|
3559 { |
|
3560 // Obtain the AgentId |
|
3561 TUint64 debugAgentId = 0; |
|
3562 |
|
3563 TInt err = Kern::ThreadRawRead(iClientThread,a1,&debugAgentId,sizeof(debugAgentId)); |
|
3564 if (err != KErrNone) |
|
3565 { |
|
3566 return err; |
|
3567 } |
|
3568 |
|
3569 // Remove the process from our list of tracked processes |
|
3570 return TheDProcessTracker.DetachAgent(debugAgentId); |
|
3571 } |
|
3572 |
|
3573 /* Set the action associated with a particular kernel event for a given agent and target process |
|
3574 * |
|
3575 * @param - a1 TDes8 target process name in a1 |
|
3576 * @param - a2 &TRM_DebugEventActionInfo |
|
3577 * @return - KErrNone if successful. KErrArgument if the filepath is an invalid size. Or one of |
|
3578 * the other system wide error codes if appropriate. |
|
3579 */ |
|
3580 TInt DRM_DebugChannel::SetEventAction(TAny* a1, TAny* a2) |
|
3581 { |
|
3582 // Validate the supplied TDes8 target process name in a1 |
|
3583 TInt length, maxLength; |
|
3584 TUint8* aPtr; |
|
3585 |
|
3586 TInt err = Kern::ThreadGetDesInfo(iClientThread,\ |
|
3587 a1,\ |
|
3588 length,\ |
|
3589 maxLength,\ |
|
3590 aPtr,\ |
|
3591 EFalse); |
|
3592 if (err != KErrNone) |
|
3593 { |
|
3594 return err; |
|
3595 } |
|
3596 |
|
3597 if (length < 1 || length >= KMaxPath) |
|
3598 { |
|
3599 return KErrArgument; |
|
3600 } |
|
3601 |
|
3602 if (maxLength < 1 || maxLength >= KMaxPath) |
|
3603 { |
|
3604 return KErrArgument; |
|
3605 } |
|
3606 |
|
3607 // Allocate space to store the target process name in a kernelspace TPtr8 |
|
3608 NKern::ThreadEnterCS(); |
|
3609 TUint8* buffer = (TUint8*)Kern::AllocZ(length); |
|
3610 NKern::ThreadLeaveCS(); |
|
3611 if (buffer==NULL) |
|
3612 { |
|
3613 // Out of memory |
|
3614 return KErrNoMemory; |
|
3615 } |
|
3616 TPtr8 targetProcessName(buffer,length,length); |
|
3617 |
|
3618 // Read the user-side data into targetProcessName |
|
3619 err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); |
|
3620 if (err != KErrNone) |
|
3621 { |
|
3622 // Something bad happened so free the memory and return |
|
3623 NKern::ThreadEnterCS(); |
|
3624 Kern::Free(buffer); |
|
3625 NKern::ThreadLeaveCS(); |
|
3626 |
|
3627 return err; |
|
3628 } |
|
3629 |
|
3630 // Read the Event and Action from the user-side |
|
3631 TRM_DebugEventActionInfo info(0,0,0); |
|
3632 |
|
3633 err = Kern::ThreadRawRead(iClientThread, a2, &info, sizeof(info)); |
|
3634 if (err != KErrNone) |
|
3635 { |
|
3636 // Could not read event action data from the user-side |
|
3637 |
|
3638 // Free memory used for targetProcessName |
|
3639 NKern::ThreadEnterCS(); |
|
3640 Kern::Free(buffer); |
|
3641 NKern::ThreadLeaveCS(); |
|
3642 |
|
3643 return err; |
|
3644 } |
|
3645 |
|
3646 // Find the target process |
|
3647 DTargetProcess* pProcess = TheDProcessTracker.FindProcess(targetProcessName); |
|
3648 if (pProcess == NULL) |
|
3649 { |
|
3650 // Could not find this process |
|
3651 |
|
3652 // Free memory used for targetProcessName |
|
3653 NKern::ThreadEnterCS(); |
|
3654 Kern::Free(buffer); |
|
3655 NKern::ThreadLeaveCS(); |
|
3656 |
|
3657 return KErrArgument; |
|
3658 } |
|
3659 |
|
3660 TUint64 debugAgentId = info.iAgentId; |
|
3661 |
|
3662 // Find the agent |
|
3663 DDebugAgent* debugAgent = pProcess->Agent(debugAgentId); |
|
3664 if (debugAgent == NULL) |
|
3665 { |
|
3666 // Bad agent means there is no tracking agent |
|
3667 LOG_MSG2("Cannot locate debug agent with pid 0x%0x16lx",info.iAgentId); |
|
3668 |
|
3669 // Free memory used for targetProcessName |
|
3670 NKern::ThreadEnterCS(); |
|
3671 Kern::Free(buffer); |
|
3672 NKern::ThreadLeaveCS(); |
|
3673 |
|
3674 return KErrGeneral; |
|
3675 } |
|
3676 |
|
3677 // Set the event action |
|
3678 debugAgent->SetEventAction((TEventType)info.iEvent,(TKernelEventAction)info.iAction); |
|
3679 |
|
3680 // Free memory used for targetProcessName |
|
3681 NKern::ThreadEnterCS(); |
|
3682 Kern::Free(buffer); |
|
3683 NKern::ThreadLeaveCS(); |
|
3684 |
|
3685 return KErrNone; |
|
3686 } |
|
3687 |
|
3688 TInt DRM_DebugChannel::Step(const TUint32 aThreadId, const TUint32 aNumSteps) |
|
3689 { |
|
3690 LOG_MSG3("DRM_DebugChannel::Step(aThreadId = 0x%08x, aNumSteps = 0x%08x)\n",aThreadId,aNumSteps); |
|
3691 |
|
3692 DThread* thread = DebugUtils::OpenThreadHandle(aThreadId); |
|
3693 |
|
3694 if (thread == NULL) |
|
3695 { |
|
3696 // The thread terminated before we could open it. |
|
3697 LOG_MSG2("DRM_DebugChannel::Step - Could not open thread %u", aThreadId); |
|
3698 |
|
3699 return KErrArgument; |
|
3700 } |
|
3701 |
|
3702 // We simply repeat this for desired number of steps |
|
3703 TInt err = KErrNone; |
|
3704 |
|
3705 // Need to step from the current location for 'n' steps |
|
3706 TUint32 startAddress; |
|
3707 |
|
3708 // We always step from the current PC. |
|
3709 err = ReadKernelRegisterValue(thread, PC_REGISTER, startAddress); |
|
3710 if(err != KErrNone) |
|
3711 { |
|
3712 LOG_MSG2("DRM_DebugChannel::Step - Could not read the PC: %d", err); |
|
3713 |
|
3714 // Close the handle |
|
3715 thread->Close(NULL); |
|
3716 |
|
3717 return err; |
|
3718 } |
|
3719 |
|
3720 err = DoStepRange(thread, startAddress, startAddress, ETrue, EFalse, aNumSteps, ETrue); |
|
3721 |
|
3722 if (err != KErrNone) |
|
3723 { |
|
3724 // There was a problem, return straightaway |
|
3725 LOG_MSG("DRM_DebugChannel::Step - failed to step"); |
|
3726 } |
|
3727 |
|
3728 // Close the handle |
|
3729 thread->Close(NULL); |
|
3730 |
|
3731 return err; |
|
3732 } |
|
3733 |
|
3734 TInt DRM_DebugChannel::KillProcess(const TUint32 aProcessId, const TInt aReason) |
|
3735 { |
|
3736 LOG_MSG3("DRM_DebugChannel::KillProcess(aProcessId = 0x%08x, aReason = 0x%08x)\n",aProcessId,aReason); |
|
3737 |
|
3738 DProcess* process = DebugUtils::OpenProcessHandle(aProcessId); |
|
3739 |
|
3740 if (process == NULL) |
|
3741 { |
|
3742 // The process terminated before we could open it to kill it ourselves. |
|
3743 LOG_MSG2("DRM_DebugChannel::KillProcess - Could not open process %u", aProcessId); |
|
3744 |
|
3745 return KErrArgument; |
|
3746 } |
|
3747 |
|
3748 TInt err = KErrNone; |
|
3749 |
|
3750 DebugSupport::TerminateProcess(process,aReason); |
|
3751 |
|
3752 // Close the handle |
|
3753 process->Close(NULL); |
|
3754 |
|
3755 return err; |
|
3756 } |
|
3757 |
|
3758 /* Security critical - this checks whether the specified process is debuggable or not |
|
3759 * |
|
3760 * @param aProcessId - The process id of the process to check |
|
3761 * @return KErrNone if debuggable, KErrPermissionDenied if not debuggable. |
|
3762 */ |
|
3763 TInt DRM_DebugChannel::IsDebuggable(const TUint32 aProcessId) |
|
3764 { |
|
3765 /* In order to ensure that only processes which are debuggable |
|
3766 * can be debugged, this function enables the security server |
|
3767 * to read the DProcess.iDebugAttributes field and ensure |
|
3768 * the process was created from a debuggable executable. |
|
3769 */ |
|
3770 LOG_MSG2("DRM_DebugChannel::IsDebuggable(aProcessId 0x%08x)\n",aProcessId); |
|
3771 |
|
3772 TInt err = KErrPermissionDenied; |
|
3773 |
|
3774 DProcess* process = DebugUtils::OpenProcessHandle(aProcessId); |
|
3775 if (process) |
|
3776 { |
|
3777 if (process->iDebugAttributes & TProcessCreateInfo::EDebugAllowed) |
|
3778 { |
|
3779 // Yes this process exists and is debuggable |
|
3780 err = KErrNone; |
|
3781 } |
|
3782 process->Close(NULL); |
|
3783 } |
|
3784 |
|
3785 if (err == KErrNone) |
|
3786 { |
|
3787 LOG_MSG2("DRM_DebugChannel::IsDebuggable(aProcessId 0x%08x) - Yes it is debuggable\n",aProcessId); |
|
3788 } |
|
3789 |
|
3790 return err; |
|
3791 } |
|