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