|
1 /* |
|
2 * Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #ifdef __WINS__ |
|
20 #error - this driver cannot be built for emulation |
|
21 #endif |
|
22 |
|
23 #include <e32def.h> |
|
24 #include <e32cmn.h> |
|
25 #include <u32std.h> |
|
26 #include <kernel.h> |
|
27 #include <kern_priv.h> |
|
28 #include <nk_trace.h> |
|
29 //#include <mmboot.h> |
|
30 #include <arm.h> |
|
31 #include <cache.h> |
|
32 #include <platform.h> |
|
33 #include <nkern.h> |
|
34 #include <u32hal.h> |
|
35 |
|
36 #include "TrkKernelDriver.h" |
|
37 #include "TrkDriver.h" |
|
38 #include "TrkEventHandler.h" |
|
39 |
|
40 #define KTrkAppSecurUid 0x200170BB |
|
41 #define KTrkExeSecurUid 0x200159E2 |
|
42 #define KTrkSrvSecurUid 0x200170B7 |
|
43 |
|
44 // Uncomment the line below for reading kernel thread registers. |
|
45 // There is a problem using NKern::Lock before calling UserContextType on old releases like S60 3.0 |
|
46 // So for now, disabling the supporting reading kern thread registers as we are not really supporting |
|
47 // device driver debugging anyway. |
|
48 //#define SUPPORT_KERNCONTEXT |
|
49 |
|
50 // |
|
51 // Static function definitions |
|
52 // |
|
53 |
|
54 static TInt Bitcount(TUint32 val) |
|
55 { |
|
56 TInt nbits; |
|
57 |
|
58 for (nbits = 0; val != 0; nbits++) |
|
59 { |
|
60 val &= val - 1; // delete rightmost 1-bit in val |
|
61 } |
|
62 |
|
63 return nbits; |
|
64 } |
|
65 |
|
66 static TUint8 tolower(TUint8 c) |
|
67 { |
|
68 if (c >= 'A' && c <= 'Z') |
|
69 c = c + ('a' - 'A'); |
|
70 |
|
71 return c; |
|
72 } |
|
73 |
|
74 |
|
75 static TInt _strnicmp(const TUint8 *s1, const TUint8 *s2, int n) |
|
76 { |
|
77 int i; |
|
78 TUint8 c1, c2; |
|
79 for (i=0; i<n; i++) |
|
80 { |
|
81 c1 = tolower(*s1++); |
|
82 c2 = tolower(*s2++); |
|
83 if (c1 < c2) return -1; |
|
84 if (c1 > c2) return 1; |
|
85 if (!c1) return 0; |
|
86 } |
|
87 return 0; |
|
88 } |
|
89 |
|
90 // |
|
91 // |
|
92 // DMetroTrkDriverFactory implementation |
|
93 // |
|
94 // |
|
95 |
|
96 // |
|
97 // DMetroTrkDriverFactory constructor |
|
98 // |
|
99 DMetroTrkDriverFactory::DMetroTrkDriverFactory() |
|
100 { |
|
101 iVersion = TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); |
|
102 } |
|
103 |
|
104 // |
|
105 // DMetroTrkDriverFactory::Create |
|
106 // |
|
107 TInt DMetroTrkDriverFactory::Create(DLogicalChannelBase*& aChannel) |
|
108 { |
|
109 if (iOpenChannels != 0) |
|
110 return KErrInUse; // a channel is already open |
|
111 |
|
112 aChannel = new DMetroTrkChannel(this); |
|
113 |
|
114 return aChannel ? KErrNone : KErrNoMemory; |
|
115 } |
|
116 |
|
117 // |
|
118 // DMetroTrkDriverFactory::Install |
|
119 // |
|
120 TInt DMetroTrkDriverFactory::Install() |
|
121 { |
|
122 return(SetName(&KMetroTrkDriverName)); |
|
123 } |
|
124 |
|
125 // |
|
126 // DMetroTrkDriverFactory::Install |
|
127 // |
|
128 void DMetroTrkDriverFactory::GetCaps(TDes8& aDes) const |
|
129 { |
|
130 TCapsMetroTrkDriver b; |
|
131 b.iVersion = TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber); |
|
132 |
|
133 Kern::InfoCopy(aDes,(TUint8*)&b, sizeof(b)); |
|
134 } |
|
135 |
|
136 |
|
137 // |
|
138 // |
|
139 // DMetroTrkChannel implementation |
|
140 // |
|
141 // |
|
142 |
|
143 // |
|
144 // DMetroTrkChannel constructor |
|
145 // |
|
146 DMetroTrkChannel::DMetroTrkChannel(DLogicalDevice* aLogicalDevice) |
|
147 : iExcludedROMAddressStart(ROM_LINEAR_BASE), |
|
148 iExcludedROMAddressEnd(0), |
|
149 iBreakPointList(NUMBER_OF_TEMP_BREAKPOINTS, 0), |
|
150 iNextBreakId(NUMBER_OF_TEMP_BREAKPOINTS), |
|
151 iEventInfo(NULL), |
|
152 iEventQueue(NUMBER_OF_EVENTS_TO_QUEUE, 0), |
|
153 iTraceEventQueue(NUMBER_OF_EVENTS_TO_QUEUE, 0), |
|
154 iRequestGetEventStatus(NULL), |
|
155 iPageSize(0x1000), |
|
156 iNotifyLibLoadedEvent(ETrue), |
|
157 iMultipleMemModel(EFalse), |
|
158 iExcInfoValid(EFalse), |
|
159 iDebugging(ETrue) |
|
160 { |
|
161 LOG_MSG("DMetroTrkChannel::DMetroTrkChannel()"); |
|
162 |
|
163 iDevice = aLogicalDevice; |
|
164 |
|
165 iClientThread = &Kern::CurrentThread(); |
|
166 TInt err = iClientThread->Open(); |
|
167 |
|
168 iBreakPointList.Reset(); |
|
169 TBreakEntry emptyTempBreak; |
|
170 |
|
171 for (TInt i = 0; i < NUMBER_OF_TEMP_BREAKPOINTS; i++) |
|
172 { |
|
173 emptyTempBreak.iId = i; |
|
174 |
|
175 if (KErrNone != iBreakPointList.Append(emptyTempBreak)) |
|
176 { |
|
177 LOG_MSG("Error appending blank temp break entry"); |
|
178 } |
|
179 } |
|
180 |
|
181 SEventInfo emptyEvent; |
|
182 |
|
183 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++) |
|
184 { |
|
185 if (KErrNone != iEventQueue.Append(emptyEvent)) |
|
186 { |
|
187 LOG_MSG("Error appending blank event entry"); |
|
188 } |
|
189 } |
|
190 |
|
191 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++) |
|
192 { |
|
193 if (KErrNone != iTraceEventQueue.Append(emptyEvent)) |
|
194 { |
|
195 LOG_MSG("Error appending blank trace event entry"); |
|
196 } |
|
197 } |
|
198 |
|
199 TTrkLibName emptyLib; |
|
200 for (TInt i=0; i<NUMBER_OF_LIBS_TO_REGISTER; i++) |
|
201 { |
|
202 if (KErrNone != iLibraryNotifyList.Append(emptyLib)) |
|
203 { |
|
204 LOG_MSG("Error appending blank empty lib entry"); |
|
205 } |
|
206 } |
|
207 |
|
208 iPageSize = Kern::RoundToPageSize(1); |
|
209 } |
|
210 |
|
211 // |
|
212 // DMetroTrkChannel destructor |
|
213 // |
|
214 DMetroTrkChannel::~DMetroTrkChannel() |
|
215 { |
|
216 LOG_MSG("DMetroTrkChannel::~DMetroTrkChannel()"); |
|
217 |
|
218 iDebugging = EFalse; |
|
219 |
|
220 Kern::SafeClose((DObject*&)iClientThread, NULL); |
|
221 |
|
222 ClearAllBreakPoints(); |
|
223 |
|
224 // close the breakpoint list and free the memory associated with it |
|
225 iBreakPointList.Close(); |
|
226 |
|
227 // close the event queue and free the memory associated with it |
|
228 iEventQueue.Close(); |
|
229 |
|
230 // close the trace event queue and free the memory associated with it |
|
231 iTraceEventQueue.Close(); |
|
232 |
|
233 //close the debug process list |
|
234 iDebugProcessList.Close(); |
|
235 |
|
236 //close the process notify list |
|
237 iProcessNotifyList.Close(); |
|
238 |
|
239 //close the code modifier |
|
240 DebugSupport::CloseCodeModifier(); |
|
241 |
|
242 // PANIC_BACKPORT |
|
243 // Resume all the frozen threads with semaphores. |
|
244 for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++) |
|
245 { |
|
246 NKern::FSSignal(iFrozenThreadSemaphores[i]); |
|
247 NKern::ThreadEnterCS(); |
|
248 delete iFrozenThreadSemaphores[i]; |
|
249 NKern::ThreadLeaveCS(); |
|
250 iFrozenThreadSemaphores.Remove(i); |
|
251 } |
|
252 //Reset the array and delete the objects that its members point to |
|
253 iFrozenThreadSemaphores.ResetAndDestroy(); |
|
254 // END PANIC_BACKPORT |
|
255 } |
|
256 |
|
257 // |
|
258 // DMetroTrkChannel::DoCreate |
|
259 // |
|
260 TInt DMetroTrkChannel::DoCreate(TInt /*aUnit*/, const TDesC* anInfo, const TVersion& aVer) |
|
261 { |
|
262 LOG_MSG("DMetroTrkChannel::DoCreate()"); |
|
263 |
|
264 if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber), aVer)) |
|
265 return KErrNotSupported; |
|
266 |
|
267 // Do the security check here so that any arbitrary application doesn't make |
|
268 // use of Trk kernel driver. |
|
269 if (!DoSecurityCheck()) |
|
270 { |
|
271 return KErrPermissionDenied; |
|
272 } |
|
273 |
|
274 if (anInfo) |
|
275 { |
|
276 // this is the end address of the user library. |
|
277 // this doesn't seem to be valid for EKA2. |
|
278 // right now we dont need this for EKA2 since we are not worried |
|
279 // about kernel being stopped as kernel is multithreaded. |
|
280 // just retaining this for future use. |
|
281 TBuf8<32> buf; |
|
282 TInt err = Kern::ThreadRawRead(iClientThread, anInfo, &buf, 32); |
|
283 if(err != KErrNone) |
|
284 return err; |
|
285 |
|
286 //iExcludedROMAddressEnd = *(TUint32 *)(&(buf.Ptr()[20])); |
|
287 } |
|
288 |
|
289 //check whether the memory model is multiple or not. |
|
290 TUint32 memModelAttrib = (TUint32)Kern::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL); |
|
291 if ((memModelAttrib & EMemModelTypeMask) == EMemModelTypeMultiple) |
|
292 { |
|
293 //Multiple memory model |
|
294 iMultipleMemModel = ETrue; |
|
295 } |
|
296 |
|
297 TUint caps; //ignored for now |
|
298 TInt err = DebugSupport::InitialiseCodeModifier(caps, NUMBER_OF_MAX_BREAKPOINTS); |
|
299 //if code modifier initializer failed, |
|
300 //return here, since we can't set an breakpoints |
|
301 if(err != KErrNone) |
|
302 return err; |
|
303 |
|
304 //Setup the driver for receiving client messages |
|
305 iDFCQue = NULL; |
|
306 TBuf8<KMaxInfoName> trkDFC = _L8("TRK DFC"); |
|
307 |
|
308 err = Kern::DfcQCreate(iDFCQue, 27, &trkDFC); |
|
309 if (err == KErrNone) |
|
310 { |
|
311 SetDfcQ(iDFCQue); |
|
312 } |
|
313 else |
|
314 { |
|
315 SetDfcQ(Kern::DfcQue0()); |
|
316 } |
|
317 iMsgQ.Receive(); |
|
318 |
|
319 iEventHandler = new DMetroTrkEventHandler; |
|
320 if (!iEventHandler) |
|
321 return KErrNoMemory; |
|
322 err = iEventHandler->Create(iDevice, this, iClientThread); |
|
323 if (err != KErrNone) |
|
324 return err; |
|
325 |
|
326 return iEventHandler->Start(); |
|
327 } |
|
328 |
|
329 // |
|
330 // DMetroTrkChannel::DoCancel |
|
331 // |
|
332 void DMetroTrkChannel::DoCancel(TInt aReqNo) |
|
333 { |
|
334 LOG_MSG("DMetroTrkChannel::DoCancel()"); |
|
335 |
|
336 switch(aReqNo) |
|
337 { |
|
338 case RMetroTrkDriver::ERequestGetEventCancel: |
|
339 { |
|
340 Kern::RequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel); |
|
341 iEventInfo = NULL; |
|
342 iRequestGetEventStatus = 0; |
|
343 } |
|
344 break; |
|
345 } |
|
346 |
|
347 } |
|
348 |
|
349 // |
|
350 // DMetroTrkChannel::DoRequest |
|
351 // |
|
352 void DMetroTrkChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
353 { |
|
354 LOG_MSG("DMetroTrkChannel::DoRequest()"); |
|
355 |
|
356 switch(aReqNo) |
|
357 { |
|
358 case RMetroTrkDriver::ERequestGetEvent: |
|
359 { |
|
360 // check to see if we have any queued up events |
|
361 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++) |
|
362 { |
|
363 if (SEventInfo::EUnknown != iEventQueue[i].iEventType) |
|
364 { |
|
365 LOG_MSG("DoRequest - slot NOT empty"); |
|
366 // iClientThread is the user side debugger thread, so use it to write the info to it memory |
|
367 TInt err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8 *)&iEventQueue[i], sizeof(SEventInfo), iClientThread); |
|
368 if (KErrNone != err) |
|
369 LOG_MSG2("Error writing event info: %d", err); |
|
370 |
|
371 // signal the debugger thread |
|
372 Kern::RequestComplete(iClientThread, aStatus, KErrNone); |
|
373 |
|
374 iEventQueue[i].Reset(); |
|
375 return; |
|
376 } |
|
377 |
|
378 LOG_MSG("DoRequest - slot empty"); |
|
379 } |
|
380 |
|
381 // check to see if we have any queued up trace events |
|
382 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++) |
|
383 { |
|
384 if (SEventInfo::EUnknown != iTraceEventQueue[i].iEventType) |
|
385 { |
|
386 LOG_MSG("DoRequest - slot NOT empty"); |
|
387 // iClientThread is the user side debugger thread, so use it to write the info to it memory |
|
388 TInt err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8 *)&iTraceEventQueue[i], sizeof(SEventInfo), iClientThread); |
|
389 if (KErrNone != err) |
|
390 LOG_MSG2("Error writing trace event info: %d", err); |
|
391 |
|
392 // signal the debugger thread |
|
393 Kern::RequestComplete(iClientThread, aStatus, KErrNone); |
|
394 |
|
395 iTraceEventQueue[i].Reset(); |
|
396 return; |
|
397 } |
|
398 |
|
399 LOG_MSG("DoRequest - trace slot empty"); |
|
400 } |
|
401 |
|
402 // store the pointer so we can modify it later |
|
403 iEventInfo = (SEventInfo *)a1; |
|
404 iRequestGetEventStatus = aStatus; |
|
405 break; |
|
406 } |
|
407 default: |
|
408 Kern::RequestComplete(iClientThread, aStatus, KErrNotSupported); |
|
409 } |
|
410 |
|
411 } |
|
412 |
|
413 // |
|
414 // DMetroTrkChannel::DoControl |
|
415 // |
|
416 TInt DMetroTrkChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
417 { |
|
418 LOG_MSG("DMetroTrkChannel::DoControl()"); |
|
419 |
|
420 LOG_MSG2("DoControl Function %d", aFunction); |
|
421 |
|
422 TInt err = KErrNone; |
|
423 |
|
424 switch(aFunction) |
|
425 { |
|
426 case RMetroTrkDriver::EControlSetBreak: |
|
427 { |
|
428 err = SetBreak((TUint32)a1, (TMetroTrkBreakInfo*)a2); |
|
429 break; |
|
430 } |
|
431 case RMetroTrkDriver::EControlClearBreak: |
|
432 { |
|
433 err = DoClearBreak((TInt32)a1); |
|
434 break; |
|
435 } |
|
436 case RMetroTrkDriver::EControlChangeBreakThread: |
|
437 { |
|
438 err = DoChangeBreakThread((TUint32)a1, (TInt32)a2); |
|
439 break; |
|
440 } |
|
441 case RMetroTrkDriver::EControlSuspendThread: |
|
442 { |
|
443 err = DoSuspendThread(ThreadFromId((TUint32)a1)); |
|
444 break; |
|
445 } |
|
446 case RMetroTrkDriver::EControlResumeThread: |
|
447 { |
|
448 err = DoResumeThread(ThreadFromId((TUint32)a1)); |
|
449 break; |
|
450 } |
|
451 case RMetroTrkDriver::EControlStepRange: |
|
452 { |
|
453 err = StepRange(ThreadFromId((TUint32)a1), (TMetroTrkStepInfo*)a2); |
|
454 break; |
|
455 } |
|
456 case RMetroTrkDriver::EControlReadMemory: |
|
457 { |
|
458 err = ReadMemory(ThreadFromId((TUint32)a1), (TMetroTrkMemoryInfo*)a2); |
|
459 break; |
|
460 } |
|
461 case RMetroTrkDriver::EControlWriteMemory: |
|
462 { |
|
463 err = WriteMemory(ThreadFromId((TUint32)a1), (TMetroTrkMemoryInfo*)a2); |
|
464 break; |
|
465 } |
|
466 case RMetroTrkDriver::EControlReadRegisters: |
|
467 { |
|
468 err = ReadRegisters(ThreadFromId((TUint32)a1), (TMetroTrkRegisterInfo*)a2); |
|
469 break; |
|
470 } |
|
471 case RMetroTrkDriver::EControlWriteRegisters: |
|
472 { |
|
473 err = WriteRegisters(ThreadFromId((TUint32)a1), (TMetroTrkRegisterInfo*)a2); |
|
474 break; |
|
475 } |
|
476 case RMetroTrkDriver::EControlGetProcessInfo: |
|
477 { |
|
478 err = GetProcessInfo((TInt)a1, (TMetroTrkTaskInfo*)a2); |
|
479 break; |
|
480 } |
|
481 case RMetroTrkDriver::EControlGetThreadInfo: |
|
482 { |
|
483 err = GetThreadInfo((TInt)a1, (TMetroTrkTaskInfo*)a2); |
|
484 break; |
|
485 } |
|
486 case RMetroTrkDriver::EControlGetProcessAddresses: |
|
487 { |
|
488 err = GetProcessAddresses(ThreadFromId((TUint32)a1), (TMetroTrkProcessInfo*)a2); |
|
489 break; |
|
490 } |
|
491 case RMetroTrkDriver::EControlGetStaticLibraryInfo: |
|
492 { |
|
493 err = GetStaticLibraryInfo((TInt)a1, (SEventInfo*)a2); |
|
494 break; |
|
495 } |
|
496 case RMetroTrkDriver::EControlEnableLibLoadedEvent: |
|
497 { |
|
498 iNotifyLibLoadedEvent = ETrue; |
|
499 break; |
|
500 } |
|
501 case RMetroTrkDriver::EControlDisableLibLoadedEvent: |
|
502 { |
|
503 iNotifyLibLoadedEvent = EFalse; |
|
504 break; |
|
505 } |
|
506 case RMetroTrkDriver::EControlGetLibraryInfo: |
|
507 { |
|
508 err = GetLibraryInfo((TMetroTrkLibInfo*)a1); |
|
509 break; |
|
510 } |
|
511 case RMetroTrkDriver::EControlGetExeInfo: |
|
512 { |
|
513 err = GetExeInfo((TMetroTrkExeInfo*)a1); |
|
514 break; |
|
515 } |
|
516 case RMetroTrkDriver::EControlGetProcUidInfo: |
|
517 { |
|
518 err = GetProcUidInfo((TMetroTrkProcUidInfo*)a1); |
|
519 break; |
|
520 } |
|
521 case RMetroTrkDriver::EControlDetachProcess: |
|
522 { |
|
523 err = DetachProcess(ProcessFromId((TInt32)a1)); |
|
524 break; |
|
525 } |
|
526 default: |
|
527 { |
|
528 return KErrGeneral; |
|
529 } |
|
530 } |
|
531 |
|
532 if (KErrNone != err) |
|
533 { |
|
534 LOG_MSG2("Error %d from control function", err); |
|
535 } |
|
536 |
|
537 return err; |
|
538 } |
|
539 |
|
540 void DMetroTrkChannel::HandleMsg(TMessageBase* aMsg) |
|
541 { |
|
542 LOG_MSG("DMetroTrkChannel::HandleMsg()"); |
|
543 |
|
544 TThreadMessage& m = *(TThreadMessage*)aMsg; |
|
545 TInt id = m.iValue; |
|
546 |
|
547 |
|
548 if (id == (TInt)ECloseMsg) |
|
549 { |
|
550 if (iEventHandler) |
|
551 { |
|
552 iDebugging = EFalse; |
|
553 iEventHandler->Stop(); |
|
554 iEventHandler->Close(); |
|
555 iEventHandler = NULL; |
|
556 } |
|
557 m.Complete(KErrNone, EFalse); |
|
558 return; |
|
559 } |
|
560 |
|
561 if (id == KMaxTInt) |
|
562 { |
|
563 // DoCancel |
|
564 DoCancel(m.Int0()); |
|
565 m.Complete(KErrNone, ETrue); |
|
566 return; |
|
567 } |
|
568 |
|
569 if (id < 0) |
|
570 { |
|
571 // DoRequest |
|
572 TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); |
|
573 DoRequest(~id, pStatus, m.Ptr1(), m.Ptr2()); |
|
574 m.Complete(KErrNone, ETrue); |
|
575 } |
|
576 else |
|
577 { |
|
578 // DoControl |
|
579 TInt err = DoControl(id, m.Ptr0(), m.Ptr1()); |
|
580 m.Complete(err, ETrue); |
|
581 } |
|
582 } |
|
583 |
|
584 // |
|
585 // DMetroTrkChannel::AddProcess |
|
586 // |
|
587 void DMetroTrkChannel::AddProcess(DProcess *aProcess, DThread *aThread) |
|
588 { |
|
589 LOG_MSG("DMetroTrkChannel::AddProcess()"); |
|
590 // check to see if we are still debugging, otherwise just return |
|
591 if (!iDebugging) |
|
592 return; |
|
593 |
|
594 if (aProcess) |
|
595 { |
|
596 if (!aThread) |
|
597 LOG_MSG("Creator thread not available"); |
|
598 |
|
599 // check to see if this process is being started by debug agent. |
|
600 // If this is the case, we don't need to notify the agent since the debug agent already knows about it. |
|
601 if (aThread && aThread->iOwningProcess->iId == iClientThread->iOwningProcess->iId) |
|
602 return; |
|
603 |
|
604 SEventInfo processEventInfo; |
|
605 processEventInfo.iEventType = processEventInfo.EProcessAdded; |
|
606 processEventInfo.iProcessId = aProcess->iId; |
|
607 processEventInfo.iFileName.Copy(*aProcess->iName); |
|
608 processEventInfo.iUid = aProcess->iUids.iUid[2].iUid; |
|
609 |
|
610 // Kernel hasn't created teh code segment yet for this process, |
|
611 // so queue this event separately and wait for start thread event to notify. |
|
612 iProcessNotifyList.Append(processEventInfo); |
|
613 } |
|
614 } |
|
615 |
|
616 // |
|
617 // DMetroTrkChannel::StartThread |
|
618 // |
|
619 void DMetroTrkChannel::StartThread(DThread *aThread) |
|
620 { |
|
621 LOG_MSG("DMetroTrkChannel::StartThread()"); |
|
622 // check to see if we are still debugging, otherwise just return |
|
623 if (!iDebugging) |
|
624 return; |
|
625 |
|
626 // Using the lib loaded event flag for notifying processes as well. |
|
627 // Check if lib loaded event is disabled. Lib loaded event |
|
628 // is disabled temporarily in some situations, when the engine |
|
629 // is performing some complex operations like installing sis |
|
630 // files, in which case, suspending the thread for lib loaded |
|
631 // events would end up in a dead lock. This is due to the fact |
|
632 // that the active object that handles the event notification |
|
633 // wouldn't get a chance to run since the code in TRK engine |
|
634 // which handles the commands from the host debugger is also |
|
635 // done in an active object which runs in the same thread. |
|
636 if (!iNotifyLibLoadedEvent) |
|
637 return; |
|
638 |
|
639 if (aThread && aThread->iOwningProcess) |
|
640 { |
|
641 DCodeSeg* codeSeg = aThread->iOwningProcess->iCodeSeg; |
|
642 if (codeSeg) |
|
643 { |
|
644 TModuleMemoryInfo processMemoryInfo; |
|
645 TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, aThread->iOwningProcess); |
|
646 if (err == KErrNone) |
|
647 { |
|
648 for (TInt i = 0; i < iProcessNotifyList.Count(); i++) |
|
649 { |
|
650 if (iProcessNotifyList[i].iProcessId == aThread->iOwningProcess->iId) |
|
651 { |
|
652 // Suspend the thread so that the host debugger can set breakpoints. |
|
653 Kern::ThreadSuspend(*aThread, 1); |
|
654 iProcessNotifyList[i].iThreadId = aThread->iId; |
|
655 iProcessNotifyList[i].iCodeAddress = processMemoryInfo.iCodeBase; |
|
656 iProcessNotifyList[i].iDataAddress = processMemoryInfo.iInitialisedDataBase; |
|
657 // Notify the process added event now that we have the code segment for the process |
|
658 NotifyEvent(iProcessNotifyList[i]); |
|
659 // Now remove from the list |
|
660 iProcessNotifyList.Remove(i); |
|
661 break; |
|
662 } |
|
663 } |
|
664 } |
|
665 else |
|
666 { |
|
667 LOG_MSG2("Error in getting memory info: %d", err); |
|
668 } |
|
669 } |
|
670 else |
|
671 { |
|
672 LOG_MSG2("Invalid code segment found for the started thread: %d", aThread->iId); |
|
673 } |
|
674 } |
|
675 } |
|
676 |
|
677 // |
|
678 // DMetroTrkChannel::RemoveProcess |
|
679 // |
|
680 void DMetroTrkChannel::RemoveProcess(DProcess *aProcess) |
|
681 { |
|
682 LOG_MSG("DMetroTrkChannel::RemoveProcess()"); |
|
683 // check to see if we are still debugging, otherwise just return |
|
684 if (!iDebugging) |
|
685 return; |
|
686 |
|
687 // this is called when a process dies. we want to mark any breakpoints in this |
|
688 // process space as obsolete. the main reason for this is so we don't return |
|
689 // an error when the host debugger tries to clear breakpoints for the process |
|
690 |
|
691 TUint32 codeAddress = 0; |
|
692 TUint32 codeSize = 0; |
|
693 |
|
694 LOG_MSG2("Process being removed, Name %S", aProcess->iName); |
|
695 |
|
696 DCodeSeg* codeSeg = aProcess->iCodeSeg; |
|
697 |
|
698 if (codeSeg) |
|
699 { |
|
700 TModuleMemoryInfo processMemoryInfo; |
|
701 TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, aProcess); |
|
702 if (err != KErrNone) |
|
703 { |
|
704 |
|
705 codeAddress = processMemoryInfo.iCodeBase; |
|
706 codeSize = processMemoryInfo.iCodeSize; |
|
707 } |
|
708 else |
|
709 { |
|
710 LOG_MSG2("Error in getting memory info: %d", err); |
|
711 } |
|
712 |
|
713 } |
|
714 |
|
715 if (!codeAddress || !codeSize) |
|
716 { |
|
717 LOG_MSG2("Code segment not available for process %d", aProcess->iId); |
|
718 // make sure there is not already a breakpoint at this address |
|
719 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
720 { |
|
721 if (iDebugProcessList[i].iId == aProcess->iId) |
|
722 { |
|
723 codeAddress = iDebugProcessList[i].iCodeAddress; |
|
724 codeSize = iDebugProcessList[i].iCodeSize; |
|
725 |
|
726 //now remove from the list |
|
727 iDebugProcessList.Remove(i); |
|
728 break; |
|
729 } |
|
730 } |
|
731 } |
|
732 |
|
733 if (!codeAddress || !codeSize) |
|
734 return; |
|
735 |
|
736 // first invalidate all breakpoints that were set in the library code |
|
737 for (TInt i=0; i<iBreakPointList.Count(); i++) |
|
738 { |
|
739 if ((iBreakPointList[i].iAddress >= codeAddress) && (iBreakPointList[i].iAddress < (codeAddress + codeSize))) |
|
740 { |
|
741 LOG_MSG2("Disabling process breakpoint at address %x", iBreakPointList[i].iAddress); |
|
742 iBreakPointList[i].iObsoleteLibraryBreakpoint = ETrue; |
|
743 } |
|
744 } |
|
745 } |
|
746 |
|
747 |
|
748 // |
|
749 // DMetroTrkChannel::AddLibrary |
|
750 // |
|
751 void DMetroTrkChannel::AddLibrary(DLibrary *aLibrary, DThread *aThread) |
|
752 { |
|
753 LOG_MSG("DMetroTrkChannel::AddLibrary()"); |
|
754 |
|
755 LOG_MSG2(("Lib loaded: %S"), aLibrary->iName); |
|
756 |
|
757 // check to see if we are still debugging, otherwise just return |
|
758 if (!iDebugging) |
|
759 return; |
|
760 |
|
761 // Check if lib loaded event is disabled. Lib loaded event |
|
762 // is disabled temporarily in some situations, when the engine |
|
763 // is performing some complex operations like installing sis |
|
764 // files, in which case, suspending the thread for lib loaded |
|
765 // events would end up in a dead lock. This is due to the fact |
|
766 // that the active object that handles the event notification |
|
767 // wouldn't get a chance to run since the code in TRK engine |
|
768 // which handles the commands from the host debugger is also |
|
769 // done in an active object which runs in the same thread. |
|
770 if (!iNotifyLibLoadedEvent) |
|
771 return; |
|
772 |
|
773 TBool isDebugging = EFalse; |
|
774 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
775 { |
|
776 if (iDebugProcessList[i].iId == aThread->iOwningProcess->iId) |
|
777 { |
|
778 isDebugging = ETrue; |
|
779 break; |
|
780 } |
|
781 } |
|
782 if (isDebugging == EFalse) |
|
783 return; |
|
784 |
|
785 if (aThread) |
|
786 { |
|
787 // make sure this is not the debugger thread |
|
788 if ((aThread != iClientThread) && (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) |
|
789 { |
|
790 SEventInfo info; |
|
791 |
|
792 Kern::ThreadSuspend(*aThread, 1); |
|
793 |
|
794 info.iEventType = SEventInfo::ELibraryLoaded; |
|
795 info.iProcessId = aThread->iOwningProcess->iId; |
|
796 info.iThreadId = aThread->iId; |
|
797 |
|
798 //get the code address |
|
799 DCodeSeg* codeSeg = aLibrary->iCodeSeg; |
|
800 if (!codeSeg) |
|
801 { |
|
802 LOG_MSG2("Code segment not available for library %S", aLibrary->iName); |
|
803 return; |
|
804 } |
|
805 |
|
806 TModuleMemoryInfo memoryInfo; |
|
807 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); //NULL for DProcess should be ok; |
|
808 if (err != KErrNone) |
|
809 { |
|
810 LOG_MSG2("Error in getting memory info: %d", err); |
|
811 return; |
|
812 } |
|
813 |
|
814 info.iCodeAddress = memoryInfo.iCodeBase; |
|
815 info.iDataAddress = memoryInfo.iInitialisedDataBase; |
|
816 |
|
817 info.iFileName.Copy(*(aLibrary->iName)); //just the name, without uid info. |
|
818 |
|
819 // now remove this library if its in our notify list |
|
820 for (TInt i =0; i<iLibraryNotifyList.Count(); i++) |
|
821 { |
|
822 if (!iLibraryNotifyList[i].iEmptySlot && |
|
823 !_strnicmp(iLibraryNotifyList[i].iName.Ptr(), info.iFileName.Ptr(), info.iFileName.Length())) |
|
824 { |
|
825 iLibraryNotifyList[i].iEmptySlot = ETrue; |
|
826 break; |
|
827 } |
|
828 } |
|
829 // now check to see if any libs are loaded because of this library load event. |
|
830 CheckLibraryNotifyList(info.iProcessId); |
|
831 //queue up or complete the event |
|
832 NotifyEvent(info); |
|
833 } |
|
834 |
|
835 } |
|
836 |
|
837 } |
|
838 |
|
839 // |
|
840 // DMetroTrkChannel::RemoveLibrary |
|
841 // |
|
842 void DMetroTrkChannel::RemoveLibrary(DLibrary *aLibrary) |
|
843 { |
|
844 LOG_MSG("DMetroTrkChannel::RemoveLibrary()"); |
|
845 LOG_MSG2(("Lib unloaded: %S"), aLibrary->iName); |
|
846 |
|
847 // check to see if we are still debugging, otherwise just return |
|
848 if (!iDebugging) |
|
849 return; |
|
850 |
|
851 // this is called when all handles to this library have been closed. this can happen when a process dies, or when a dll is |
|
852 // unloaded while the process lives on. in former case, we don't need to notify the host debugger because that process is |
|
853 // dying anyway. for the latter case, we do need to notify the host so it can unload the symbolics, etc. |
|
854 |
|
855 DThread* aThread = &Kern::CurrentThread(); |
|
856 |
|
857 if ((aThread) && |
|
858 (aThread != iClientThread) && |
|
859 (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) |
|
860 { |
|
861 //the library gets unloaded only when the mapcount is 0. |
|
862 if (aLibrary->iMapCount != 0) |
|
863 return; |
|
864 |
|
865 DCodeSeg* codeSeg = aLibrary->iCodeSeg; |
|
866 if (!codeSeg) |
|
867 { |
|
868 LOG_MSG2("Code segment not available for library %S", aLibrary->iName); |
|
869 return; |
|
870 } |
|
871 |
|
872 TModuleMemoryInfo processMemoryInfo; |
|
873 TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, NULL); //passing NULL for the DProcess argument should be ok; |
|
874 if (err != KErrNone) |
|
875 { |
|
876 LOG_MSG2("Error in getting memory info: %d", err); |
|
877 return; |
|
878 } |
|
879 |
|
880 TUint32 codeAddress = processMemoryInfo.iCodeBase; |
|
881 TUint32 codeSize = processMemoryInfo.iCodeSize; |
|
882 |
|
883 // first invalidate all breakpoints that were set in the library code |
|
884 for (TInt i=0; i<iBreakPointList.Count(); i++) |
|
885 { |
|
886 if ((iBreakPointList[i].iAddress >= codeAddress) && (iBreakPointList[i].iAddress < (codeAddress + codeSize))) |
|
887 { |
|
888 LOG_MSG2("Disabling library breakpoint at address %x", iBreakPointList[i].iAddress); |
|
889 iBreakPointList[i].iObsoleteLibraryBreakpoint = ETrue; |
|
890 } |
|
891 } |
|
892 |
|
893 DProcess *process = &Kern::CurrentProcess(); |
|
894 if (process) |
|
895 { |
|
896 RArray<SCodeSegEntry>* dynamicCode = &(process->iDynamicCode); |
|
897 if (dynamicCode) |
|
898 { |
|
899 for (TInt j=0; j<dynamicCode->Count(); j++) |
|
900 { |
|
901 if ((*dynamicCode)[j].iLib == aLibrary) |
|
902 { |
|
903 SEventInfo info; |
|
904 |
|
905 info.iEventType = SEventInfo::ELibraryUnloaded; |
|
906 info.iFileName.Copy(*(aLibrary->iName)); //lib name without uid info |
|
907 //info.iFileName.ZeroTerminate(); |
|
908 info.iProcessId = process->iId; |
|
909 info.iThreadId = 0xFFFFFFFF; // don't care! |
|
910 |
|
911 //queue up or complete the event |
|
912 NotifyEvent(info); |
|
913 } |
|
914 } |
|
915 } |
|
916 } |
|
917 } |
|
918 } |
|
919 |
|
920 |
|
921 // |
|
922 // DMetroTrkChannel::AddCodeSegment |
|
923 // |
|
924 void DMetroTrkChannel::AddCodeSegment(DCodeSeg *aCodeSeg, DProcess *aProcess) |
|
925 { |
|
926 LOG_MSG("DMetroTrkChannel::AddCodeSegment()"); |
|
927 |
|
928 // Check if lib loaded event is disabled. Lib loaded event |
|
929 // is disabled temporarily in some situations, when the engine |
|
930 // is performing some complex operations like installing sis |
|
931 // files, in which case, suspending the thread for lib loaded |
|
932 // events would end up in a dead lock. This is due to the fact |
|
933 // that the active object that handles the event notification |
|
934 // wouldn't get a chance to run since the code in TRK engine |
|
935 // which handles the commands from the host debugger is also |
|
936 // done in an active object which runs in the same thread. |
|
937 if (!iNotifyLibLoadedEvent) |
|
938 return; |
|
939 |
|
940 TBool isDebugging = EFalse; |
|
941 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
942 { |
|
943 if (iDebugProcessList[i].iId == aProcess->iId) |
|
944 { |
|
945 isDebugging = ETrue; |
|
946 break; |
|
947 } |
|
948 } |
|
949 if (isDebugging == EFalse) |
|
950 return; |
|
951 |
|
952 if (aCodeSeg) |
|
953 { |
|
954 const TUint8* ptr = aCodeSeg->iFileName->Ptr(); |
|
955 if (aCodeSeg->IsDll()) |
|
956 { |
|
957 LOG_MSG2("DLL code segment is loaded: %s", ptr); |
|
958 |
|
959 DThread* mainThread = aProcess->FirstThread(); |
|
960 if (mainThread) |
|
961 { |
|
962 // make sure this is not the debugger thread |
|
963 if ((mainThread->iId != iClientThread->iId) && (aProcess->iId != iClientThread->iOwningProcess->iId)) |
|
964 { |
|
965 SEventInfo info; |
|
966 |
|
967 //DoSuspendThread(mainThread); |
|
968 Kern::ThreadSuspend(*mainThread, 1); |
|
969 |
|
970 info.iEventType = SEventInfo::ELibraryLoaded; |
|
971 info.iProcessId = aProcess->iId; |
|
972 info.iThreadId = mainThread->iId; |
|
973 |
|
974 TModuleMemoryInfo memoryInfo; |
|
975 TInt err = aCodeSeg->GetMemoryInfo(memoryInfo, NULL); //NULL for DProcess should be ok; |
|
976 if (err != KErrNone) |
|
977 { |
|
978 LOG_MSG2("Error in getting memory info: %d", err); |
|
979 return; |
|
980 } |
|
981 |
|
982 info.iCodeAddress = memoryInfo.iCodeBase; |
|
983 info.iDataAddress = memoryInfo.iInitialisedDataBase; |
|
984 |
|
985 info.iFileName.Copy(aCodeSeg->iRootName); //just the name, without uid info. |
|
986 |
|
987 //queue up or complete the event |
|
988 NotifyEvent(info); |
|
989 } |
|
990 |
|
991 } |
|
992 else |
|
993 { |
|
994 LOG_MSG2("Invalid main thread for this process: %d", aProcess->iId); |
|
995 } |
|
996 |
|
997 } |
|
998 else |
|
999 { |
|
1000 if (aCodeSeg->IsExe()) |
|
1001 LOG_MSG2("EXE code segment is loaded: %s", ptr); |
|
1002 } |
|
1003 |
|
1004 } |
|
1005 |
|
1006 } |
|
1007 |
|
1008 // |
|
1009 // DMetroTrkChannel::RemoveCodeSegment |
|
1010 // |
|
1011 void DMetroTrkChannel::RemoveCodeSegment(DCodeSeg *aCodeSeg, DProcess *aProcess) |
|
1012 { |
|
1013 LOG_MSG("DMetroTrkChannel::RemoveCodeSegment()"); |
|
1014 |
|
1015 // We don't do anything right now as we are not using the code segment events. |
|
1016 |
|
1017 } |
|
1018 |
|
1019 // |
|
1020 // DMetroTrkChannel::HandleEventKillThread |
|
1021 // |
|
1022 TBool DMetroTrkChannel::HandleEventKillThread(DThread* aThread) |
|
1023 { |
|
1024 LOG_MSG("DMetroTrkChannel::HandleEventKillThread"); |
|
1025 // check to see if we are still debugging, otherwise just return |
|
1026 if (!iDebugging) |
|
1027 return EFalse; |
|
1028 |
|
1029 if (!aThread) |
|
1030 { |
|
1031 LOG_MSG("Invalid thread handle"); |
|
1032 return EFalse; |
|
1033 } |
|
1034 |
|
1035 |
|
1036 DThread* currentThread = &Kern::CurrentThread(); |
|
1037 if (!currentThread) |
|
1038 { |
|
1039 LOG_MSG("Error getting current thread"); |
|
1040 return EFalse; |
|
1041 } |
|
1042 |
|
1043 //Kern::ThreadSuspend(*currentThread, 1); |
|
1044 |
|
1045 if (aThread->iExitType != EExitPanic) |
|
1046 { |
|
1047 return EFalse; |
|
1048 } |
|
1049 |
|
1050 SEventInfo info; |
|
1051 |
|
1052 info.iProcessId = aThread->iOwningProcess->iId; |
|
1053 info.iThreadId = aThread->iId; |
|
1054 info.iCurrentPC = ReadRegister(aThread, 14);//PC_REGISTER); |
|
1055 info.iPanicCategory.Copy(aThread->iExitCategory); |
|
1056 |
|
1057 info.iExceptionNumber = 100;//aThread->iExitReason; |
|
1058 info.iPanicReason = aThread->iExitReason; |
|
1059 info.iEventType = SEventInfo::EThreadPanic; |
|
1060 |
|
1061 // if its not an invalide opcode exception, check to see if we are debugging |
|
1062 // the process. |
|
1063 TBool isDebugging = EFalse; |
|
1064 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
1065 { |
|
1066 if (iDebugProcessList[i].iId == info.iProcessId) |
|
1067 { |
|
1068 isDebugging = ETrue; |
|
1069 break; |
|
1070 } |
|
1071 } |
|
1072 if (!isDebugging) |
|
1073 return EFalse; |
|
1074 |
|
1075 #define DOFREEZE 1 |
|
1076 // PANIC_BACKPORT |
|
1077 #if DOFREEZE |
|
1078 NKern::ThreadEnterCS(); |
|
1079 NFastSemaphore* sem = new NFastSemaphore(); |
|
1080 NKern::ThreadLeaveCS(); |
|
1081 // sem->iOwningThread = &(Kern::CurrentThread().iNThread); |
|
1082 sem->iOwningThread = &aThread->iNThread; |
|
1083 iFrozenThreadSemaphores.Append(sem); |
|
1084 // First do the notify, then FSWait |
|
1085 NotifyEvent(info); |
|
1086 NKern::FSWait(sem); |
|
1087 return ETrue; |
|
1088 #else |
|
1089 NotifyEvent(info); |
|
1090 LOG_MSG("DMetroTrkChannel::HandleEventKillThread - Panic Do Nothing"); |
|
1091 return EFalse; |
|
1092 #endif |
|
1093 // END PANIC_BACKPORT |
|
1094 } |
|
1095 |
|
1096 // |
|
1097 // DMetroTrkChannel::HandleSwException |
|
1098 // |
|
1099 TBool DMetroTrkChannel::HandleSwException(TExcType aExcType) |
|
1100 { |
|
1101 LOG_MSG("DMetroTrkChannel::HandleSwException"); |
|
1102 |
|
1103 SEventInfo info; |
|
1104 |
|
1105 DThread* currentThread = &Kern::CurrentThread(); |
|
1106 if (!currentThread) |
|
1107 { |
|
1108 LOG_MSG("Error getting current thread"); |
|
1109 return EFalse; |
|
1110 } |
|
1111 |
|
1112 info.iProcessId = currentThread->iOwningProcess->iId; |
|
1113 info.iThreadId = currentThread->iId; |
|
1114 info.iCurrentPC = ReadRegister(currentThread, PC_REGISTER); |
|
1115 info.iExceptionNumber = aExcType; |
|
1116 info.iEventType = SEventInfo::EThreadException; |
|
1117 |
|
1118 if (info.iExceptionNumber != EExcInvalidOpCode) |
|
1119 { |
|
1120 // if its not an invalide opcode exception, check to see if we are debugging |
|
1121 // the process. |
|
1122 TBool isDebugging = EFalse; |
|
1123 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
1124 { |
|
1125 if (iDebugProcessList[i].iId == info.iProcessId) |
|
1126 { |
|
1127 isDebugging = ETrue; |
|
1128 break; |
|
1129 } |
|
1130 } |
|
1131 if (!isDebugging) |
|
1132 return EFalse; |
|
1133 } |
|
1134 |
|
1135 NThread nThread = currentThread->iNThread; |
|
1136 |
|
1137 if (nThread.iSuspendCount == 0) |
|
1138 Kern::ThreadSuspend(*currentThread, 1); |
|
1139 |
|
1140 HandleException(info, currentThread); |
|
1141 |
|
1142 return ETrue; |
|
1143 } |
|
1144 |
|
1145 // |
|
1146 // DMetroTrkChannel::HandleHwException |
|
1147 // |
|
1148 TBool DMetroTrkChannel::HandleHwException(TArmExcInfo* aExcInfo) |
|
1149 { |
|
1150 LOG_MSG("DMetroTrkChannel::HandleHwException()"); |
|
1151 |
|
1152 SEventInfo info; |
|
1153 |
|
1154 DThread* currentThread = &Kern::CurrentThread(); |
|
1155 |
|
1156 if (!currentThread) |
|
1157 { |
|
1158 LOG_MSG("Error getting current thread"); |
|
1159 return EFalse; |
|
1160 } |
|
1161 |
|
1162 //store the exception info as its needed to read the context for system threads |
|
1163 iExcInfoValid = ETrue; |
|
1164 iCurrentExcInfo = *aExcInfo; |
|
1165 |
|
1166 info.iProcessId = currentThread->iOwningProcess->iId; |
|
1167 info.iThreadId = currentThread->iId; |
|
1168 info.iCurrentPC = aExcInfo->iR15; |
|
1169 |
|
1170 switch (aExcInfo->iExcCode) |
|
1171 { |
|
1172 case 0: |
|
1173 info.iExceptionNumber = EExcCodeAbort; |
|
1174 break; |
|
1175 case 1: |
|
1176 info.iExceptionNumber = EExcDataAbort; |
|
1177 break; |
|
1178 case 2: |
|
1179 info.iExceptionNumber = EExcInvalidOpCode; |
|
1180 break; |
|
1181 default: |
|
1182 return EFalse; |
|
1183 |
|
1184 } |
|
1185 info.iEventType = SEventInfo::EThreadException; |
|
1186 |
|
1187 if (info.iExceptionNumber != EExcInvalidOpCode) |
|
1188 { |
|
1189 // if its not an invalide opcode exception, check to see if we are debugging |
|
1190 // the process. |
|
1191 TBool isDebugging = EFalse; |
|
1192 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
1193 { |
|
1194 if (iDebugProcessList[i].iId == info.iProcessId) |
|
1195 { |
|
1196 isDebugging = ETrue; |
|
1197 break; |
|
1198 } |
|
1199 } |
|
1200 if (!isDebugging) |
|
1201 return EFalse; |
|
1202 } |
|
1203 |
|
1204 NThread nThread = currentThread->iNThread; |
|
1205 |
|
1206 if (nThread.iSuspendCount == 0) //don't suspend the thread if its already suspended. |
|
1207 Kern::ThreadSuspend(*currentThread, 1); |
|
1208 |
|
1209 HandleException(info, currentThread); |
|
1210 |
|
1211 return ETrue; |
|
1212 } |
|
1213 |
|
1214 // |
|
1215 // DMetroTrkChannel::HandleException |
|
1216 // |
|
1217 void DMetroTrkChannel::HandleException(SEventInfo& aEventInfo, DThread* aCurrentThread) |
|
1218 { |
|
1219 TInt err = KErrNone; |
|
1220 // see if it was a breakpoint that stopped the thread |
|
1221 if (((TInt)2 == aEventInfo.iExceptionNumber) || ((TInt)EExcInvalidOpCode == aEventInfo.iExceptionNumber)) |
|
1222 { |
|
1223 TUint32 inst = KArmBreakPoint; |
|
1224 TInt instSize = 4; |
|
1225 |
|
1226 // change these for thumb mode |
|
1227 if (ReadRegister(aCurrentThread, STATUS_REGISTER) & ECpuThumb) |
|
1228 { |
|
1229 inst = KThumbBreakPoint; |
|
1230 instSize = 2; |
|
1231 } |
|
1232 |
|
1233 TUint32 instruction = 0; |
|
1234 err = Kern::ThreadRawRead(aCurrentThread, (TUint32 *)aEventInfo.iCurrentPC, (TUint8 *)&instruction, instSize); |
|
1235 |
|
1236 if (KErrNone != err) |
|
1237 LOG_MSG2("Error reading instruction at currentpc: %d", err); |
|
1238 |
|
1239 if (!memcompare((TUint8 *)&inst, instSize, (TUint8 *)&instruction, instSize)) |
|
1240 { |
|
1241 // the exception was a breakpoint instruction. see if we have a breakpoint at that address |
|
1242 for (TInt i=0; i<iBreakPointList.Count(); i++) |
|
1243 { |
|
1244 TBreakEntry breakEntry = iBreakPointList[i]; |
|
1245 |
|
1246 if (breakEntry.iAddress == aEventInfo.iCurrentPC) |
|
1247 { |
|
1248 LOG_MSG2("Breakpoint with Id %d has been hit", breakEntry.iId); |
|
1249 |
|
1250 //change the event type to breakpoint type |
|
1251 aEventInfo.iEventType = SEventInfo::EThreadBreakPoint; |
|
1252 |
|
1253 |
|
1254 // enable any breakpoints we had to disable for this thread |
|
1255 err = DoEnableDisabledBreak(aEventInfo.iThreadId); |
|
1256 if (KErrNone != err) |
|
1257 LOG_MSG2("Error %d enabling disabled breakpoints", err); |
|
1258 |
|
1259 // see if this is a temp breakpoint |
|
1260 if (i < NUMBER_OF_TEMP_BREAKPOINTS) |
|
1261 { |
|
1262 // this was a temp breakpoint, so we need to clear it now |
|
1263 err = DoClearBreak(i); |
|
1264 if (KErrNone != err) |
|
1265 LOG_MSG2("Error %d clearing temp breakpoint", err); |
|
1266 |
|
1267 // if we're not out of range yet, go ahead and single step again |
|
1268 // if we are out of range, either continue or report the event depending |
|
1269 // on the iResumeOnceOutOfRange flag |
|
1270 if ((aEventInfo.iCurrentPC > breakEntry.iRangeStart) && (aEventInfo.iCurrentPC < breakEntry.iRangeEnd)) |
|
1271 { |
|
1272 LOG_MSG("PC is still in range, stepping will continue"); |
|
1273 err = DoStepRange(aCurrentThread, breakEntry.iRangeStart, breakEntry.iRangeEnd, breakEntry.iSteppingInto, breakEntry.iResumeOnceOutOfRange, breakEntry.iSteppingInto); |
|
1274 if (KErrNone != err) |
|
1275 { |
|
1276 LOG_MSG2("Error in DoStepRange: %d. Resuming thread.", err); |
|
1277 err = DoResumeThread(aCurrentThread); |
|
1278 if (KErrNone != err) |
|
1279 LOG_MSG2("Error in DoResumeThread: %d", err); |
|
1280 } |
|
1281 return; |
|
1282 } |
|
1283 else |
|
1284 { |
|
1285 if (breakEntry.iResumeOnceOutOfRange) |
|
1286 { |
|
1287 LOG_MSG("PC is out of range, continuing thread"); |
|
1288 DoResumeThread(aCurrentThread); |
|
1289 |
|
1290 return; |
|
1291 } |
|
1292 } |
|
1293 } |
|
1294 |
|
1295 // if the breakpoint is thread specific, make sure it's the right thread |
|
1296 // if not, just continue the thread. take special care if it's the debugger |
|
1297 // thread. if it hits a regular breakpoint, we NEVER want to stop at it. if |
|
1298 // it hits a temp breakpoint, we're probably just stepping past a real breakpoint |
|
1299 // and we do need to handle it. |
|
1300 if (((breakEntry.iThreadId != aEventInfo.iThreadId) && breakEntry.iThreadSpecific)/*(breakEntry.iThreadId != 0xFFFFFFFF))*/ || |
|
1301 ((aEventInfo.iProcessId == iClientThread->iOwningProcess->iId) && (breakEntry.iThreadId != aEventInfo.iThreadId))) |
|
1302 { |
|
1303 LOG_MSG("breakpoint does not match threadId, calling DoResumeThread"); |
|
1304 err = DoResumeThread(aCurrentThread); |
|
1305 if (KErrNone != err) |
|
1306 LOG_MSG2("Error in DoResumeThread: %d", err); |
|
1307 |
|
1308 return; |
|
1309 } |
|
1310 |
|
1311 //normal user break point, just notify the event |
|
1312 break; |
|
1313 } |
|
1314 } |
|
1315 |
|
1316 } |
|
1317 } |
|
1318 |
|
1319 NotifyEvent(aEventInfo); |
|
1320 } |
|
1321 |
|
1322 // |
|
1323 // DMetroTrkChannel::HandleUserTrace |
|
1324 // |
|
1325 TBool DMetroTrkChannel::HandleUserTrace(TText* aStr, TInt aLen) |
|
1326 { |
|
1327 LOG_MSG("DMetroTrkChannel::HandleUserTrace()"); |
|
1328 |
|
1329 // handle user trace events only for app trk. |
|
1330 #ifndef __OEM_TRK__ |
|
1331 // check to see if we are still debugging, otherwise just return |
|
1332 if (!iDebugging) |
|
1333 return EFalse; |
|
1334 |
|
1335 DThread* currentThread = &Kern::CurrentThread(); |
|
1336 |
|
1337 if (!currentThread) |
|
1338 { |
|
1339 LOG_MSG("Error getting current thread"); |
|
1340 return EFalse; |
|
1341 } |
|
1342 |
|
1343 if (currentThread->iOwningProcess->iId == iClientThread->iOwningProcess->iId) |
|
1344 return EFalse; |
|
1345 |
|
1346 // only send traces for processes you are debugging |
|
1347 TBool isDebugging = EFalse; |
|
1348 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
1349 { |
|
1350 if (iDebugProcessList[i].iId == currentThread->iOwningProcess->iId) |
|
1351 { |
|
1352 isDebugging = ETrue; |
|
1353 break; |
|
1354 } |
|
1355 } |
|
1356 if (!isDebugging) |
|
1357 return EFalse; |
|
1358 |
|
1359 if (aLen > 0) |
|
1360 { |
|
1361 SEventInfo info; |
|
1362 |
|
1363 // This is a temporary solution for grabbing the rdebug printfs. |
|
1364 // With the current TRK implementation, we don't have a mechanism for |
|
1365 // using dynamically allocated buffers between the engine and the driver. |
|
1366 // So for now we are limiting the printf strings to 256 bytes. |
|
1367 TUint8 traceStr[260]; |
|
1368 info.iTraceDataLen = aLen; |
|
1369 |
|
1370 if (info.iTraceDataLen > 256) |
|
1371 info.iTraceDataLen = 256; |
|
1372 |
|
1373 XTRAPD(r, XT_DEFAULT, kumemget(traceStr, aStr, info.iTraceDataLen)); |
|
1374 |
|
1375 if (r == KErrNone) |
|
1376 { |
|
1377 info.iEventType = SEventInfo::EUserTrace; |
|
1378 traceStr[info.iTraceDataLen] = '\r'; |
|
1379 traceStr[info.iTraceDataLen+1] = '\n'; |
|
1380 info.iTraceDataLen += 2; // account for \r and \n. |
|
1381 |
|
1382 info.iTraceData.Copy((TUint8*)traceStr, info.iTraceDataLen); |
|
1383 NotifyEvent(info, ETrue); |
|
1384 } |
|
1385 else |
|
1386 { |
|
1387 return EFalse; |
|
1388 } |
|
1389 } |
|
1390 #endif |
|
1391 |
|
1392 return ETrue; |
|
1393 } |
|
1394 |
|
1395 |
|
1396 // |
|
1397 // DMetroTrkChannel::SetBreak |
|
1398 // |
|
1399 TInt DMetroTrkChannel::SetBreak(TUint32 aThreadId, TMetroTrkBreakInfo* aBreakInfo) |
|
1400 { |
|
1401 LOG_MSG("DMetroTrkChannel::SetBreak()"); |
|
1402 |
|
1403 TInt err = KErrNone; |
|
1404 |
|
1405 if (!aBreakInfo) |
|
1406 return KErrArgument; |
|
1407 |
|
1408 //User side memory is not accessible directly |
|
1409 TMetroTrkBreakInfo info(0, 0, 0, 0); |
|
1410 err = Kern::ThreadRawRead(iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TMetroTrkBreakInfo)); |
|
1411 if (err != KErrNone) |
|
1412 return err; |
|
1413 |
|
1414 if (!info.iId) //first check if the iId address is valid |
|
1415 return KErrArgument; |
|
1416 |
|
1417 if (err == KErrNone) |
|
1418 { |
|
1419 TInt32 iId; |
|
1420 |
|
1421 err = DoSetBreak(info.iProcessId, aThreadId, info.iAddress, info.iThumbMode, iId); |
|
1422 |
|
1423 if (err == KErrNone) |
|
1424 { |
|
1425 err = Kern::ThreadRawWrite(iClientThread, (TUint8 *)info.iId, &iId, sizeof(TInt32), iClientThread); |
|
1426 } |
|
1427 } |
|
1428 return err; |
|
1429 } |
|
1430 |
|
1431 // |
|
1432 // DMetroTrkChannel::StepRange |
|
1433 // |
|
1434 TInt DMetroTrkChannel::StepRange(DThread* aThread, TMetroTrkStepInfo* aStepInfo) |
|
1435 { |
|
1436 LOG_MSG("DMetroTrkChannel::StepRange()"); |
|
1437 |
|
1438 TInt err = KErrNone; |
|
1439 |
|
1440 if (!aStepInfo) |
|
1441 return KErrArgument; |
|
1442 |
|
1443 TMetroTrkStepInfo info(0, 0, 0); |
|
1444 err = Kern::ThreadRawRead(iClientThread, aStepInfo, (TUint8*)&info, sizeof(TMetroTrkStepInfo)); |
|
1445 |
|
1446 if (err != KErrNone) |
|
1447 return err; |
|
1448 |
|
1449 err = DoStepRange(aThread, info.iStartAddress, info.iStopAddress, info.iStepInto, EFalse, ETrue); |
|
1450 |
|
1451 return err; |
|
1452 } |
|
1453 |
|
1454 // |
|
1455 // DMetroTrkChannel::ReadMemory |
|
1456 // |
|
1457 TInt DMetroTrkChannel::ReadMemory(DThread* aThread, TMetroTrkMemoryInfo* aMemoryInfo) |
|
1458 { |
|
1459 LOG_MSG("DMetroTrkChannel::ReadMemory()"); |
|
1460 |
|
1461 TInt err = KErrNone; |
|
1462 |
|
1463 if (!aMemoryInfo) |
|
1464 return KErrArgument; |
|
1465 |
|
1466 #ifndef __OEM_TRK__ |
|
1467 if (!IsBeingDebugged(aThread)) |
|
1468 return KErrPermissionDenied; |
|
1469 #endif |
|
1470 |
|
1471 TMetroTrkMemoryInfo info(0, 0, 0); |
|
1472 err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TMetroTrkMemoryInfo)); |
|
1473 if (err != KErrNone) |
|
1474 return err; |
|
1475 |
|
1476 if (!info.iData) |
|
1477 return KErrArgument; |
|
1478 |
|
1479 TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); |
|
1480 if (!data) |
|
1481 return KErrNoMemory; |
|
1482 |
|
1483 TPtr8 dataDes(data, info.iLength); |
|
1484 |
|
1485 err = DoReadMemory(aThread, info.iAddress, info.iLength, dataDes); |
|
1486 if (err != KErrNone) |
|
1487 return err; |
|
1488 |
|
1489 err = Kern::ThreadDesWrite(iClientThread, info.iData, dataDes, 0, KChunkShiftBy0, iClientThread); |
|
1490 |
|
1491 Kern::Free(data); |
|
1492 |
|
1493 return err; |
|
1494 } |
|
1495 |
|
1496 // |
|
1497 // DMetroTrkChannel::WriteMemory |
|
1498 // |
|
1499 TInt DMetroTrkChannel::WriteMemory(DThread* aThread, TMetroTrkMemoryInfo* aMemoryInfo) |
|
1500 { |
|
1501 LOG_MSG("DMetroTrkChannel::WriteMemory()"); |
|
1502 |
|
1503 TInt err = KErrNone; |
|
1504 |
|
1505 if (!aMemoryInfo) |
|
1506 return KErrArgument; |
|
1507 |
|
1508 #ifndef __OEM_TRK__ |
|
1509 if (!IsBeingDebugged(aThread)) |
|
1510 return KErrPermissionDenied; |
|
1511 #endif |
|
1512 |
|
1513 TMetroTrkMemoryInfo info(0, 0, 0); |
|
1514 err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TMetroTrkMemoryInfo)); |
|
1515 if (err != KErrNone) |
|
1516 return err; |
|
1517 |
|
1518 if (!info.iData) |
|
1519 return KErrArgument; |
|
1520 |
|
1521 TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); |
|
1522 if (!data) |
|
1523 return KErrNoMemory; |
|
1524 |
|
1525 TPtr8 dataDes(data, info.iLength); |
|
1526 |
|
1527 err = Kern::ThreadDesRead(iClientThread, info.iData, dataDes, 0); |
|
1528 if (err != KErrNone) |
|
1529 return err; |
|
1530 |
|
1531 err = DoWriteMemory(aThread, info.iAddress, info.iLength, dataDes); |
|
1532 |
|
1533 Kern::Free(data); |
|
1534 |
|
1535 return err; |
|
1536 } |
|
1537 |
|
1538 // |
|
1539 // DMetroTrkChannel::ReadRegisters |
|
1540 // |
|
1541 TInt DMetroTrkChannel::ReadRegisters(DThread* aThread, TMetroTrkRegisterInfo* aRegisterInfo) |
|
1542 { |
|
1543 LOG_MSG("DMetroTrkChannel::ReadRegisters()"); |
|
1544 |
|
1545 TInt err = KErrNone; |
|
1546 |
|
1547 if (!aRegisterInfo) |
|
1548 return KErrArgument; |
|
1549 |
|
1550 #ifndef __OEM_TRK__ |
|
1551 if (!IsBeingDebugged(aThread)) |
|
1552 return KErrPermissionDenied; |
|
1553 #endif |
|
1554 |
|
1555 TMetroTrkRegisterInfo info(0, 0, 0); |
|
1556 err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TMetroTrkRegisterInfo)); |
|
1557 if (err != KErrNone) |
|
1558 return err; |
|
1559 |
|
1560 if (!info.iValues) |
|
1561 return KErrArgument; |
|
1562 |
|
1563 TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; |
|
1564 TUint8 *values = (TUint8*)Kern::Alloc(length); |
|
1565 if (!values) |
|
1566 return KErrNoMemory; |
|
1567 |
|
1568 TPtr8 valuesDes(values, length); |
|
1569 |
|
1570 err = DoReadRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); |
|
1571 if (err != KErrNone) |
|
1572 return err; |
|
1573 |
|
1574 err = Kern::ThreadDesWrite(iClientThread, info.iValues, valuesDes, 0, KChunkShiftBy0, iClientThread); |
|
1575 |
|
1576 Kern::Free(values); |
|
1577 |
|
1578 return err; |
|
1579 } |
|
1580 |
|
1581 // |
|
1582 // DMetroTrkChannel::WriteRegisters |
|
1583 // |
|
1584 TInt DMetroTrkChannel::WriteRegisters(DThread* aThread, TMetroTrkRegisterInfo* aRegisterInfo) |
|
1585 { |
|
1586 LOG_MSG("DMetroTrkChannel::WriteRegisters()"); |
|
1587 |
|
1588 TInt err = KErrNone; |
|
1589 |
|
1590 if (!aRegisterInfo) |
|
1591 return KErrArgument; |
|
1592 |
|
1593 #ifndef __OEM_TRK__ |
|
1594 if (!IsBeingDebugged(aThread)) |
|
1595 return KErrPermissionDenied; |
|
1596 #endif |
|
1597 |
|
1598 TMetroTrkRegisterInfo info(0, 0, 0); |
|
1599 err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TMetroTrkRegisterInfo)); |
|
1600 if (err != KErrNone) |
|
1601 return err; |
|
1602 |
|
1603 if (!info.iValues) |
|
1604 return KErrArgument; |
|
1605 |
|
1606 TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; |
|
1607 |
|
1608 TUint8 *values = (TUint8*)Kern::Alloc(length); |
|
1609 if (!values) |
|
1610 return KErrNoMemory; |
|
1611 |
|
1612 TPtr8 valuesDes(values, length); |
|
1613 |
|
1614 err = Kern::ThreadDesRead(iClientThread, info.iValues, valuesDes, 0); |
|
1615 if (err != KErrNone) |
|
1616 return err; |
|
1617 |
|
1618 err = DoWriteRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); |
|
1619 |
|
1620 Kern::Free(values); |
|
1621 |
|
1622 return err; |
|
1623 } |
|
1624 |
|
1625 // |
|
1626 // DMetroTrkChannel::GetProcessInfo |
|
1627 // |
|
1628 TInt DMetroTrkChannel::GetProcessInfo(TInt aIndex, TMetroTrkTaskInfo* aTaskInfo) |
|
1629 { |
|
1630 LOG_MSG("DMetroTrkChannel::GetProcessInfo()"); |
|
1631 |
|
1632 TInt err = KErrNone; |
|
1633 |
|
1634 if (!aTaskInfo) |
|
1635 return KErrArgument; |
|
1636 |
|
1637 TMetroTrkTaskInfo info(0); |
|
1638 |
|
1639 err = DoGetProcessInfo(aIndex, &info); |
|
1640 |
|
1641 if (err != KErrNone) |
|
1642 return err; |
|
1643 |
|
1644 err = Kern::ThreadRawWrite(iClientThread, aTaskInfo, &info, sizeof(TMetroTrkTaskInfo), iClientThread); |
|
1645 |
|
1646 return err; |
|
1647 } |
|
1648 |
|
1649 // |
|
1650 // DMetroTrkChannel::GetThreadInfo |
|
1651 // |
|
1652 TInt DMetroTrkChannel::GetThreadInfo(TInt aIndex, TMetroTrkTaskInfo* aTaskInfo) |
|
1653 { |
|
1654 LOG_MSG("DMetroTrkChannel::GetThreadInfo()"); |
|
1655 |
|
1656 TInt err = KErrNone; |
|
1657 |
|
1658 if (!aTaskInfo) |
|
1659 return KErrArgument; |
|
1660 |
|
1661 TMetroTrkTaskInfo info(0); |
|
1662 err = Kern::ThreadRawRead(iClientThread, aTaskInfo, (TUint8*)&info, sizeof(TMetroTrkTaskInfo)); |
|
1663 if (err != KErrNone) |
|
1664 return err; |
|
1665 |
|
1666 err = DoGetThreadInfo(aIndex, &info); |
|
1667 |
|
1668 if (err != KErrNone) |
|
1669 return err; |
|
1670 |
|
1671 err = Kern::ThreadRawWrite(iClientThread, aTaskInfo, &info, sizeof(TMetroTrkTaskInfo), iClientThread); |
|
1672 |
|
1673 return err; |
|
1674 } |
|
1675 |
|
1676 // |
|
1677 // DMetroTrkChannel::GetProcessAddresses |
|
1678 // |
|
1679 TInt DMetroTrkChannel::GetProcessAddresses(DThread* aThread, TMetroTrkProcessInfo* aProcessInfo) |
|
1680 { |
|
1681 LOG_MSG("DMetroTrkChannel::GetProcessAddresses()"); |
|
1682 |
|
1683 TInt err = KErrNone; |
|
1684 |
|
1685 if (!aProcessInfo) |
|
1686 return KErrArgument; |
|
1687 |
|
1688 TMetroTrkProcessInfo info(0, 0); |
|
1689 err = Kern::ThreadRawRead(iClientThread, aProcessInfo, (TUint8*)&info, sizeof(TMetroTrkProcessInfo)); |
|
1690 |
|
1691 if (err != KErrNone) |
|
1692 return err; |
|
1693 |
|
1694 if (!info.iCodeAddress || !info.iDataAddress) |
|
1695 return KErrArgument; |
|
1696 |
|
1697 TUint32 codeAddress; |
|
1698 TUint32 dataAddress; |
|
1699 |
|
1700 err = DoGetProcessAddresses(aThread, codeAddress, dataAddress); |
|
1701 |
|
1702 if (err != KErrNone) |
|
1703 return err; |
|
1704 |
|
1705 err = Kern::ThreadRawWrite(iClientThread, info.iCodeAddress, (TUint8*)&codeAddress, sizeof(TUint32), iClientThread); |
|
1706 err = Kern::ThreadRawWrite(iClientThread, info.iDataAddress, (TUint8*)&dataAddress, sizeof(TUint32), iClientThread); |
|
1707 |
|
1708 return err; |
|
1709 } |
|
1710 |
|
1711 // |
|
1712 // DMetroTrkChannel::GetStaticLibraryInfo |
|
1713 // |
|
1714 TInt DMetroTrkChannel::GetStaticLibraryInfo(TInt aIndex, SEventInfo* aEventInfo) |
|
1715 { |
|
1716 LOG_MSG("DMetroTrkChannel::GetStaticLibraryInfo()"); |
|
1717 |
|
1718 TInt err = KErrNone; |
|
1719 |
|
1720 if (!aEventInfo) |
|
1721 return KErrArgument; |
|
1722 |
|
1723 SEventInfo info; |
|
1724 |
|
1725 err = Kern::ThreadRawRead(iClientThread, aEventInfo, (TUint8*)&info, sizeof(SEventInfo)); |
|
1726 |
|
1727 if (err != KErrNone) |
|
1728 return err; |
|
1729 |
|
1730 err = DoGetStaticLibraryInfo(aIndex, &info); |
|
1731 |
|
1732 if (err != KErrNone) |
|
1733 return err; |
|
1734 |
|
1735 err = Kern::ThreadRawWrite(iClientThread, aEventInfo, &info, sizeof(SEventInfo), iClientThread); |
|
1736 |
|
1737 return err; |
|
1738 } |
|
1739 |
|
1740 // |
|
1741 // DMetroTrkChannel::GetLibInfo |
|
1742 // |
|
1743 TInt DMetroTrkChannel::GetLibraryInfo(TMetroTrkLibInfo* aLibInfo) |
|
1744 { |
|
1745 LOG_MSG("DMetroTrkChannel::GetLibraryInfo()"); |
|
1746 |
|
1747 TInt err = KErrNone; |
|
1748 |
|
1749 if (!aLibInfo) |
|
1750 return KErrArgument; |
|
1751 |
|
1752 TMetroTrkLibInfo info(0, 0); |
|
1753 |
|
1754 err = Kern::ThreadRawRead(iClientThread, aLibInfo, (TUint8*)&info, sizeof(TMetroTrkLibInfo)); |
|
1755 |
|
1756 if (err != KErrNone) |
|
1757 return err; |
|
1758 |
|
1759 if (!info.iFileName) |
|
1760 return KErrArgument; |
|
1761 |
|
1762 TUint8 *dllName = (TUint8*)Kern::Alloc(info.iFileNameLength); |
|
1763 if (!dllName) |
|
1764 return KErrNoMemory; |
|
1765 |
|
1766 TPtr8 dllNameDes(dllName, info.iFileNameLength); |
|
1767 |
|
1768 err = Kern::ThreadDesRead(iClientThread, info.iFileName, dllNameDes, 0); |
|
1769 if (!err) |
|
1770 { |
|
1771 err = DoGetLibraryInfo(dllNameDes, &info); |
|
1772 |
|
1773 if (!err) |
|
1774 err = Kern::ThreadRawWrite(iClientThread, aLibInfo, &info, sizeof(TMetroTrkLibInfo), iClientThread); |
|
1775 |
|
1776 // we couldn't find the library info, so add to our list to look for |
|
1777 // when a library is loaded or a process is loaded. |
|
1778 if (err != KErrNone) |
|
1779 { |
|
1780 for (TInt i=0; i<NUMBER_OF_LIBS_TO_REGISTER; i++) |
|
1781 { |
|
1782 if (!iLibraryNotifyList[i].iName.Length() && iLibraryNotifyList[i].iEmptySlot) |
|
1783 { |
|
1784 iLibraryNotifyList[i].iName.Copy(dllNameDes); |
|
1785 iLibraryNotifyList[i].iEmptySlot = EFalse; |
|
1786 break; |
|
1787 } |
|
1788 else if (!iLibraryNotifyList[i].iEmptySlot && !_strnicmp(iLibraryNotifyList[i].iName.Ptr(), dllNameDes.Ptr(), dllNameDes.Length())) |
|
1789 { |
|
1790 break; |
|
1791 } |
|
1792 } |
|
1793 } |
|
1794 } |
|
1795 |
|
1796 // now free the allocated memory |
|
1797 Kern::Free(dllName); |
|
1798 |
|
1799 return err; |
|
1800 } |
|
1801 |
|
1802 // |
|
1803 // DMetroTrkChannel::GetExeInfo |
|
1804 // |
|
1805 TInt DMetroTrkChannel::GetExeInfo(TMetroTrkExeInfo* aExeInfo) |
|
1806 { |
|
1807 LOG_MSG("DMetroTrkChannel::GetExeInfo()"); |
|
1808 |
|
1809 TInt err = KErrNone; |
|
1810 |
|
1811 if (!aExeInfo) |
|
1812 return KErrArgument; |
|
1813 |
|
1814 TMetroTrkExeInfo info(0, 0, 0); |
|
1815 |
|
1816 err = Kern::ThreadRawRead(iClientThread, aExeInfo, (TUint8*)&info, sizeof(TMetroTrkExeInfo)); |
|
1817 |
|
1818 if (err != KErrNone) |
|
1819 return err; |
|
1820 |
|
1821 if (!info.iFileName) |
|
1822 return KErrArgument; |
|
1823 |
|
1824 TUint8 *exeName = (TUint8*)Kern::Alloc(info.iFileNameLength); |
|
1825 if (!exeName) |
|
1826 return KErrNoMemory; |
|
1827 |
|
1828 TPtr8 exeNameDes(exeName, info.iFileNameLength); |
|
1829 |
|
1830 err = Kern::ThreadDesRead(iClientThread, info.iFileName, exeNameDes, 0); |
|
1831 if (KErrNone == err) |
|
1832 { |
|
1833 err = DoGetExeInfo(exeNameDes, &info); |
|
1834 if (KErrNone == err) |
|
1835 { |
|
1836 err = Kern::ThreadRawWrite(iClientThread, aExeInfo, &info, sizeof(TMetroTrkExeInfo), iClientThread); |
|
1837 } |
|
1838 } |
|
1839 |
|
1840 Kern::Free(exeName); |
|
1841 |
|
1842 return err; |
|
1843 } |
|
1844 |
|
1845 // |
|
1846 // DMetroTrkChannel::GetProcUidInfo |
|
1847 // |
|
1848 TInt DMetroTrkChannel::GetProcUidInfo(TMetroTrkProcUidInfo* aProcUidInfo) |
|
1849 { |
|
1850 LOG_MSG("DMetroTrkChannel::GetProcUidInfo()"); |
|
1851 |
|
1852 TInt err = KErrNone; |
|
1853 |
|
1854 if (!aProcUidInfo) |
|
1855 return KErrArgument; |
|
1856 |
|
1857 TMetroTrkProcUidInfo info(0); |
|
1858 |
|
1859 err = Kern::ThreadRawRead(iClientThread, aProcUidInfo, (TUint8*)&info, sizeof(TMetroTrkProcUidInfo)); |
|
1860 |
|
1861 if (err != KErrNone) |
|
1862 return err; |
|
1863 |
|
1864 err = DoGetProcUidInfo(&info); |
|
1865 |
|
1866 if (err != KErrNone) |
|
1867 return err; |
|
1868 |
|
1869 err = Kern::ThreadRawWrite(iClientThread, aProcUidInfo, &info, sizeof(TMetroTrkProcUidInfo), iClientThread); |
|
1870 |
|
1871 return err; |
|
1872 } |
|
1873 |
|
1874 // |
|
1875 //DMetroTrkChannel::DetachProcess |
|
1876 // |
|
1877 TInt DMetroTrkChannel::DetachProcess(DProcess *aProcess) |
|
1878 { |
|
1879 LOG_MSG("DMetroTrkChannel::DetachProcess()"); |
|
1880 // check to see if we are still debugging, otherwise just return |
|
1881 if (!iDebugging || !aProcess) |
|
1882 return KErrArgument; |
|
1883 |
|
1884 // This is called when a process has been detached. |
|
1885 // We want to mark any breakpoints in this process space as clear. |
|
1886 TUint32 codeAddress = 0; |
|
1887 TUint32 codeSize = 0; |
|
1888 |
|
1889 LOG_MSG2("Process being Detached, Name %S", aProcess->iName); |
|
1890 |
|
1891 // make sure there is not already a breakpoint at this address |
|
1892 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
1893 { |
|
1894 if (iDebugProcessList[i].iId == aProcess->iId) |
|
1895 { |
|
1896 codeAddress = iDebugProcessList[i].iCodeAddress; |
|
1897 codeSize = iDebugProcessList[i].iCodeSize; |
|
1898 //now remove from the list |
|
1899 iDebugProcessList.Remove(i); |
|
1900 break; |
|
1901 } |
|
1902 } |
|
1903 |
|
1904 if (!codeAddress || !codeSize) |
|
1905 return KErrArgument; |
|
1906 |
|
1907 // first invalidate all breakpoints that were set in the library code |
|
1908 for (TInt i=0; i<iBreakPointList.Count(); i++) |
|
1909 { |
|
1910 if ((iBreakPointList[i].iAddress >= codeAddress) && (iBreakPointList[i].iAddress < (codeAddress + codeSize))) |
|
1911 { |
|
1912 LOG_MSG2("Clearing process breakpoint at address %x", iBreakPointList[i].iAddress); |
|
1913 // clear the break here |
|
1914 TInt32 err = KErrNone; |
|
1915 err = DoClearBreak(iBreakPointList[i].iId); |
|
1916 |
|
1917 //If not able to clear the break point host debugger make obselete. |
|
1918 if (KErrNone != err) |
|
1919 { |
|
1920 LOG_MSG2("Clearing process breakpoint at address %x failed", iBreakPointList[i].iAddress); |
|
1921 } |
|
1922 } |
|
1923 } |
|
1924 |
|
1925 return KErrNone; |
|
1926 } |
|
1927 |
|
1928 |
|
1929 // |
|
1930 // DMetroTrkChannel::DoSetBreak |
|
1931 // |
|
1932 TInt DMetroTrkChannel::DoSetBreak(const TUint32 aProcessId, const TUint32 aThreadId, const TUint32 aAddress, const TBool aThumbMode, TInt32 &aId) |
|
1933 { |
|
1934 LOG_MSG("DMetroTrkChannel::DoSetBreak()"); |
|
1935 |
|
1936 // do not allow breakpoints in the excluded ROM region |
|
1937 //if ((aAddress >= iExcludedROMAddressStart) && (aAddress < iExcludedROMAddressEnd)) |
|
1938 //{ |
|
1939 // return KErrNotSupported; |
|
1940 //} |
|
1941 |
|
1942 // make sure there is not already a breakpoint at this address |
|
1943 for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) |
|
1944 { |
|
1945 if (iBreakPointList[i].iAddress == aAddress) |
|
1946 { |
|
1947 return KErrAlreadyExists; |
|
1948 } |
|
1949 } |
|
1950 |
|
1951 // increment the break id |
|
1952 aId = iNextBreakId++; |
|
1953 |
|
1954 // create the new breakpoint entry |
|
1955 TBreakEntry breakEntry(aId, aThreadId, aAddress, aThumbMode); |
|
1956 |
|
1957 // IDE currently sends non-thread specific breakpoints (threadId == 0xffffffff) |
|
1958 // if this changes, we will get a real thread ID |
|
1959 // This check must be done before calling DoEnableBreak as it will replace the |
|
1960 // the breakentry threadId with a real one |
|
1961 if (aThreadId == 0xFFFFFFFF) |
|
1962 { |
|
1963 breakEntry.iThreadSpecific = EFalse; |
|
1964 breakEntry.iThreadId = aProcessId+1; //process wide break, just use the main thread id for this process |
|
1965 } |
|
1966 else |
|
1967 { |
|
1968 breakEntry.iThreadSpecific = ETrue; |
|
1969 } |
|
1970 |
|
1971 TInt err = DoEnableBreak(breakEntry, ETrue); |
|
1972 |
|
1973 if (KErrNone == err) |
|
1974 { |
|
1975 ReturnIfError(iBreakPointList.Append(breakEntry)); |
|
1976 } |
|
1977 |
|
1978 return err; |
|
1979 } |
|
1980 |
|
1981 |
|
1982 // |
|
1983 // DMetroTrkChannel::DoEnableBreak |
|
1984 // |
|
1985 TInt DMetroTrkChannel::DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction) |
|
1986 { |
|
1987 LOG_MSG("DMetroTrkChannel::DoEnableBreak()"); |
|
1988 |
|
1989 // default to arm mode |
|
1990 TUint32 inst = KArmBreakPoint; |
|
1991 TInt instSize = 4; |
|
1992 |
|
1993 if (aEntry.iThumbMode) |
|
1994 { |
|
1995 LOG_MSG("Thumb Breakpoint"); |
|
1996 inst = KThumbBreakPoint; |
|
1997 instSize = 2; |
|
1998 } |
|
1999 |
|
2000 TInt err = KErrNone; |
|
2001 |
|
2002 // Get thread id from the process that we are debugging |
|
2003 TProcessInfo * proc = NULL; |
|
2004 TUint32 threadId = NULL; |
|
2005 |
|
2006 threadId = aEntry.iThreadId; |
|
2007 |
|
2008 if (!threadId || threadId==0xFFFFFFFF) //threadId=0xFFFFFFFF is special case with CW debugger. |
|
2009 { |
|
2010 for (TInt i=0; i<iDebugProcessList.Count(); i++) |
|
2011 { |
|
2012 proc = &iDebugProcessList[i]; |
|
2013 if ( proc && (proc->iCodeAddress <= aEntry.iAddress) && (aEntry.iAddress <= (proc->iCodeAddress + proc->iCodeSize))) |
|
2014 { |
|
2015 threadId = proc->iId+1; |
|
2016 break; |
|
2017 } |
|
2018 } |
|
2019 } |
|
2020 |
|
2021 DThread* threadObj = ThreadFromId(threadId); |
|
2022 //if we don't have the right thread id for the address, |
|
2023 //then try with the thread id of the process that we are debugging |
|
2024 if (!threadObj && iDebugProcessList.Count()) |
|
2025 { |
|
2026 proc = &iDebugProcessList[0]; |
|
2027 if (proc) |
|
2028 { |
|
2029 threadId = proc->iId+1; |
|
2030 } |
|
2031 threadObj = ThreadFromId(threadId); |
|
2032 } |
|
2033 |
|
2034 if (threadObj) |
|
2035 { |
|
2036 if (aSaveOldInstruction) |
|
2037 { |
|
2038 TUint32 instruction; |
|
2039 |
|
2040 // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint |
|
2041 // trap exceptions in case the address is invalid |
|
2042 XTRAPD(r, XT_DEFAULT, err = TryToReadMemory(threadObj, (TAny *)aEntry.iAddress, (TAny *)&instruction, instSize)); |
|
2043 |
|
2044 ReturnIfError((KErrNone == r) ? err : r); |
|
2045 |
|
2046 aEntry.iInstruction.Copy((TUint8 *)&instruction, instSize); |
|
2047 } |
|
2048 |
|
2049 aEntry.iThreadId = threadId; //set the thread ID here |
|
2050 XTRAPD(r, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, aEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal)); |
|
2051 err = (DebugSupport::EBreakpointGlobal == r) ? KErrNone : r; |
|
2052 } |
|
2053 else |
|
2054 { |
|
2055 err = KErrBadHandle; |
|
2056 } |
|
2057 |
|
2058 |
|
2059 return err; |
|
2060 } |
|
2061 |
|
2062 // |
|
2063 // DMetroTrkChannel::DoClearBreak |
|
2064 // |
|
2065 TInt DMetroTrkChannel::DoClearBreak(const TInt32 aId) |
|
2066 { |
|
2067 LOG_MSG("DMetroTrkChannel::DoClearBreak()"); |
|
2068 |
|
2069 // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id |
|
2070 TBreakEntry entry; |
|
2071 entry.iId = aId; |
|
2072 TInt index = iBreakPointList.FindInSignedKeyOrder(entry); |
|
2073 |
|
2074 TInt err = KErrNone; |
|
2075 if (index >= 0) |
|
2076 { |
|
2077 // if this breakpoint was set in a library and that library has already been unloaded, don't try to clear it |
|
2078 if (!iBreakPointList[index].iObsoleteLibraryBreakpoint) |
|
2079 { |
|
2080 LOG_MSG2("Clearing breakpoint at address %x", iBreakPointList[index].iAddress); |
|
2081 |
|
2082 DThread* threadObj = ThreadFromId(iBreakPointList[index].iThreadId); |
|
2083 // In case of multiple memory model, if the thread doesn't exist any more, don't try to clear it. |
|
2084 // For example it might be in a static library which was unloaded when the thread exited, |
|
2085 // but we didn't get told so we didn't mark it as iObsoleteLibraryBreakpoint. |
|
2086 if (threadObj != NULL) |
|
2087 { |
|
2088 XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress)); |
|
2089 err = (KErrNone == r) ? err : r; |
|
2090 |
|
2091 } |
|
2092 else |
|
2093 { |
|
2094 err = KErrBadHandle; |
|
2095 } |
|
2096 } |
|
2097 |
|
2098 if (KErrNone == err) |
|
2099 { |
|
2100 // if this is a temp breakpoint, just clear out the values, otherwise remove it from the list |
|
2101 if (index < NUMBER_OF_TEMP_BREAKPOINTS) |
|
2102 { |
|
2103 iBreakPointList[index].Reset(); |
|
2104 } |
|
2105 else |
|
2106 { |
|
2107 iBreakPointList.Remove(index); |
|
2108 } |
|
2109 } |
|
2110 else |
|
2111 { |
|
2112 LOG_MSG2("Error clearing breakpoint %d", err); |
|
2113 } |
|
2114 |
|
2115 return err; |
|
2116 } |
|
2117 |
|
2118 LOG_MSG2("Break Id %d not found", aId); |
|
2119 |
|
2120 return KErrNotFound; |
|
2121 } |
|
2122 |
|
2123 |
|
2124 // |
|
2125 // DMetroTrkChannel::DoChangeBreakThread |
|
2126 // |
|
2127 TInt DMetroTrkChannel::DoChangeBreakThread(TUint32 aThreadId, TInt32 aId) |
|
2128 { |
|
2129 LOG_MSG("DMetroTrkChannel::DoChangeBreakThread()"); |
|
2130 |
|
2131 // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id |
|
2132 TBreakEntry entry; |
|
2133 entry.iId = aId; |
|
2134 TInt index = iBreakPointList.FindInSignedKeyOrder(entry); |
|
2135 |
|
2136 if (index >=0) |
|
2137 { |
|
2138 // change the thread id for this breakpoint |
|
2139 iBreakPointList[index].iThreadId = aThreadId; |
|
2140 return KErrNone; |
|
2141 } |
|
2142 |
|
2143 return KErrNotFound; |
|
2144 } |
|
2145 |
|
2146 // |
|
2147 // DMetroTrkChannel::DoSuspendThread |
|
2148 // |
|
2149 TInt DMetroTrkChannel::DoSuspendThread(DThread *aThread) |
|
2150 { |
|
2151 LOG_MSG("DMetroTrkChannel::DoSuspendThread()"); |
|
2152 |
|
2153 if (!aThread) |
|
2154 { |
|
2155 LOG_MSG("Invalid dthread object"); |
|
2156 return KErrArgument; |
|
2157 } |
|
2158 |
|
2159 NThread nThread = aThread->iNThread; |
|
2160 |
|
2161 if (nThread.iSuspendCount == 0) |
|
2162 Kern::ThreadSuspend(*aThread, 1); |
|
2163 |
|
2164 return KErrNone; |
|
2165 } |
|
2166 |
|
2167 // |
|
2168 // DMetroTrkChannel::DoResumeThread |
|
2169 // |
|
2170 TInt DMetroTrkChannel::DoResumeThread(DThread *aThread) |
|
2171 { |
|
2172 LOG_MSG("DMetroTrkChannel::DoResumeThread()"); |
|
2173 |
|
2174 if (!aThread) |
|
2175 return KErrArgument; |
|
2176 |
|
2177 // get the current PC |
|
2178 TUint32 currentPC = ReadRegister(aThread, PC_REGISTER); |
|
2179 |
|
2180 // if there is a breakpoint at the current PC, we need to single step past it |
|
2181 for (TInt i=NUMBER_OF_TEMP_BREAKPOINTS; i<iBreakPointList.Count(); i++) |
|
2182 { |
|
2183 if (iBreakPointList[i].iAddress == currentPC) |
|
2184 { |
|
2185 return DoStepRange(aThread, currentPC, currentPC+1, ETrue, ETrue); |
|
2186 } |
|
2187 } |
|
2188 |
|
2189 // PANIC_BACKPORT |
|
2190 // if frozen use semaphore |
|
2191 for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++) |
|
2192 { |
|
2193 if(iFrozenThreadSemaphores[i]->iOwningThread == &aThread->iNThread) |
|
2194 { |
|
2195 NKern::FSSignal(iFrozenThreadSemaphores[i]); |
|
2196 NKern::ThreadEnterCS(); |
|
2197 delete iFrozenThreadSemaphores[i]; |
|
2198 NKern::ThreadLeaveCS(); |
|
2199 iFrozenThreadSemaphores.Remove(i); |
|
2200 return KErrNone; |
|
2201 } |
|
2202 } |
|
2203 // END PANIC_BACKPORT |
|
2204 |
|
2205 // else use ThreadResume |
|
2206 Kern::ThreadResume(*aThread); |
|
2207 |
|
2208 return KErrNone; |
|
2209 } |
|
2210 |
|
2211 // |
|
2212 // DMetroTrkChannel::DoStepRange |
|
2213 // |
|
2214 TInt DMetroTrkChannel::DoStepRange(DThread *aThread, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto, TBool aResumeOnceOutOfRange, TBool aUserRequest) |
|
2215 { |
|
2216 LOG_MSG("DMetroTrkChannel::DoStepRange()"); |
|
2217 |
|
2218 if (!aThread) |
|
2219 return KErrArgument; |
|
2220 |
|
2221 TUint32 startAddress = (aStartAddress & 0x1) ? aStartAddress + 1 : aStartAddress; |
|
2222 TUint32 stopAddress = (aStopAddress & 0x1) ? aStopAddress + 1 : aStopAddress; |
|
2223 |
|
2224 // don't allow the user to step in the excluded ROM region. this could be called |
|
2225 // internally however. for example, the the special breakpoints we set to handle |
|
2226 // panics, exceptions, and library loaded events are in the user library, and we |
|
2227 // will need to step past the breakpoint before continuing the thread. |
|
2228 //if (aUserRequest && (startAddress >= iExcludedROMAddressStart) && (startAddress < iExcludedROMAddressEnd)) |
|
2229 //{ |
|
2230 // return KErrNotSupported; |
|
2231 //} |
|
2232 |
|
2233 // set the temp breakpoint, and disable the breakpoint at the current PC if necessary |
|
2234 // if its not a user request, and we are just trying to resume from a breakpoint, |
|
2235 // then we don't need to check for stubs. The last parameter aUserRequest tells |
|
2236 // ModifyBreaksForStep to check for stubs or not. In some cases, the check for stubs |
|
2237 // is true even if its not a user request.For example, this is true in cases where |
|
2238 // we are doing a step range and the instruction in the range modified PC. |
|
2239 // in this case, DoStepRange will be called from the exception handler where |
|
2240 // we need to check for the stubs for the valid behavior. So truly, we don't need to check |
|
2241 // for stubs only when resuming from a breakpoint. |
|
2242 ReturnIfError(ModifyBreaksForStep(aThread, startAddress, stopAddress, aStepInto, aResumeOnceOutOfRange, aUserRequest)); |
|
2243 |
|
2244 // PANIC_BACKPORT |
|
2245 // if frozen use semaphore |
|
2246 for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++) |
|
2247 { |
|
2248 if(iFrozenThreadSemaphores[i]->iOwningThread == &aThread->iNThread) |
|
2249 { |
|
2250 NKern::FSSignal(iFrozenThreadSemaphores[i]); |
|
2251 NKern::ThreadEnterCS(); |
|
2252 delete iFrozenThreadSemaphores[i]; |
|
2253 NKern::ThreadLeaveCS(); |
|
2254 iFrozenThreadSemaphores.Remove(i); |
|
2255 return KErrNone; |
|
2256 } |
|
2257 } |
|
2258 |
|
2259 // END PANIC_BACKPORT |
|
2260 // else use ThreadResume |
|
2261 Kern::ThreadResume(*aThread); |
|
2262 |
|
2263 return KErrNone; |
|
2264 } |
|
2265 |
|
2266 // |
|
2267 // DMetroTrkChannel::DoReadMemory |
|
2268 // |
|
2269 TInt DMetroTrkChannel::DoReadMemory(DThread *aThread, const TUint32 aAddress, const TInt16 aLength, TDes8 &aData) |
|
2270 { |
|
2271 LOG_MSG("DMetroTrkChannel::DoReadMemory()"); |
|
2272 |
|
2273 // make sure the parameters are valid |
|
2274 if (aLength > aData.MaxSize()) |
|
2275 return KErrArgument; |
|
2276 |
|
2277 TInt err = KErrNone; |
|
2278 |
|
2279 // trap exceptions in case the address is invalid |
|
2280 XTRAPD(r, XT_DEFAULT, err = TryToReadMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); |
|
2281 |
|
2282 err = (KErrNone == r) ? err : r; |
|
2283 |
|
2284 if (KErrNone == err) |
|
2285 { |
|
2286 aData.SetLength(aLength); |
|
2287 |
|
2288 TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); |
|
2289 |
|
2290 // if we have any breakpoints in this range, put the actual instruction in the buffer |
|
2291 for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) |
|
2292 { |
|
2293 if ((iBreakPointList[i].iAddress >= aAddress) && (iBreakPointList[i].iAddress < (aAddress + aLength))) |
|
2294 { |
|
2295 TInt instSize = (TInt)(iBreakPointList[i].iThumbMode ? 2 : 4); |
|
2296 memcpy((TAny*)&data[iBreakPointList[i].iAddress - aAddress], (TAny *)iBreakPointList[i].iInstruction.Ptr(), instSize); |
|
2297 } |
|
2298 } |
|
2299 } |
|
2300 |
|
2301 return err; |
|
2302 } |
|
2303 |
|
2304 // |
|
2305 // DMetroTrkChannel::DoWriteMemory |
|
2306 // |
|
2307 TInt DMetroTrkChannel::DoWriteMemory(DThread *aThread, const TUint32 aAddress, const TInt16 aLength, TDes8 &aData) |
|
2308 { |
|
2309 LOG_MSG("DMetroTrkChannel::DoWriteMemory()"); |
|
2310 |
|
2311 // make sure the parameters are valid |
|
2312 if (aLength > aData.Length()) |
|
2313 return KErrArgument; |
|
2314 |
|
2315 TInt err = KErrNone; |
|
2316 |
|
2317 // trap exceptions in case the address is invalid |
|
2318 XTRAPD(r, XT_DEFAULT, err = TryToWriteMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); |
|
2319 |
|
2320 err = (KErrNone == r) ? err : r; |
|
2321 |
|
2322 // reset any breakpoints we may have just overwritten |
|
2323 if (KErrNone == err) |
|
2324 { |
|
2325 TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); |
|
2326 |
|
2327 for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) |
|
2328 { |
|
2329 if ((iBreakPointList[i].iAddress >= aAddress) && (iBreakPointList[i].iAddress < (aAddress + aLength))) |
|
2330 { |
|
2331 // default to arm mode |
|
2332 TUint32 inst = KArmBreakPoint; |
|
2333 TInt instSize = 4; |
|
2334 |
|
2335 if (iBreakPointList[i].iThumbMode) |
|
2336 { |
|
2337 inst = KThumbBreakPoint; |
|
2338 instSize = 2; |
|
2339 } |
|
2340 |
|
2341 iBreakPointList[i].iInstruction.Copy(&data[iBreakPointList[i].iAddress - aAddress], instSize); |
|
2342 //memcpy((TAny*)iBreakPointList[i].iAddress, (TAny *)&inst, instSize); |
|
2343 TryToWriteMemory(aThread, (TAny*)iBreakPointList[i].iAddress, (TAny *)&inst, instSize); |
|
2344 } |
|
2345 } |
|
2346 |
|
2347 } |
|
2348 |
|
2349 return err; |
|
2350 } |
|
2351 |
|
2352 // |
|
2353 // DMetroTrkChannel::DoReadRegisters |
|
2354 // |
|
2355 TInt DMetroTrkChannel::DoReadRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDes8 &aValues) |
|
2356 { |
|
2357 LOG_MSG("DMetroTrkChannel::DoReadRegisters()"); |
|
2358 |
|
2359 // make sure the parameters are valid |
|
2360 if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) |
|
2361 return KErrArgument; |
|
2362 |
|
2363 // make sure the descriptor is big enough to hold the requested data |
|
2364 if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.MaxSize())) |
|
2365 return KErrArgument; |
|
2366 |
|
2367 TArmRegSet regSet; |
|
2368 TUint32 unused; |
|
2369 |
|
2370 #ifdef SUPPORT_KERNCONTEXT |
|
2371 NKern::Lock(); // lock the kernel before callin UserContextType as its required by this function |
|
2372 NThread nThread = aThread->iNThread; |
|
2373 NThread::TUserContextType userContextType = nThread.UserContextType(); |
|
2374 NKern::Unlock(); //unlock the kernel now |
|
2375 |
|
2376 if (userContextType == NThread::EContextNone || userContextType == NThread::EContextKernel) |
|
2377 { |
|
2378 //NKern::ThreadGetSystemContext(&aThread->iNThread, ®Set, unused); |
|
2379 if (!GetSystemThreadRegisters(®Set)) |
|
2380 return KErrGeneral; |
|
2381 } |
|
2382 else |
|
2383 #endif |
|
2384 { |
|
2385 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); |
|
2386 } |
|
2387 |
|
2388 TArmReg *reg = ®Set.iR0; |
|
2389 |
|
2390 if (!reg) |
|
2391 return KErrGeneral; |
|
2392 |
|
2393 for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) |
|
2394 aValues.Append((TUint8 *)®[i], sizeof(TArmReg)); |
|
2395 |
|
2396 return KErrNone; |
|
2397 } |
|
2398 |
|
2399 // |
|
2400 // DMetroTrkChannel::DoWriteRegisters |
|
2401 // |
|
2402 TInt DMetroTrkChannel::DoWriteRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDesC8 &aValues) |
|
2403 { |
|
2404 LOG_MSG("DMetroTrkChannel::DoWriteRegisters()"); |
|
2405 |
|
2406 // make sure the parameters are valid |
|
2407 if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) |
|
2408 return KErrArgument; |
|
2409 |
|
2410 // make sure the descriptor is big enough to hold the data to write |
|
2411 if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.Length())) |
|
2412 return KErrArgument; |
|
2413 |
|
2414 TArmRegSet regSet; |
|
2415 TUint32 unused; |
|
2416 |
|
2417 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); |
|
2418 |
|
2419 TArmReg *reg = ®Set.iR0; |
|
2420 |
|
2421 for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) |
|
2422 { |
|
2423 #ifndef __OEM_TRK__ |
|
2424 if (IsRegisterSecure(i)) |
|
2425 return KErrNotSupported; |
|
2426 #endif |
|
2427 reg[i] = *(TUint32 *)&aValues[(i-aFirstRegister)*sizeof(TArmReg)]; |
|
2428 } |
|
2429 |
|
2430 |
|
2431 NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); |
|
2432 |
|
2433 return KErrNone; |
|
2434 } |
|
2435 |
|
2436 // |
|
2437 // DMetroTrkChannel::DoGetProcessInfo |
|
2438 // |
|
2439 TInt DMetroTrkChannel::DoGetProcessInfo(const TInt aIndex, TMetroTrkTaskInfo *aInfo) |
|
2440 { |
|
2441 LOG_MSG("DMetroTrkChannel::DoGetProcessInfo()"); |
|
2442 |
|
2443 DObjectCon *processes = Kern::Containers()[EProcess]; |
|
2444 if (!processes) |
|
2445 return KErrGeneral; |
|
2446 |
|
2447 TInt err = KErrNone; |
|
2448 |
|
2449 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
2450 processes->Wait(); // Obtain the container mutex so the list does get changed under us |
|
2451 |
|
2452 // make sure the index is valid |
|
2453 if ((aIndex >= 0) && (aIndex < processes->Count())) // >= because the index is zero based |
|
2454 { |
|
2455 DProcess *process = (DProcess *)((*processes)[aIndex]); |
|
2456 |
|
2457 if (process) |
|
2458 { |
|
2459 process->Name(aInfo->iName); |
|
2460 aInfo->iId = process->iId; |
|
2461 aInfo->iPriority = (TUint32)process->iPriority; |
|
2462 } |
|
2463 else |
|
2464 { |
|
2465 LOG_MSG2("Process %d not found", aIndex); |
|
2466 err = KErrArgument; |
|
2467 } |
|
2468 } |
|
2469 else |
|
2470 { |
|
2471 err = KErrArgument; |
|
2472 } |
|
2473 |
|
2474 processes->Signal(); |
|
2475 NKern::ThreadLeaveCS(); |
|
2476 |
|
2477 return err; |
|
2478 } |
|
2479 |
|
2480 // |
|
2481 // DMetroTrkChannel::DoGetThreadInfo |
|
2482 // |
|
2483 TInt DMetroTrkChannel::DoGetThreadInfo(const TInt aIndex, TMetroTrkTaskInfo *aInfo) |
|
2484 { |
|
2485 LOG_MSG("DMetroTrkChannel::DoGetThreadInfo()"); |
|
2486 |
|
2487 DObjectCon *threads = Kern::Containers()[EThread]; |
|
2488 if (!threads) |
|
2489 return KErrGeneral; |
|
2490 |
|
2491 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
2492 threads->Wait(); // Obtain the container mutex so the list does get changed under us |
|
2493 |
|
2494 TInt err = KErrNone; |
|
2495 if ((aIndex >= 0) && (aIndex < threads->Count())) |
|
2496 { |
|
2497 DThread *thread = NULL; |
|
2498 |
|
2499 TInt threadsForProcessCount = 0; |
|
2500 TBool found = EFalse; |
|
2501 |
|
2502 for (TInt i=0; i<threads->Count(); i++) |
|
2503 { |
|
2504 thread = (DThread *)((*threads)[i]); |
|
2505 |
|
2506 if (thread && (aInfo->iOtherId == thread->iOwningProcess->iId)) |
|
2507 { |
|
2508 if (threadsForProcessCount == aIndex) |
|
2509 { |
|
2510 thread->Name(aInfo->iName); |
|
2511 aInfo->iId = thread->iId; |
|
2512 aInfo->iPriority = (TUint32)thread->iThreadPriority; |
|
2513 found = ETrue; |
|
2514 break; |
|
2515 } |
|
2516 threadsForProcessCount++; |
|
2517 } |
|
2518 } |
|
2519 |
|
2520 if (!found) |
|
2521 { |
|
2522 LOG_MSG("Thread for process matching index not found"); |
|
2523 err = KErrArgument; |
|
2524 } |
|
2525 |
|
2526 } |
|
2527 else |
|
2528 { |
|
2529 err = KErrArgument; |
|
2530 } |
|
2531 |
|
2532 threads->Signal(); |
|
2533 NKern::ThreadLeaveCS(); |
|
2534 |
|
2535 return err; |
|
2536 } |
|
2537 |
|
2538 // |
|
2539 // DMetroTrkChannel::DoGetProcessAddresses |
|
2540 // |
|
2541 TInt DMetroTrkChannel::DoGetProcessAddresses(DThread *aThread, TUint32 &aCodeAddress, TUint32 &aDataAddress) |
|
2542 { |
|
2543 LOG_MSG("DMetroTrkChannel::DoGetProcessAddresses()"); |
|
2544 |
|
2545 if (!aThread) |
|
2546 return KErrArgument; |
|
2547 |
|
2548 #ifndef __OEM_TRK__ |
|
2549 if (HasManufacturerCaps(aThread)) |
|
2550 return KErrPermissionDenied; |
|
2551 #endif |
|
2552 |
|
2553 DProcess *process = (DProcess *)aThread->iOwningProcess; |
|
2554 |
|
2555 if (!process) |
|
2556 return KErrArgument; |
|
2557 |
|
2558 DCodeSeg* codeSeg = process->iCodeSeg; |
|
2559 if (!codeSeg) |
|
2560 return KErrArgument; |
|
2561 |
|
2562 TModuleMemoryInfo processMemoryInfo; |
|
2563 TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, process); |
|
2564 if (err != KErrNone) |
|
2565 return err; |
|
2566 |
|
2567 aCodeAddress = processMemoryInfo.iCodeBase; |
|
2568 aDataAddress = processMemoryInfo.iInitialisedDataBase; |
|
2569 |
|
2570 //add this process to the list of processes that we are debugging |
|
2571 TProcessInfo processInfo(process->iId, aCodeAddress, processMemoryInfo.iCodeSize, aDataAddress); |
|
2572 iDebugProcessList.Append(processInfo); |
|
2573 |
|
2574 return KErrNone; |
|
2575 } |
|
2576 |
|
2577 // |
|
2578 // DMetroTrkChannel::DoGetStaticLibraryInfo |
|
2579 // |
|
2580 |
|
2581 TInt DMetroTrkChannel::DoGetStaticLibraryInfo(const TInt aIndex, SEventInfo *aInfo) |
|
2582 { |
|
2583 LOG_MSG("DMetroTrkChannel::DoGetStaticLibraryInfo()"); |
|
2584 |
|
2585 if (!aInfo) |
|
2586 return KErrArgument; |
|
2587 |
|
2588 DThread *thread = ThreadFromId(aInfo->iThreadId); |
|
2589 |
|
2590 if (!thread) |
|
2591 return KErrArgument; |
|
2592 |
|
2593 DProcess *process = (DProcess *)thread->iOwningProcess; |
|
2594 |
|
2595 |
|
2596 if (!process) |
|
2597 return KErrArgument; |
|
2598 |
|
2599 |
|
2600 DCodeSeg *processCodeSeg = process->iCodeSeg; |
|
2601 |
|
2602 if (!processCodeSeg) |
|
2603 return KErrArgument; |
|
2604 |
|
2605 int count = processCodeSeg->iDepCount; |
|
2606 LOG_MSG2("code segment count %d", count); |
|
2607 |
|
2608 |
|
2609 if (aIndex < 0 || aIndex >= count) |
|
2610 return KErrArgument; |
|
2611 |
|
2612 DCodeSeg **codeSegList = processCodeSeg->iDeps; |
|
2613 if (!codeSegList) |
|
2614 return KErrArgument; |
|
2615 |
|
2616 DCodeSeg* codeSeg = codeSegList[aIndex]; |
|
2617 if (!codeSeg) |
|
2618 { |
|
2619 return KErrArgument; |
|
2620 } |
|
2621 if (!codeSeg->IsDll()) |
|
2622 { |
|
2623 LOG_MSG(" -- code segment is not for a dll"); |
|
2624 return KErrArgument; |
|
2625 } |
|
2626 TModuleMemoryInfo memoryInfo; |
|
2627 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); //NULL for DProcess should be ok; |
|
2628 if (err != KErrNone) |
|
2629 { |
|
2630 LOG_MSG2("Error in getting TModuleMemoryInfo info: %d", err); |
|
2631 return KErrArgument; |
|
2632 } |
|
2633 |
|
2634 aInfo->iEventType = SEventInfo::ELibraryLoaded; |
|
2635 aInfo->iFileName.Copy(*(codeSeg->iFileName)); //just the name, without uid info. |
|
2636 aInfo->iCodeAddress = memoryInfo.iCodeBase; |
|
2637 aInfo->iDataAddress = memoryInfo.iInitialisedDataBase; |
|
2638 //this way, host debugger will not resume the thread, instead engine will resume |
|
2639 //after going through the list of all static libraries.. |
|
2640 aInfo->iThreadId = 0xFFFFFFFF; |
|
2641 |
|
2642 LOG_MSG2("library name: %S", codeSeg->iFileName); |
|
2643 LOG_MSG2("code address: %x", aInfo->iCodeAddress); |
|
2644 LOG_MSG2("data address: %x", aInfo->iDataAddress); |
|
2645 |
|
2646 return KErrNone; |
|
2647 } |
|
2648 |
|
2649 |
|
2650 // |
|
2651 // DMetroTrkChannel::DoGetLibraryInfo |
|
2652 // |
|
2653 TInt DMetroTrkChannel::DoGetLibraryInfo(TDesC8 &aDllName, TMetroTrkLibInfo *aInfo) |
|
2654 { |
|
2655 LOG_MSG("DMetroTrkChannel::DoGetLibraryInfo()"); |
|
2656 |
|
2657 TInt err = KErrArgument; |
|
2658 |
|
2659 if (!aInfo) |
|
2660 return err; |
|
2661 |
|
2662 err = DoGetLibInfoFromCodeSegList(aDllName, aInfo); |
|
2663 |
|
2664 return err; |
|
2665 } |
|
2666 |
|
2667 // |
|
2668 // DMetroTrkChannel::DoGetExeInfo |
|
2669 // |
|
2670 TInt DMetroTrkChannel::DoGetExeInfo(TDesC8 &aExeName, TMetroTrkExeInfo* aExeInfo) |
|
2671 { |
|
2672 LOG_MSG("DMetroTrkChannel::DoGetExeInfo()"); |
|
2673 |
|
2674 DObjectCon *processes = Kern::Containers()[EProcess]; |
|
2675 if (!processes) |
|
2676 return KErrGeneral; |
|
2677 |
|
2678 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
2679 processes->Wait(); // Obtain the container mutex so the list does get changed under us |
|
2680 |
|
2681 TInt err = KErrNotFound; //set err to KErrNotFound |
|
2682 for (TInt i=0; i < processes->Count(); i++) // >= because the index is zero based |
|
2683 { |
|
2684 DProcess *process = (DProcess *)((*processes)[i]); |
|
2685 if (process && (0x0 != aExeInfo->iUid) && (aExeInfo->iUid == process->iUids.iUid[2].iUid)) |
|
2686 { |
|
2687 DCodeSeg* codeSeg = process->iCodeSeg; |
|
2688 DThread* mainThread = process->FirstThread(); |
|
2689 if (codeSeg && mainThread) |
|
2690 { |
|
2691 aExeInfo->iProcessID = process->iId; |
|
2692 aExeInfo->iThreadID = mainThread->iId; |
|
2693 |
|
2694 TModuleMemoryInfo memoryInfo; |
|
2695 err = codeSeg->GetMemoryInfo(memoryInfo, NULL); |
|
2696 if (KErrNone == err) |
|
2697 { |
|
2698 aExeInfo->iCodeAddress = memoryInfo.iCodeBase; |
|
2699 aExeInfo->iDataAddress = memoryInfo.iInitialisedDataBase; |
|
2700 break; |
|
2701 } |
|
2702 } |
|
2703 } |
|
2704 } |
|
2705 |
|
2706 processes->Signal(); |
|
2707 NKern::ThreadLeaveCS(); |
|
2708 |
|
2709 return err; |
|
2710 } |
|
2711 |
|
2712 |
|
2713 // |
|
2714 // DMetroTrkChannel::DoGetProcUidInfo |
|
2715 // |
|
2716 TInt DMetroTrkChannel::DoGetProcUidInfo(TMetroTrkProcUidInfo* aProcUidInfo) |
|
2717 { |
|
2718 LOG_MSG("DMetroTrkChannel::DoGetProcUidInfo()"); |
|
2719 |
|
2720 TInt err = KErrNotFound; |
|
2721 DProcess* process = ProcessFromId(aProcUidInfo->iProcessID); |
|
2722 if (process) |
|
2723 { |
|
2724 aProcUidInfo->iUid1 = process->iUids.iUid[0].iUid; |
|
2725 aProcUidInfo->iUid2 = process->iUids.iUid[1].iUid; |
|
2726 aProcUidInfo->iUid3 = process->iUids.iUid[2].iUid; |
|
2727 aProcUidInfo->iSecurID = process->iS.iSecureId; |
|
2728 aProcUidInfo->iVendorID = process->iS.iVendorId; |
|
2729 |
|
2730 err = KErrNone; |
|
2731 } |
|
2732 return err; |
|
2733 } |
|
2734 |
|
2735 // |
|
2736 // DMetroTrkChannel::DoGetLibInfoFromCodeSegList |
|
2737 // |
|
2738 TInt DMetroTrkChannel::DoGetLibInfoFromCodeSegList(TDesC8 &aDllName, TMetroTrkLibInfo *aInfo) |
|
2739 { |
|
2740 LOG_MSG("DMetroTrkChannel::DoGetLibInfoFromCodeSegList()"); |
|
2741 |
|
2742 TInt err = KErrArgument; |
|
2743 |
|
2744 //get global code seg list |
|
2745 SDblQue* codeSegList = Kern::CodeSegList(); |
|
2746 if (!codeSegList) |
|
2747 return KErrBadHandle; |
|
2748 |
|
2749 //iterate through the list |
|
2750 for (SDblQueLink* codeSegPtr = codeSegList->First(); codeSegPtr!=(SDblQueLink*) (codeSegList); codeSegPtr=codeSegPtr->iNext) |
|
2751 { |
|
2752 DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iLink); |
|
2753 if (codeSeg && codeSeg->IsDll()) |
|
2754 { |
|
2755 if (codeSeg->iFileName) //If this is valid, the rootname will also be valid. |
|
2756 { |
|
2757 // some dll names from the code segment list have some characters towards the end. |
|
2758 // Not sure why. |
|
2759 // To account for this, we need to compare those strings that are |
|
2760 // atleast as big as the dll we are looking for. |
|
2761 // Also the dll names in the code segment list don't have null terminator and so -1. |
|
2762 if (codeSeg->iRootName.Length() < aDllName.Length()-1) |
|
2763 continue; |
|
2764 |
|
2765 if (!_strnicmp(codeSeg->iRootName.Ptr(), aDllName.Ptr(), aDllName.Length()-1)) |
|
2766 { |
|
2767 TModuleMemoryInfo memoryInfo; |
|
2768 |
|
2769 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); |
|
2770 if (err != KErrNone) |
|
2771 { |
|
2772 //there's been an error so return it |
|
2773 return err; |
|
2774 } |
|
2775 |
|
2776 aInfo->iCodeAddress = memoryInfo.iCodeBase; |
|
2777 aInfo->iDataAddress = memoryInfo.iInitialisedDataBase; |
|
2778 if (codeSeg->iAttachProcess) //not valid if dll is used by multiple processes, so not reliable. |
|
2779 { |
|
2780 aInfo->iAttachProcessId = codeSeg->iAttachProcess->iId; |
|
2781 if (codeSeg->iAttachProcess->FirstThread()) |
|
2782 aInfo->iAttachThreadId = codeSeg->iAttachProcess->FirstThread()->iId; |
|
2783 } |
|
2784 |
|
2785 LOG_MSG2("Code segment found for lib: %s", aDllName.Ptr()); |
|
2786 LOG_MSG2("code address: %x", aInfo->iCodeAddress); |
|
2787 LOG_MSG2("data address: %x", aInfo->iDataAddress); |
|
2788 |
|
2789 return KErrNone; |
|
2790 } |
|
2791 } |
|
2792 } |
|
2793 } |
|
2794 |
|
2795 LOG_MSG2("Code segment not found for lib: %s", aDllName.Ptr()); |
|
2796 return err; |
|
2797 } |
|
2798 |
|
2799 // |
|
2800 // DMetroTrkChannel::DoGetLibInfoFromKernLibContainer |
|
2801 // |
|
2802 TInt DMetroTrkChannel::DoGetLibInfoFromKernLibContainer(TDesC8 &aDllName, TMetroTrkLibInfo *aInfo) |
|
2803 { |
|
2804 LOG_MSG("DMetroTrkChannel::DoGetLibInfoFromKernLibContainer()"); |
|
2805 |
|
2806 TInt err = KErrNone; |
|
2807 |
|
2808 DObjectCon *libraries = Kern::Containers()[ELibrary]; |
|
2809 |
|
2810 if (!libraries) |
|
2811 return KErrGeneral; |
|
2812 |
|
2813 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
2814 libraries->Wait(); // Obtain the container mutex so the list does get changed under us |
|
2815 |
|
2816 for (TInt i=0; i<libraries->Count(); i++) |
|
2817 { |
|
2818 DLibrary *library = (DLibrary *)((*libraries)[i]); |
|
2819 |
|
2820 if (library) |
|
2821 { |
|
2822 TBuf<KMaxPath> libName; |
|
2823 libName.Copy(*(library->iName)); //just copy the name without the UID info. |
|
2824 |
|
2825 if (libName.Length() < aDllName.Length()-1) |
|
2826 continue; |
|
2827 |
|
2828 if (!_strnicmp(libName.Ptr(), aDllName.Ptr(), aDllName.Length()-1)) |
|
2829 { |
|
2830 //get the code address |
|
2831 DCodeSeg* codeSeg = library->iCodeSeg; |
|
2832 if (codeSeg) |
|
2833 { |
|
2834 TModuleMemoryInfo memoryInfo; |
|
2835 |
|
2836 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); |
|
2837 if (err == KErrNone) |
|
2838 { |
|
2839 // there's been an error so return it |
|
2840 aInfo->iCodeAddress = memoryInfo.iCodeBase; |
|
2841 aInfo->iDataAddress = memoryInfo.iInitialisedDataBase; |
|
2842 // process id and thread id are in DLibrary object. |
|
2843 } |
|
2844 } |
|
2845 else |
|
2846 { |
|
2847 LOG_MSG2("Code segment not available for library %S", library->iName); |
|
2848 err = KErrNotFound; |
|
2849 } |
|
2850 break; |
|
2851 } |
|
2852 } |
|
2853 } |
|
2854 |
|
2855 libraries->Signal(); |
|
2856 NKern::ThreadLeaveCS(); |
|
2857 |
|
2858 return err; |
|
2859 } |
|
2860 |
|
2861 // |
|
2862 // DMetroTrkChannel::DoSecurityCheck |
|
2863 // |
|
2864 TBool DMetroTrkChannel::DoSecurityCheck() |
|
2865 { |
|
2866 DProcess* clientProcess = iClientThread->iOwningProcess; |
|
2867 if (clientProcess) |
|
2868 { |
|
2869 // now we also check to make sure that TRK app has ALLFILES capability as well. |
|
2870 if (!iClientThread->HasCapability(ECapabilityAllFiles)) |
|
2871 return EFalse; |
|
2872 |
|
2873 SSecurityInfo secureInfo = clientProcess->iS; |
|
2874 if ((secureInfo.iSecureId == KTrkSrvSecurUid) || (secureInfo.iSecureId == KTrkAppSecurUid) || (secureInfo.iSecureId == KTrkExeSecurUid)) |
|
2875 { |
|
2876 return ETrue; |
|
2877 } |
|
2878 } |
|
2879 return EFalse; |
|
2880 } |
|
2881 |
|
2882 // |
|
2883 // DMetroTrkChannel::TryToReadMemory |
|
2884 // |
|
2885 TInt DMetroTrkChannel::TryToReadMemory(DThread *aThread, TAny *aSrc, TAny *aDest, TInt16 aLength) |
|
2886 { |
|
2887 LOG_MSG("DMetroTrkChannel::TryToReadMemory()"); |
|
2888 |
|
2889 TInt err = KErrNone; |
|
2890 // on some targets reading from 0xFFFFFFFF address causes a kernel fault. |
|
2891 // avoid reading the last 4 bytes in the 32 bit address space. |
|
2892 TUint32 srcAddr = (TUint32)(aSrc); |
|
2893 if ((srcAddr >= 0xFFFFFFFC) || (aLength > (0xFFFFFFFC-srcAddr))) |
|
2894 return KErrAccessDenied; |
|
2895 |
|
2896 #ifndef __OEM_TRK__ |
|
2897 if (IsAddressInRom((TUint32)(aSrc)) || IsAddressSecure((TUint32)(aSrc))) |
|
2898 return KErrNotSupported; |
|
2899 #endif |
|
2900 |
|
2901 //check if we have a valid thread object |
|
2902 if (!aThread) |
|
2903 return KErrBadHandle; |
|
2904 |
|
2905 LOG_MSG2("Using Kern::ThreadRawRead to read memory at address %x", aSrc); |
|
2906 err = Kern::ThreadRawRead(aThread, aSrc, aDest, aLength); |
|
2907 |
|
2908 return err; |
|
2909 } |
|
2910 |
|
2911 |
|
2912 // |
|
2913 // DMetroTrkChannel::TryToWriteMemory |
|
2914 // |
|
2915 TInt DMetroTrkChannel::TryToWriteMemory(DThread *aThread, TAny *aDest, TAny *aSrc, TInt16 aLength) |
|
2916 { |
|
2917 LOG_MSG("DMetroTrkChannel::TryToWriteMemory()"); |
|
2918 |
|
2919 TInt err = KErrNone; |
|
2920 // on some targets writing to 0xFFFFFFFF address causes a kernel fault. |
|
2921 // avoid writing the last 4 bytes in the 32 bit address space. |
|
2922 TUint32 destAddr = (TUint32)(aDest); |
|
2923 if ((destAddr>=0xFFFFFFFC) || (aLength > (0xFFFFFFFC-destAddr))) |
|
2924 return KErrAccessDenied; |
|
2925 |
|
2926 #ifndef __OEM_TRK__ |
|
2927 if (IsAddressInRom((TUint32)(aDest)) || IsAddressSecure((TUint32)(aDest))) |
|
2928 return KErrNotSupported; |
|
2929 #endif |
|
2930 |
|
2931 //check if we have a valid thread object |
|
2932 if (!aThread) |
|
2933 return KErrBadHandle; |
|
2934 |
|
2935 LOG_MSG2("Using Kern::ThreadRawWrite to write memory at address %x", (TUint32)aDest); |
|
2936 err = Kern::ThreadRawWrite(aThread, aDest, aSrc, aLength, iClientThread); |
|
2937 |
|
2938 return err; |
|
2939 } |
|
2940 |
|
2941 // |
|
2942 // DMetroTrkChannel::ReadRegister |
|
2943 // |
|
2944 TInt32 DMetroTrkChannel::ReadRegister(DThread *aThread, TInt aNum) |
|
2945 { |
|
2946 LOG_MSG("DMetroTrkChannel::ReadRegister()"); |
|
2947 |
|
2948 if (!aThread || (aNum < 0) || (aNum >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) |
|
2949 { |
|
2950 LOG_MSG2("Invalid register number (%d) passed to ReadRegister", aNum); |
|
2951 return 0; |
|
2952 } |
|
2953 |
|
2954 TArmRegSet regSet; |
|
2955 TUint32 unused; |
|
2956 |
|
2957 #ifdef SUPPORT_KERNCONTEXT |
|
2958 NKern::Lock(); // lock the kernel before callin UserContextType as its required by this function |
|
2959 NThread nThread = aThread->iNThread; |
|
2960 NThread::TUserContextType userContextType = nThread.UserContextType(); |
|
2961 NKern::Unlock(); // unlock the kernel now |
|
2962 |
|
2963 if (userContextType == NThread::EContextNone || userContextType == NThread::EContextKernel) |
|
2964 { |
|
2965 //NKern::ThreadGetSystemContext(&aThread->iNThread, ®Set, unused); |
|
2966 if (!GetSystemThreadRegisters(®Set)) |
|
2967 return KErrGeneral; |
|
2968 } |
|
2969 else |
|
2970 #endif |
|
2971 { |
|
2972 NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); |
|
2973 } |
|
2974 |
|
2975 TArmReg *reg = ®Set.iR0; |
|
2976 |
|
2977 return ((TUint32 *)reg)[aNum]; |
|
2978 } |
|
2979 |
|
2980 // |
|
2981 // DMetroTrkChannel::ShiftedRegValue |
|
2982 // |
|
2983 TUint32 DMetroTrkChannel::ShiftedRegValue(DThread *aThread, TUint32 aInstruction, TUint32 aCurrentPC, TUint32 aStatusRegister) |
|
2984 { |
|
2985 LOG_MSG("DMetroTrkChannel::ShiftedRegValue()"); |
|
2986 |
|
2987 TUint32 shift = 0; |
|
2988 if (aInstruction & 0x10) // bit 4 |
|
2989 { |
|
2990 shift = (ARM_RS(aInstruction) == PC_REGISTER ? aCurrentPC + 8 : aStatusRegister) & 0xFF; |
|
2991 } |
|
2992 else |
|
2993 { |
|
2994 shift = ARM_DATA_C(aInstruction); |
|
2995 } |
|
2996 |
|
2997 TInt rm = ARM_RM(aInstruction); |
|
2998 TUint32 res = (rm == PC_REGISTER ? (aCurrentPC + ((aInstruction & 0x10) ? 12 : 8)) : ReadRegister(aThread, rm)); |
|
2999 |
|
3000 switch(ARM_DATA_SHIFT(aInstruction)) |
|
3001 { |
|
3002 case 0: // LSL |
|
3003 { |
|
3004 res = shift >= 32 ? 0 : res << shift; |
|
3005 break; |
|
3006 } |
|
3007 case 1: // LSR |
|
3008 { |
|
3009 res = shift >= 32 ? 0 : res >> shift; |
|
3010 break; |
|
3011 } |
|
3012 case 2: // ASR |
|
3013 { |
|
3014 if (shift >= 32) |
|
3015 shift = 31; |
|
3016 res = ((res & 0x80000000L) ? ~((~res) >> shift) : res >> shift); |
|
3017 break; |
|
3018 } |
|
3019 case 3: // ROR/RRX |
|
3020 { |
|
3021 shift &= 31; |
|
3022 if (shift == 0) |
|
3023 { |
|
3024 res = (res >> 1) | ((aStatusRegister & ARM_CARRY_BIT) ? 0x80000000L : 0); |
|
3025 } |
|
3026 else |
|
3027 { |
|
3028 res = (res >> shift) | (res << (32 - shift)); |
|
3029 } |
|
3030 break; |
|
3031 } |
|
3032 } |
|
3033 |
|
3034 return res & 0xFFFFFFFF; |
|
3035 } |
|
3036 |
|
3037 |
|
3038 // |
|
3039 // DMetroTrkChannel::ModifyBreaksForStep |
|
3040 // |
|
3041 // Set a temporary breakpoint at the next instruction to be executed after the one at the current PC |
|
3042 // Disable the breakpoint at the current PC if one exists |
|
3043 // |
|
3044 TInt DMetroTrkChannel::ModifyBreaksForStep(DThread *aThread, TUint32 aRangeStart, TUint32 aRangeEnd, TBool aStepInto, TBool aResumeOnceOutOfRange, TBool aCheckForStubs) |
|
3045 { |
|
3046 LOG_MSG("DMetroTrkChannel::ModifyBreaksForStep()"); |
|
3047 |
|
3048 if (!aThread) |
|
3049 return KErrArgument; |
|
3050 |
|
3051 LOG_MSG2("Range Start: %x", aRangeStart); |
|
3052 LOG_MSG2("Range End: %x", aRangeEnd); |
|
3053 |
|
3054 // get the current PC |
|
3055 TUint32 currentPC = ReadRegister(aThread, PC_REGISTER); |
|
3056 LOG_MSG2("Current PC: %x", currentPC); |
|
3057 |
|
3058 // disable breakpoint at the current PC if necessary |
|
3059 ReturnIfError(DisableBreakAtAddress(currentPC)); |
|
3060 |
|
3061 // get the status register |
|
3062 TUint32 statusRegister = ReadRegister(aThread, STATUS_REGISTER); |
|
3063 LOG_MSG2("Current SR: %x", statusRegister); |
|
3064 |
|
3065 TBool thumbMode = (statusRegister & ECpuThumb); |
|
3066 if (thumbMode) |
|
3067 LOG_MSG("Thumb Mode"); |
|
3068 |
|
3069 TInt instSize = thumbMode ? 2 : 4; |
|
3070 |
|
3071 TBool changingModes = EFalse; |
|
3072 |
|
3073 TUint32 breakAddress = 0; |
|
3074 |
|
3075 TInt rangeSize = aRangeEnd - currentPC; |
|
3076 |
|
3077 const TInt KMaxInstructionBuffer = 80; |
|
3078 |
|
3079 // scan the memory and see if any instruction might modify the PC. if one does, |
|
3080 // stop scanning and just set a breakpoint at that instruction (with the range set accordingly). |
|
3081 // if none is found just set the breakpoint after the range. |
|
3082 // if there is only one instruction there is no need to parse the memory, just execute it |
|
3083 if ((rangeSize <= KMaxInstructionBuffer) && (rangeSize > instSize)) |
|
3084 { |
|
3085 LOG_MSG("Scanning range for instructions that might modify the PC"); |
|
3086 |
|
3087 // set it to the end of the range by default |
|
3088 breakAddress = aRangeEnd; |
|
3089 |
|
3090 // get the instructions in range |
|
3091 // we really should be dynamically allocating this memory, but this could be |
|
3092 // called from another thread, so we can't |
|
3093 TBuf8<KMaxInstructionBuffer> instructions; |
|
3094 |
|
3095 ReturnIfError(DoReadMemory(aThread, currentPC, rangeSize, instructions)); |
|
3096 |
|
3097 for (TInt i = 0; i < (TInt)rangeSize/instSize; i++) |
|
3098 { |
|
3099 if (InstructionModifiesPC(aThread, &instructions[i*instSize], thumbMode, aStepInto)) |
|
3100 { |
|
3101 breakAddress = currentPC + i*instSize; |
|
3102 LOG_MSG2("Setting breakpoint at %x inside range", breakAddress); |
|
3103 break; |
|
3104 } |
|
3105 } |
|
3106 } |
|
3107 |
|
3108 |
|
3109 TUint32 newRangeEnd = aRangeEnd; |
|
3110 |
|
3111 if ((breakAddress == 0) || (breakAddress == currentPC)) |
|
3112 { |
|
3113 // either the range consists of a single instruction, or the instruction at the currentPC may modify the PC |
|
3114 // decode the instruction and see where we need to set the breakpoint |
|
3115 breakAddress = PCAfterInstructionExecutes(aThread, currentPC, statusRegister, instSize, aStepInto, newRangeEnd, changingModes); |
|
3116 |
|
3117 // check to see if this is one of the stubs (found in stubs.s) |
|
3118 if (aStepInto && aCheckForStubs) |
|
3119 { |
|
3120 TBuf8<16> destination; |
|
3121 TInt err = DoReadMemory(aThread, breakAddress, 16, destination); |
|
3122 |
|
3123 if (KErrNone == err) |
|
3124 { |
|
3125 TInt offset = 0; |
|
3126 |
|
3127 if (0 == destination.Find(KArm4Stub, sizeof(KArm4Stub))) |
|
3128 { |
|
3129 LOG_MSG("Arm4 stub found"); |
|
3130 offset = 8; |
|
3131 } |
|
3132 else if ((0 == destination.Find(KArmIStub, sizeof(KArmIStub))) || |
|
3133 (0 == destination.Find(KFastArmIStub, sizeof(KFastArmIStub)))) |
|
3134 { |
|
3135 LOG_MSG("ArmI stub found"); |
|
3136 offset = 12; |
|
3137 } |
|
3138 else if ((0 == destination.Find(KThumbStub, sizeof(KThumbStub))) || |
|
3139 (0 == destination.Find(KFastThumbStub, sizeof(KFastThumbStub)))) |
|
3140 { |
|
3141 LOG_MSG("Thumb stub found"); |
|
3142 offset = 12; |
|
3143 } |
|
3144 else if ((0 == destination.Find(KThumbStub2, sizeof(KThumbStub2))) || |
|
3145 (0 == destination.Find(KFastThumbStub2, sizeof(KFastThumbStub2)))) |
|
3146 { |
|
3147 LOG_MSG("Thumb stub found"); |
|
3148 offset = 8; |
|
3149 } |
|
3150 //check to see if this is the stub generated with RVCT tools. |
|
3151 //Look into genstubs.cpp for more details on this stub |
|
3152 else if(0 == destination.Find(KRvctArm4Stub, sizeof(KRvctArm4Stub))) |
|
3153 { |
|
3154 LOG_MSG("RVCT Arm4 stub found"); |
|
3155 offset = 4; |
|
3156 } |
|
3157 |
|
3158 |
|
3159 if (offset != 0) |
|
3160 { |
|
3161 if (offset == 4) |
|
3162 { |
|
3163 breakAddress = *(TUint32 *)&destination[offset]; |
|
3164 } |
|
3165 else |
|
3166 { |
|
3167 err = DoReadMemory(aThread, *(TUint32 *)&destination[offset], 4, destination); |
|
3168 if (KErrNone == err) |
|
3169 breakAddress = *(TUint32 *)destination.Ptr(); |
|
3170 } |
|
3171 |
|
3172 if (KErrNone == err) |
|
3173 { |
|
3174 if (thumbMode) |
|
3175 { |
|
3176 if ((breakAddress & 0x00000001) == 1) |
|
3177 changingModes = EFalse; |
|
3178 else |
|
3179 changingModes = ETrue; |
|
3180 } |
|
3181 else |
|
3182 { |
|
3183 if ((breakAddress & 0x00000001) == 1) |
|
3184 changingModes = ETrue; |
|
3185 else |
|
3186 changingModes = EFalse; |
|
3187 } |
|
3188 |
|
3189 breakAddress &= 0xFFFFFFFE; |
|
3190 } |
|
3191 else |
|
3192 { |
|
3193 LOG_MSG("Error reading destination of stub"); |
|
3194 } |
|
3195 } |
|
3196 } |
|
3197 else |
|
3198 { |
|
3199 LOG_MSG("Error reading memory while decoding branch instruction"); |
|
3200 } |
|
3201 } |
|
3202 |
|
3203 // don't allow the user to step in a function in the excluded ROM region. |
|
3204 //if ((breakAddress >= iExcludedROMAddressStart) && (breakAddress < iExcludedROMAddressEnd)) |
|
3205 //{ |
|
3206 // breakAddress = currentPC + instSize; |
|
3207 // changingModes = EFalse; |
|
3208 //} |
|
3209 } |
|
3210 |
|
3211 // see if there is already a breakpoint at this address. if there is, we do not need to set the temp breakpoint |
|
3212 for (TInt i=NUMBER_OF_TEMP_BREAKPOINTS; i<iBreakPointList.Count(); i++) |
|
3213 { |
|
3214 if (iBreakPointList[i].iAddress == breakAddress) |
|
3215 { |
|
3216 return KErrNone; |
|
3217 } |
|
3218 } |
|
3219 |
|
3220 for (TInt i=0; i<NUMBER_OF_TEMP_BREAKPOINTS; i++) |
|
3221 { |
|
3222 if (iBreakPointList[i].iAddress == 0) |
|
3223 { |
|
3224 iBreakPointList[i].iThreadId = aThread->iId; |
|
3225 iBreakPointList[i].iAddress = breakAddress; |
|
3226 iBreakPointList[i].iThumbMode = (thumbMode && !changingModes) || (!thumbMode && changingModes); |
|
3227 iBreakPointList[i].iResumeOnceOutOfRange = aResumeOnceOutOfRange; |
|
3228 iBreakPointList[i].iSteppingInto = aStepInto; |
|
3229 iBreakPointList[i].iRangeStart = aRangeStart; |
|
3230 iBreakPointList[i].iRangeEnd = newRangeEnd; |
|
3231 |
|
3232 // Temporary breakpoints are always thread specific |
|
3233 iBreakPointList[i].iThreadSpecific = ETrue; |
|
3234 |
|
3235 LOG_MSG2("Adding temp breakpoint with id: %d", i); |
|
3236 LOG_MSG2("Adding temp breakpoint with thread id: %d", aThread->iId); |
|
3237 |
|
3238 return DoEnableBreak(iBreakPointList[i], ETrue); |
|
3239 } |
|
3240 } |
|
3241 |
|
3242 return KErrNoMemory; |
|
3243 } |
|
3244 |
|
3245 // |
|
3246 // DMetroTrkChannel::ClearAllBreakPoints |
|
3247 // |
|
3248 void DMetroTrkChannel::ClearAllBreakPoints() |
|
3249 { |
|
3250 LOG_MSG("DMetroTrkChannel::ClearAllBreakPoints()"); |
|
3251 |
|
3252 TInt err = KErrNone; |
|
3253 |
|
3254 for (TInt i=0; i<iBreakPointList.Count(); i++) |
|
3255 { |
|
3256 if ((iBreakPointList[i].iAddress != 0) && !iBreakPointList[i].iObsoleteLibraryBreakpoint) |
|
3257 { |
|
3258 LOG_MSG2("Clearing breakpoint at address %x", iBreakPointList[i].iAddress); |
|
3259 |
|
3260 DThread* threadObj = ThreadFromId(iBreakPointList[i].iThreadId); |
|
3261 |
|
3262 if (threadObj != NULL) |
|
3263 { |
|
3264 XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[i].iAddress)); |
|
3265 |
|
3266 err = (KErrNone == r) ? err : r; |
|
3267 } |
|
3268 else |
|
3269 { |
|
3270 err = KErrBadHandle; |
|
3271 } |
|
3272 |
|
3273 if (KErrNone != err) |
|
3274 { |
|
3275 LOG_MSG2("Error %d while clearing breakpoint", err); |
|
3276 } |
|
3277 } |
|
3278 } |
|
3279 |
|
3280 iBreakPointList.Reset(); |
|
3281 } |
|
3282 |
|
3283 |
|
3284 // |
|
3285 // DMetroTrkChannel::DisableBreakAtAddress |
|
3286 // |
|
3287 TInt DMetroTrkChannel::DisableBreakAtAddress(TUint32 aAddress) |
|
3288 { |
|
3289 LOG_MSG("DMetroTrkChannel::DisableBreakAtAddress()"); |
|
3290 |
|
3291 TInt err = KErrNone; |
|
3292 |
|
3293 for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) |
|
3294 { |
|
3295 if (iBreakPointList[i].iAddress == aAddress) |
|
3296 { |
|
3297 iBreakPointList[i].iDisabledForStep = ETrue; |
|
3298 LOG_MSG2("Disabling breakpoint at address %x", iBreakPointList[i].iAddress); |
|
3299 |
|
3300 DThread* threadObj = ThreadFromId(iBreakPointList[i].iThreadId); |
|
3301 |
|
3302 //clear the breakpoint with code modifier |
|
3303 //code modifier will restore the org instruction and also frees the shadow page if necessary |
|
3304 if (threadObj != NULL) |
|
3305 { |
|
3306 XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, aAddress)); |
|
3307 |
|
3308 err = (KErrNone == r) ? err : r; |
|
3309 } |
|
3310 else |
|
3311 { |
|
3312 err = KErrBadHandle; |
|
3313 } |
|
3314 break; |
|
3315 } |
|
3316 } |
|
3317 |
|
3318 return err; |
|
3319 } |
|
3320 |
|
3321 // |
|
3322 // DMetroTrkChannel::InstructionModifiesPC |
|
3323 // |
|
3324 TBool DMetroTrkChannel::InstructionModifiesPC(DThread *aThread, TUint8 *aInstruction, TBool aThumbMode, TBool aStepInto) |
|
3325 { |
|
3326 LOG_MSG("DMetroTrkChannel::InstructionModifiesPC()"); |
|
3327 |
|
3328 if (aThumbMode) |
|
3329 { |
|
3330 TUint16 inst = *(TUint16 *)aInstruction; |
|
3331 |
|
3332 switch(THUMB_OPCODE(inst)) |
|
3333 { |
|
3334 case 0x08: |
|
3335 { |
|
3336 if (aStepInto && (THUMB_INST_7_15(inst) == 0x08F)) |
|
3337 { |
|
3338 // BLX(2) |
|
3339 return ETrue; |
|
3340 } |
|
3341 else if (THUMB_INST_7_15(inst) == 0x08E) |
|
3342 { |
|
3343 // BX |
|
3344 return ETrue; |
|
3345 } |
|
3346 else if (((THUMB_INST_8_15(inst) == 0x46) || (THUMB_INST_8_15(inst) == 0x44)) && ((inst & 0x87) == 0x87)) |
|
3347 { |
|
3348 // ADD or MOV with PC as the destination |
|
3349 return ETrue; |
|
3350 } |
|
3351 break; |
|
3352 } |
|
3353 case 0x13: |
|
3354 { |
|
3355 if (THUMB_INST_8_15(inst) == 0x9F) |
|
3356 { |
|
3357 // LDR(4) with the PC as the destination |
|
3358 return ETrue; |
|
3359 } |
|
3360 break; |
|
3361 } |
|
3362 case 0x17: |
|
3363 { |
|
3364 if (THUMB_INST_8_15(inst) == 0xBD) |
|
3365 { |
|
3366 // POP with the PC in the list |
|
3367 return ETrue; |
|
3368 } |
|
3369 break; |
|
3370 } |
|
3371 case 0x1A: |
|
3372 case 0x1B: |
|
3373 { |
|
3374 if (THUMB_INST_8_15(inst) < 0xDE) |
|
3375 { |
|
3376 // B(1) conditional branch |
|
3377 return ETrue; |
|
3378 } |
|
3379 break; |
|
3380 } |
|
3381 case 0x1C: |
|
3382 { |
|
3383 // B(2) unconditional branch |
|
3384 return ETrue; |
|
3385 } |
|
3386 case 0x1D: |
|
3387 { |
|
3388 // NOTE: Only return true for the suffix since it's the second instruction that actually does the branch |
|
3389 if (aStepInto && !(inst & 0x00000001)) |
|
3390 { |
|
3391 // BLX(1) |
|
3392 return ETrue; |
|
3393 } |
|
3394 break; |
|
3395 } |
|
3396 case 0x1F: |
|
3397 { |
|
3398 // NOTE: Only return true for the suffix since it's the second instruction that actually does the branch |
|
3399 if (aStepInto) |
|
3400 { |
|
3401 // BL |
|
3402 return ETrue; |
|
3403 } |
|
3404 break; |
|
3405 } |
|
3406 } |
|
3407 } |
|
3408 else |
|
3409 { |
|
3410 // Arm mode |
|
3411 TUint32 inst = *(TUint32 *)aInstruction; |
|
3412 |
|
3413 switch(ARM_OPCODE(inst)) // bits 27-25 |
|
3414 { |
|
3415 case 0: |
|
3416 { |
|
3417 switch((inst & 0x00000010) >> 4) // bit 4 |
|
3418 { |
|
3419 case 0: |
|
3420 { |
|
3421 switch((inst & 0x01800000) >> 23) // bits 24-23 |
|
3422 { |
|
3423 case 2: |
|
3424 { |
|
3425 // move to/from status register. pc updates not allowed |
|
3426 // or TST, TEQ, CMP, CMN which don't modify the PC |
|
3427 break; |
|
3428 } |
|
3429 default: |
|
3430 { |
|
3431 // Data processing immediate shift |
|
3432 if (ARM_RD(inst) == PC_REGISTER) |
|
3433 { |
|
3434 // destination register is the PC |
|
3435 if (IsPreviousInstructionMovePCToLR(aThread)) |
|
3436 { |
|
3437 return aStepInto; |
|
3438 } |
|
3439 else |
|
3440 { |
|
3441 return ETrue; |
|
3442 } |
|
3443 } |
|
3444 break; |
|
3445 } |
|
3446 } |
|
3447 break; |
|
3448 } |
|
3449 case 1: |
|
3450 { |
|
3451 switch((inst & 0x00000080) >> 7) // bit 7 |
|
3452 { |
|
3453 case 0: |
|
3454 { |
|
3455 switch((inst & 0x01900000) >> 20) // bits 24-23 and bit 20 |
|
3456 { |
|
3457 case 0x10: |
|
3458 { |
|
3459 // from figure 3-3 |
|
3460 switch((inst & 0x000000F0) >> 4) // bits 7-4 |
|
3461 { |
|
3462 case 1: |
|
3463 { |
|
3464 if (((inst & 0x00400000) >> 22) == 0) // bit 22 |
|
3465 { |
|
3466 // BX |
|
3467 if (IsPreviousInstructionMovePCToLR(aThread)) |
|
3468 { |
|
3469 return aStepInto; |
|
3470 } |
|
3471 else |
|
3472 { |
|
3473 return ETrue; |
|
3474 } |
|
3475 } |
|
3476 break; |
|
3477 } |
|
3478 case 3: |
|
3479 { |
|
3480 // BLX |
|
3481 if (aStepInto) |
|
3482 { |
|
3483 return ETrue; |
|
3484 } |
|
3485 break; |
|
3486 } |
|
3487 default: |
|
3488 { |
|
3489 // either doesn't modify the PC or it is illegal to |
|
3490 break; |
|
3491 } |
|
3492 } |
|
3493 break; |
|
3494 } |
|
3495 default: |
|
3496 { |
|
3497 // Data processing register shift |
|
3498 if (((inst & 0x01800000) >> 23) == 2) // bits 24-23 |
|
3499 { |
|
3500 // TST, TEQ, CMP, CMN don't modify the PC |
|
3501 return EFalse; |
|
3502 } |
|
3503 else if (ARM_RD(inst) == PC_REGISTER) |
|
3504 { |
|
3505 // destination register is the PC |
|
3506 if (IsPreviousInstructionMovePCToLR(aThread)) |
|
3507 { |
|
3508 return aStepInto; |
|
3509 } |
|
3510 else |
|
3511 { |
|
3512 return ETrue; |
|
3513 } |
|
3514 } |
|
3515 break; |
|
3516 } |
|
3517 } |
|
3518 break; |
|
3519 } |
|
3520 default: |
|
3521 { |
|
3522 // from figure 3-2, updates to the PC illegal |
|
3523 break; |
|
3524 } |
|
3525 } |
|
3526 break; |
|
3527 } |
|
3528 } |
|
3529 break; |
|
3530 } |
|
3531 case 1: |
|
3532 { |
|
3533 if (((inst & 0x01800000) >> 23) == 2) // bits 24-23 |
|
3534 { |
|
3535 // cannot modify the PC |
|
3536 break; |
|
3537 } |
|
3538 else if (ARM_RD(inst) == PC_REGISTER) |
|
3539 { |
|
3540 // destination register is the PC |
|
3541 if (IsPreviousInstructionMovePCToLR(aThread)) |
|
3542 { |
|
3543 return aStepInto; |
|
3544 } |
|
3545 else |
|
3546 { |
|
3547 return ETrue; |
|
3548 } |
|
3549 } |
|
3550 break; |
|
3551 } |
|
3552 case 2: |
|
3553 { |
|
3554 // load/store immediate offset |
|
3555 if (ARM_LOAD(inst)) // bit 20 |
|
3556 { |
|
3557 // loading a register from memory |
|
3558 if (ARM_RD(inst) == PC_REGISTER) |
|
3559 { |
|
3560 // loading the PC register |
|
3561 if (IsPreviousInstructionMovePCToLR(aThread)) |
|
3562 { |
|
3563 return aStepInto; |
|
3564 } |
|
3565 else |
|
3566 { |
|
3567 return ETrue; |
|
3568 } |
|
3569 } |
|
3570 } |
|
3571 break; |
|
3572 } |
|
3573 case 3: |
|
3574 { |
|
3575 if (((inst & 0xF0000000) != 0xF) && ((inst & 0x00000010) == 0)) |
|
3576 { |
|
3577 // load/store register offset |
|
3578 if (ARM_LOAD(inst)) // bit 20 |
|
3579 { |
|
3580 // loading a register from memory |
|
3581 if (ARM_RD(inst) == PC_REGISTER) |
|
3582 { |
|
3583 // loading the PC register |
|
3584 if (IsPreviousInstructionMovePCToLR(aThread)) |
|
3585 { |
|
3586 return aStepInto; |
|
3587 } |
|
3588 else |
|
3589 { |
|
3590 return ETrue; |
|
3591 } |
|
3592 } |
|
3593 } |
|
3594 } |
|
3595 break; |
|
3596 } |
|
3597 case 4: |
|
3598 { |
|
3599 if ((inst & 0xF0000000) != 0xF) |
|
3600 { |
|
3601 // load/store multiple |
|
3602 if (ARM_LOAD(inst)) // bit 20 |
|
3603 { |
|
3604 // loading a register from memory |
|
3605 if (((inst & 0x00008000) >> 15)) |
|
3606 { |
|
3607 // loading the PC register |
|
3608 return ETrue; |
|
3609 } |
|
3610 } |
|
3611 } |
|
3612 break; |
|
3613 } |
|
3614 case 5: |
|
3615 { |
|
3616 if ((inst & 0xF0000000) == 0xF) |
|
3617 { |
|
3618 // BLX |
|
3619 if (aStepInto) |
|
3620 { |
|
3621 return ETrue; |
|
3622 } |
|
3623 } |
|
3624 else |
|
3625 { |
|
3626 if ((inst & 0x01000000)) // bit 24 |
|
3627 { |
|
3628 // BL |
|
3629 if (aStepInto) |
|
3630 { |
|
3631 return ETrue; |
|
3632 } |
|
3633 } |
|
3634 else |
|
3635 { |
|
3636 // B |
|
3637 return ETrue; |
|
3638 } |
|
3639 } |
|
3640 break; |
|
3641 } |
|
3642 } |
|
3643 } |
|
3644 |
|
3645 return EFalse; |
|
3646 } |
|
3647 |
|
3648 // |
|
3649 // DMetroTrkChannel::PCAfterInstructionExecutes |
|
3650 // |
|
3651 TUint32 DMetroTrkChannel::PCAfterInstructionExecutes(DThread *aThread, TUint32 aCurrentPC, TUint32 aStatusRegister, TInt aInstSize, TBool aStepInto, TUint32 &aNewRangeEnd, TBool &aChangingModes) |
|
3652 { |
|
3653 LOG_MSG("DMetroTrkChannel::PCAfterInstructionExecutes()"); |
|
3654 |
|
3655 // by default we will set the breakpoint at the next instruction |
|
3656 TUint32 breakAddress = aCurrentPC + aInstSize; |
|
3657 |
|
3658 // get the instruction at the current PC |
|
3659 TBuf8<4> instruction; |
|
3660 TInt err = DoReadMemory(aThread, aCurrentPC, aInstSize, instruction); |
|
3661 |
|
3662 if (KErrNone != err) |
|
3663 { |
|
3664 return breakAddress; |
|
3665 } |
|
3666 |
|
3667 if (4 == aInstSize) |
|
3668 { |
|
3669 TUint32 inst = *(TUint32 *)instruction.Ptr(); |
|
3670 LOG_MSG2("Current instruction: %x", inst); |
|
3671 |
|
3672 // check the conditions to see if this will actually get executed |
|
3673 if (IsExecuted(((inst>>28) & 0x0000000F), aStatusRegister)) |
|
3674 { |
|
3675 switch(ARM_OPCODE(inst)) // bits 27-25 |
|
3676 { |
|
3677 case 0: |
|
3678 { |
|
3679 switch((inst & 0x00000010) >> 4) // bit 4 |
|
3680 { |
|
3681 case 0: |
|
3682 { |
|
3683 switch((inst & 0x01800000) >> 23) // bits 24-23 |
|
3684 { |
|
3685 case 2: |
|
3686 { |
|
3687 // move to/from status register. pc updates not allowed |
|
3688 // or TST, TEQ, CMP, CMN which don't modify the PC |
|
3689 break; |
|
3690 } |
|
3691 default: |
|
3692 { |
|
3693 // Data processing immediate shift |
|
3694 if (ARM_RD(inst) == PC_REGISTER) |
|
3695 { |
|
3696 // destination register is the PC |
|
3697 if (IsPreviousInstructionMovePCToLR(aThread) && !aStepInto) |
|
3698 { |
|
3699 return breakAddress; |
|
3700 } |
|
3701 |
|
3702 TUint32 rn = aCurrentPC + 8; |
|
3703 if (ARM_RN(inst) != PC_REGISTER) // bits 19-16 |
|
3704 { |
|
3705 rn = ReadRegister(aThread, ARM_RN(inst)); |
|
3706 } |
|
3707 |
|
3708 TUint32 shifter = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister); |
|
3709 |
|
3710 DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress); |
|
3711 } |
|
3712 break; |
|
3713 } |
|
3714 } |
|
3715 break; |
|
3716 } |
|
3717 case 1: |
|
3718 { |
|
3719 switch((inst & 0x00000080) >> 7) // bit 7 |
|
3720 { |
|
3721 case 0: |
|
3722 { |
|
3723 switch((inst & 0x01900000) >> 20) // bits 24-23 and bit 20 |
|
3724 { |
|
3725 case 0x10: |
|
3726 { |
|
3727 // from figure 3-3 |
|
3728 switch((inst & 0x000000F0) >> 4) // bits 7-4 |
|
3729 { |
|
3730 case 1: |
|
3731 { |
|
3732 if (((inst & 0x00400000) >> 22) == 0) // bit 22 |
|
3733 { |
|
3734 // BX |
|
3735 // this is a strange case. normally this is used in the epilogue to branch the the link |
|
3736 // register. sometimes it is used to call a function, and the LR is stored in the previous |
|
3737 // instruction. since what we want to do is different for the two cases when stepping over, |
|
3738 // we need to read the previous instruction to see what we should do |
|
3739 if (IsPreviousInstructionMovePCToLR(aThread) && !aStepInto) |
|
3740 { |
|
3741 return breakAddress; |
|
3742 } |
|
3743 |
|
3744 breakAddress = ReadRegister(aThread, (inst & 0x0000000F)); |
|
3745 |
|
3746 if ((breakAddress & 0x00000001) == 1) |
|
3747 { |
|
3748 aChangingModes = ETrue; |
|
3749 } |
|
3750 |
|
3751 breakAddress &= 0xFFFFFFFE; |
|
3752 } |
|
3753 break; |
|
3754 } |
|
3755 case 3: |
|
3756 { |
|
3757 // BLX |
|
3758 if (aStepInto) |
|
3759 { |
|
3760 breakAddress = ReadRegister(aThread, (inst & 0x0000000F)); |
|
3761 |
|
3762 if ((breakAddress & 0x00000001) == 1) |
|
3763 { |
|
3764 aChangingModes = ETrue; |
|
3765 } |
|
3766 |
|
3767 breakAddress &= 0xFFFFFFFE; |
|
3768 } |
|
3769 break; |
|
3770 } |
|
3771 default: |
|
3772 { |
|
3773 // either doesn't modify the PC or it is illegal to |
|
3774 break; |
|
3775 } |
|
3776 } |
|
3777 break; |
|
3778 } |
|
3779 default: |
|
3780 { |
|
3781 // Data processing register shift |
|
3782 if (((inst & 0x01800000) >> 23) == 2) // bits 24-23 |
|
3783 { |
|
3784 // TST, TEQ, CMP, CMN don't modify the PC |
|
3785 } |
|
3786 else if (ARM_RD(inst) == PC_REGISTER) |
|
3787 { |
|
3788 // destination register is the PC |
|
3789 if (IsPreviousInstructionMovePCToLR(aThread) && !aStepInto) |
|
3790 { |
|
3791 return breakAddress; |
|
3792 } |
|
3793 |
|
3794 TUint32 rn = aCurrentPC + 8; |
|
3795 if (ARM_RN(inst) != PC_REGISTER) // bits 19-16 |
|
3796 { |
|
3797 rn = ReadRegister(aThread, ARM_RN(inst)); |
|
3798 } |
|
3799 |
|
3800 TUint32 shifter = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister); |
|
3801 |
|
3802 DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress); |
|
3803 } |
|
3804 break; |
|
3805 } |
|
3806 } |
|
3807 break; |
|
3808 } |
|
3809 default: |
|
3810 { |
|
3811 // from figure 3-2, updates to the PC illegal |
|
3812 break; |
|
3813 } |
|
3814 } |
|
3815 break; |
|
3816 } |
|
3817 } |
|
3818 break; |
|
3819 } |
|
3820 case 1: |
|
3821 { |
|
3822 if (((inst & 0x01800000) >> 23) == 2) // bits 24-23 |
|
3823 { |
|
3824 // cannot modify the PC |
|
3825 break; |
|
3826 } |
|
3827 else if (ARM_RD(inst) == PC_REGISTER) |
|
3828 { |
|
3829 // destination register is the PC |
|
3830 if (IsPreviousInstructionMovePCToLR(aThread) && !aStepInto) |
|
3831 { |
|
3832 return breakAddress; |
|
3833 } |
|
3834 |
|
3835 TUint32 rn = ReadRegister(aThread, ARM_RN(inst)); // bits 19-16 |
|
3836 TUint32 shifter = ((ARM_DATA_IMM(inst) >> ARM_DATA_ROT(inst)) | (ARM_DATA_IMM(inst) << (32 - ARM_DATA_ROT(inst)))) & 0xffffffff; |
|
3837 |
|
3838 DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress); |
|
3839 } |
|
3840 break; |
|
3841 } |
|
3842 case 2: |
|
3843 { |
|
3844 // load/store immediate offset |
|
3845 if (ARM_LOAD(inst)) // bit 20 |
|
3846 { |
|
3847 // loading a register from memory |
|
3848 if (ARM_RD(inst) == PC_REGISTER) |
|
3849 { |
|
3850 // loading the PC register |
|
3851 if (IsPreviousInstructionMovePCToLR(aThread) && !aStepInto) |
|
3852 { |
|
3853 return breakAddress; |
|
3854 } |
|
3855 |
|
3856 TUint32 base = ReadRegister(aThread, ARM_RN(inst)); |
|
3857 TUint32 offset = 0; |
|
3858 |
|
3859 if (ARM_SINGLE_PRE(inst)) |
|
3860 { |
|
3861 // Pre-indexing |
|
3862 offset = ARM_SINGLE_IMM(inst); |
|
3863 |
|
3864 if (ARM_SINGLE_U(inst)) |
|
3865 { |
|
3866 base += offset; |
|
3867 } |
|
3868 else |
|
3869 { |
|
3870 base -= offset; |
|
3871 } |
|
3872 } |
|
3873 |
|
3874 TBuf8<4> destination; |
|
3875 TInt err = DoReadMemory(aThread, base, 4, destination); |
|
3876 |
|
3877 if (KErrNone == err) |
|
3878 { |
|
3879 breakAddress = *(TUint32 *)destination.Ptr(); |
|
3880 |
|
3881 if ((breakAddress & 0x00000001) == 1) |
|
3882 { |
|
3883 aChangingModes = ETrue; |
|
3884 } |
|
3885 breakAddress &= 0xFFFFFFFE; |
|
3886 } |
|
3887 else |
|
3888 { |
|
3889 LOG_MSG("Error reading memory in decoding step instruction"); |
|
3890 } |
|
3891 } |
|
3892 } |
|
3893 break; |
|
3894 } |
|
3895 case 3: |
|
3896 { |
|
3897 if (((inst & 0xF0000000) != 0xF) && ((inst & 0x00000010) == 0)) |
|
3898 { |
|
3899 // load/store register offset |
|
3900 if (ARM_LOAD(inst)) // bit 20 |
|
3901 { |
|
3902 // loading a register from memory |
|
3903 if (ARM_RD(inst) == PC_REGISTER) |
|
3904 { |
|
3905 // loading the PC register |
|
3906 if (IsPreviousInstructionMovePCToLR(aThread) && !aStepInto) |
|
3907 { |
|
3908 return breakAddress; |
|
3909 } |
|
3910 |
|
3911 TUint32 base = (ARM_RN(inst) == PC_REGISTER) ? aCurrentPC + 8 : ReadRegister(aThread, ARM_RN(inst)); |
|
3912 TUint32 offset = 0; |
|
3913 |
|
3914 if (ARM_SINGLE_PRE(inst)) |
|
3915 { |
|
3916 offset = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister); |
|
3917 |
|
3918 if (ARM_SINGLE_U(inst)) |
|
3919 { |
|
3920 base += offset; |
|
3921 } |
|
3922 else |
|
3923 { |
|
3924 base -= offset; |
|
3925 } |
|
3926 } |
|
3927 |
|
3928 TBuf8<4> destination; |
|
3929 TInt err = DoReadMemory(aThread, base, 4, destination); |
|
3930 |
|
3931 if (KErrNone == err) |
|
3932 { |
|
3933 breakAddress = *(TUint32 *)destination.Ptr(); |
|
3934 |
|
3935 if ((breakAddress & 0x00000001) == 1) |
|
3936 { |
|
3937 aChangingModes = ETrue; |
|
3938 } |
|
3939 breakAddress &= 0xFFFFFFFE; |
|
3940 } |
|
3941 else |
|
3942 { |
|
3943 LOG_MSG("Error reading memory in decoding step instruction"); |
|
3944 } |
|
3945 } |
|
3946 } |
|
3947 } |
|
3948 break; |
|
3949 } |
|
3950 case 4: |
|
3951 { |
|
3952 if ((inst & 0xF0000000) != 0xF) |
|
3953 { |
|
3954 // load/store multiple |
|
3955 if (ARM_LOAD(inst)) // bit 20 |
|
3956 { |
|
3957 // loading a register from memory |
|
3958 if (((inst & 0x00008000) >> 15)) |
|
3959 { |
|
3960 // loading the PC register |
|
3961 TInt offset = 0; |
|
3962 if (ARM_BLOCK_U(inst)) |
|
3963 { |
|
3964 TUint32 reglist = ARM_BLOCK_REGLIST(inst); |
|
3965 offset = Bitcount(reglist) * 4 - 4; |
|
3966 if (ARM_BLOCK_PRE(inst)) |
|
3967 offset += 4; |
|
3968 } |
|
3969 else if (ARM_BLOCK_PRE(inst)) |
|
3970 { |
|
3971 offset = -4; |
|
3972 } |
|
3973 |
|
3974 TUint32 temp = ReadRegister(aThread, ARM_RN(inst)); |
|
3975 |
|
3976 temp += offset; |
|
3977 |
|
3978 TBuf8<4> destination; |
|
3979 TInt err = DoReadMemory(aThread, temp, 4, destination); |
|
3980 |
|
3981 if (KErrNone == err) |
|
3982 { |
|
3983 breakAddress = *(TUint32 *)destination.Ptr(); |
|
3984 if ((breakAddress & 0x00000001) == 1) |
|
3985 { |
|
3986 aChangingModes = ETrue; |
|
3987 } |
|
3988 breakAddress &= 0xFFFFFFFE; |
|
3989 } |
|
3990 else |
|
3991 { |
|
3992 LOG_MSG("Error reading memory in decoding step instruction"); |
|
3993 } |
|
3994 } |
|
3995 } |
|
3996 } |
|
3997 break; |
|
3998 } |
|
3999 case 5: |
|
4000 { |
|
4001 if ((inst & 0xF0000000) == 0xF) |
|
4002 { |
|
4003 // BLX |
|
4004 if (aStepInto) |
|
4005 { |
|
4006 breakAddress = (TUint32)ARM_INSTR_B_DEST(inst, aCurrentPC); |
|
4007 |
|
4008 if ((breakAddress & 0x00000001) == 1) |
|
4009 { |
|
4010 aChangingModes = ETrue; |
|
4011 } |
|
4012 |
|
4013 breakAddress &= 0xFFFFFFFE; |
|
4014 } |
|
4015 } |
|
4016 else |
|
4017 { |
|
4018 if ((inst & 0x01000000)) // bit 24 |
|
4019 { |
|
4020 // BL |
|
4021 if (aStepInto) |
|
4022 { |
|
4023 breakAddress = (TUint32)ARM_INSTR_B_DEST(inst, aCurrentPC); |
|
4024 } |
|
4025 } |
|
4026 else |
|
4027 { |
|
4028 // B |
|
4029 breakAddress = (TUint32)ARM_INSTR_B_DEST(inst, aCurrentPC); |
|
4030 } |
|
4031 } |
|
4032 break; |
|
4033 } |
|
4034 } |
|
4035 } |
|
4036 } |
|
4037 else |
|
4038 { |
|
4039 // Thumb Mode |
|
4040 TUint16 inst = *(TUint16 *)instruction.Ptr(); |
|
4041 LOG_MSG2("Current instruction: %x", inst); |
|
4042 |
|
4043 switch(THUMB_OPCODE(inst)) |
|
4044 { |
|
4045 case 0x08: |
|
4046 { |
|
4047 if (aStepInto && (THUMB_INST_7_15(inst) == 0x08F)) |
|
4048 { |
|
4049 // BLX(2) |
|
4050 breakAddress = ReadRegister(aThread, ((inst & 0x0078) >> 3)); |
|
4051 |
|
4052 if ((breakAddress & 0x00000001) == 0) |
|
4053 { |
|
4054 aChangingModes = ETrue; |
|
4055 } |
|
4056 |
|
4057 breakAddress &= 0xFFFFFFFE; |
|
4058 } |
|
4059 else if (THUMB_INST_7_15(inst) == 0x08E) |
|
4060 { |
|
4061 // BX |
|
4062 breakAddress = ReadRegister(aThread, ((inst & 0x0078) >> 3)); |
|
4063 |
|
4064 if ((breakAddress & 0x00000001) == 0) |
|
4065 { |
|
4066 aChangingModes = ETrue; |
|
4067 } |
|
4068 |
|
4069 breakAddress &= 0xFFFFFFFE; |
|
4070 } |
|
4071 else if ((THUMB_INST_8_15(inst) == 0x46) && ((inst & 0x87) == 0x87)) |
|
4072 { |
|
4073 // MOV with PC as the destination |
|
4074 breakAddress = ReadRegister(aThread, ((inst & 0x0078) >> 3)); |
|
4075 } |
|
4076 else if ((THUMB_INST_8_15(inst) == 0x44) && ((inst & 0x87) == 0x87)) |
|
4077 { |
|
4078 // ADD with PC as the destination |
|
4079 breakAddress = aCurrentPC + ReadRegister(aThread, ((inst & 0x0078) >> 3)); |
|
4080 } |
|
4081 break; |
|
4082 } |
|
4083 case 0x13: |
|
4084 { |
|
4085 //This instruction doesn't modify the PC. |
|
4086 |
|
4087 //if (THUMB_INST_8_15(inst) == 0x9F) |
|
4088 //{ |
|
4089 // LDR(4) with the PC as the destination |
|
4090 // breakAddress = ReadRegister(aThread, SP_REGISTER) + (4 * (inst & 0x00FF)); |
|
4091 //} |
|
4092 break; |
|
4093 } |
|
4094 case 0x17: |
|
4095 { |
|
4096 if (THUMB_INST_8_15(inst) == 0xBD) |
|
4097 { |
|
4098 // POP with the PC in the list |
|
4099 TUint32 regList = (inst & 0x00FF); |
|
4100 TInt offset = ReadRegister(aThread, SP_REGISTER) + (Bitcount(regList) * 4); |
|
4101 |
|
4102 TBuf8<4> destination; |
|
4103 TInt err = DoReadMemory(aThread, offset, 4, destination); |
|
4104 |
|
4105 if (KErrNone == err) |
|
4106 { |
|
4107 breakAddress = *(TUint32 *)destination.Ptr(); |
|
4108 |
|
4109 if ((breakAddress & 0x00000001) == 0) |
|
4110 { |
|
4111 aChangingModes = ETrue; |
|
4112 } |
|
4113 |
|
4114 breakAddress &= 0xFFFFFFFE; |
|
4115 } |
|
4116 else |
|
4117 { |
|
4118 LOG_MSG("Error reading memory in decoding step instruction"); |
|
4119 } |
|
4120 } |
|
4121 break; |
|
4122 } |
|
4123 case 0x1A: |
|
4124 case 0x1B: |
|
4125 { |
|
4126 if (THUMB_INST_8_15(inst) < 0xDE) |
|
4127 { |
|
4128 // B(1) conditional branch |
|
4129 if (IsExecuted(((inst & 0x0F00) >> 8), aStatusRegister)) |
|
4130 { |
|
4131 TUint32 offset = ((inst & 0x000000FF) << 1); |
|
4132 if (offset & 0x00000100) |
|
4133 { |
|
4134 offset |= 0xFFFFFF00; |
|
4135 } |
|
4136 |
|
4137 breakAddress = aCurrentPC + 4 + offset; |
|
4138 } |
|
4139 } |
|
4140 break; |
|
4141 } |
|
4142 case 0x1C: |
|
4143 { |
|
4144 // B(2) unconditional branch |
|
4145 TUint32 offset = (inst & 0x000007FF) << 1; |
|
4146 if (offset & 0x00000800) |
|
4147 { |
|
4148 offset |= 0xFFFFF800; |
|
4149 } |
|
4150 |
|
4151 breakAddress = aCurrentPC + 4 + offset; |
|
4152 break; |
|
4153 } |
|
4154 case 0x1D: |
|
4155 { |
|
4156 if (aStepInto && !(inst & 0x0001)) |
|
4157 { |
|
4158 // BLX(1) |
|
4159 breakAddress = (ReadRegister(aThread, LINK_REGISTER) + ((inst & 0x07FF) << 1)); |
|
4160 if ((breakAddress & 0x00000001) == 0) |
|
4161 { |
|
4162 aChangingModes = ETrue; |
|
4163 } |
|
4164 |
|
4165 breakAddress &= 0xFFFFFFFC; |
|
4166 } |
|
4167 break; |
|
4168 } |
|
4169 case 0x1E: |
|
4170 { |
|
4171 // BL/BLX prefix - destination is encoded in this and the next instruction |
|
4172 aNewRangeEnd += 2; |
|
4173 // BL Stepping Changes |
|
4174 if (aStepInto) |
|
4175 { |
|
4176 TBuf8<2> nextInstruction; |
|
4177 TInt err = DoReadMemory(aThread, aCurrentPC+2, aInstSize, nextInstruction); |
|
4178 if (KErrNone == err) |
|
4179 { |
|
4180 TUint16 nextInst = *(TUint16*)nextInstruction.Ptr(); |
|
4181 LOG_MSG2("Next instruction: %x", nextInst); |
|
4182 |
|
4183 // base new LR from first instruction |
|
4184 TUint32 newLR = inst & 0x07FF; |
|
4185 newLR <<= 12; |
|
4186 if (newLR & (TUint32)(0x0400 << 12)) |
|
4187 { |
|
4188 // sign-extend it |
|
4189 newLR |= 0xFF800000; |
|
4190 } |
|
4191 newLR += aCurrentPC + 4; // pc is pointing to first instruction + 4 |
|
4192 TUint32 newPC = newLR + ((nextInst & 0x07FF) << 1); |
|
4193 if (THUMB_OPCODE(nextInst) == 0x1D) // H = 01 changing to ARM (BLX) |
|
4194 { |
|
4195 newPC &= 0xFFFFFFFC; |
|
4196 aChangingModes = ETrue; |
|
4197 } |
|
4198 |
|
4199 breakAddress = newPC; |
|
4200 } |
|
4201 } |
|
4202 else // step over |
|
4203 { |
|
4204 breakAddress += 2; |
|
4205 } |
|
4206 // End of BL Stepping Changes |
|
4207 break; |
|
4208 } |
|
4209 case 0x1F: |
|
4210 { |
|
4211 if (aStepInto) |
|
4212 { |
|
4213 // BL |
|
4214 breakAddress = ReadRegister(aThread, LINK_REGISTER) + ((inst & 0x07FF) << 1); |
|
4215 } |
|
4216 break; |
|
4217 } |
|
4218 } |
|
4219 } |
|
4220 |
|
4221 return breakAddress; |
|
4222 } |
|
4223 |
|
4224 |
|
4225 // |
|
4226 // DMetroTrkChannel::DecodeDataProcessingInstruction |
|
4227 // |
|
4228 void DMetroTrkChannel::DecodeDataProcessingInstruction(TUint8 aOpcode, TUint32 aOp1, TUint32 aOp2, TUint32 aStatusRegister, TUint32 &aBreakAddress) |
|
4229 { |
|
4230 LOG_MSG("DMetroTrkChannel::DecodeDataProcessingInstruction()"); |
|
4231 |
|
4232 switch(aOpcode) |
|
4233 { |
|
4234 case 0: |
|
4235 { |
|
4236 // AND |
|
4237 aBreakAddress = aOp1 & aOp2; |
|
4238 break; |
|
4239 } |
|
4240 case 1: |
|
4241 { |
|
4242 // EOR |
|
4243 aBreakAddress = aOp1 ^ aOp2; |
|
4244 break; |
|
4245 } |
|
4246 case 2: |
|
4247 { |
|
4248 // SUB |
|
4249 aBreakAddress = aOp1 - aOp2; |
|
4250 break; |
|
4251 } |
|
4252 case 3: |
|
4253 { |
|
4254 // RSB |
|
4255 aBreakAddress = aOp2 - aOp1; |
|
4256 break; |
|
4257 } |
|
4258 case 4: |
|
4259 { |
|
4260 // ADD |
|
4261 aBreakAddress = aOp1 + aOp2; |
|
4262 break; |
|
4263 } |
|
4264 case 5: |
|
4265 { |
|
4266 // ADC |
|
4267 aBreakAddress = aOp1 + aOp2 + (aStatusRegister & ARM_CARRY_BIT) ? 1 : 0; |
|
4268 break; |
|
4269 } |
|
4270 case 6: |
|
4271 { |
|
4272 // SBC |
|
4273 aBreakAddress = aOp1 - aOp2 - (aStatusRegister & ARM_CARRY_BIT) ? 0 : 1; |
|
4274 break; |
|
4275 } |
|
4276 case 7: |
|
4277 { |
|
4278 // RSC |
|
4279 aBreakAddress = aOp2 - aOp1 - (aStatusRegister & ARM_CARRY_BIT) ? 0 : 1; |
|
4280 break; |
|
4281 } |
|
4282 case 12: |
|
4283 { |
|
4284 // ORR |
|
4285 aBreakAddress = aOp1 | aOp2; |
|
4286 break; |
|
4287 } |
|
4288 case 13: |
|
4289 { |
|
4290 // MOV |
|
4291 aBreakAddress = aOp2; |
|
4292 break; |
|
4293 } |
|
4294 case 14: |
|
4295 { |
|
4296 // BIC |
|
4297 aBreakAddress = aOp1 & ~aOp2; |
|
4298 break; |
|
4299 } |
|
4300 case 15: |
|
4301 { |
|
4302 // MVN |
|
4303 aBreakAddress = ~aOp2; |
|
4304 break; |
|
4305 } |
|
4306 } |
|
4307 } |
|
4308 |
|
4309 // |
|
4310 // DMetroTrkChannel::IsPreviousInstructionMovePCToLR |
|
4311 // |
|
4312 TBool DMetroTrkChannel::IsPreviousInstructionMovePCToLR(DThread *aThread) |
|
4313 { |
|
4314 LOG_MSG("DMetroTrkChannel::IsPreviousInstructionMovePCToLR()"); |
|
4315 |
|
4316 // there are several types of instructions that modify the PC that aren't |
|
4317 // designated as linked or non linked branches. the way gcc generates the |
|
4318 // code can tell us whether or not these instructions are to be treated as |
|
4319 // linked branches. the main cases are bx and any type of mov or load or |
|
4320 // arithmatic operation that changes the PC. if these are really just |
|
4321 // function calls that will return, gcc will generate a mov lr, pc |
|
4322 // instruction as the previous instruction. note that this is just for arm |
|
4323 // and armi |
|
4324 |
|
4325 // get the address of the previous instruction |
|
4326 TUint32 address = ReadRegister(aThread, PC_REGISTER) - 4; |
|
4327 |
|
4328 TBuf8<4> previousInstruction; |
|
4329 TInt err = DoReadMemory(aThread, address, 4, previousInstruction); |
|
4330 if (KErrNone != err) |
|
4331 { |
|
4332 LOG_MSG2("Error %d reading memory at address %x", address); |
|
4333 return EFalse; |
|
4334 } |
|
4335 |
|
4336 const TUint32 movePCToLRIgnoringCondition = 0x01A0E00F; |
|
4337 |
|
4338 TUint32 inst = *(TUint32 *)previousInstruction.Ptr(); |
|
4339 |
|
4340 if ((inst & 0x0FFFFFFF) == movePCToLRIgnoringCondition) |
|
4341 { |
|
4342 return ETrue; |
|
4343 } |
|
4344 |
|
4345 return EFalse; |
|
4346 } |
|
4347 |
|
4348 // |
|
4349 // DMetroTrkChannel::DoEnableDisabledBreak |
|
4350 // |
|
4351 // Restore the breakpoint that was disabled for stepping past it if necessary |
|
4352 // |
|
4353 TInt DMetroTrkChannel::DoEnableDisabledBreak(TUint32 aThreadId) |
|
4354 { |
|
4355 LOG_MSG("DMetroTrkChannel::DoEnableDisabledBreak()"); |
|
4356 |
|
4357 for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) |
|
4358 { |
|
4359 // if (iBreakPointList[i].iDisabledForStep && ((iBreakPointList[i].iThreadId == aThreadId) || (iBreakPointList[i].iThreadId == 0xFFFFFFFF))) |
|
4360 // Always re-enable non-Thread Specific breakpoints |
|
4361 if (iBreakPointList[i].iDisabledForStep && ((iBreakPointList[i].iThreadId == aThreadId) || (iBreakPointList[i].iThreadSpecific == EFalse))) |
|
4362 { |
|
4363 LOG_MSG2("Re-enabling breakpoint at address %x", iBreakPointList[i].iAddress); |
|
4364 iBreakPointList[i].iDisabledForStep = EFalse; |
|
4365 return DoEnableBreak(iBreakPointList[i], EFalse); |
|
4366 } |
|
4367 } |
|
4368 |
|
4369 return KErrNone; |
|
4370 } |
|
4371 |
|
4372 // |
|
4373 // DMetroTrkChannel::IsExecuted |
|
4374 // |
|
4375 // Determines whether or not an instruction will be executed |
|
4376 // |
|
4377 TBool DMetroTrkChannel::IsExecuted(TUint8 aCondition ,TUint32 aStatusRegister) |
|
4378 { |
|
4379 LOG_MSG("DMetroTrkChannel::IsExecuted()"); |
|
4380 |
|
4381 TBool N = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000008; |
|
4382 TBool Z = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000004; |
|
4383 TBool C = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000002; |
|
4384 TBool V = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000001; |
|
4385 |
|
4386 switch(aCondition) |
|
4387 { |
|
4388 case 0: |
|
4389 return Z; |
|
4390 case 1: |
|
4391 return !Z; |
|
4392 case 2: |
|
4393 return C; |
|
4394 case 3: |
|
4395 return !C; |
|
4396 case 4: |
|
4397 return N; |
|
4398 case 5: |
|
4399 return !N; |
|
4400 case 6: |
|
4401 return V; |
|
4402 case 7: |
|
4403 return !V; |
|
4404 case 8: |
|
4405 return (C && !Z); |
|
4406 case 9: |
|
4407 return (!C || Z); |
|
4408 case 10: |
|
4409 return (N == V); |
|
4410 case 11: |
|
4411 return (N != V); |
|
4412 case 12: |
|
4413 return ((N == V) && !Z); |
|
4414 case 13: |
|
4415 return (Z || (N != V)); |
|
4416 case 14: |
|
4417 case 15: |
|
4418 return ETrue; |
|
4419 } |
|
4420 |
|
4421 return EFalse; |
|
4422 } |
|
4423 |
|
4424 |
|
4425 TBool DMetroTrkChannel::IsAddressInRom(TUint32 aAddress) |
|
4426 { |
|
4427 LOG_MSG("DMetroTrkChannel::IsAddressInRom()"); |
|
4428 |
|
4429 TRomHeader romHeader = Epoc::RomHeader(); |
|
4430 |
|
4431 if ((aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iRomSize))) |
|
4432 return ETrue; |
|
4433 |
|
4434 return EFalse; |
|
4435 } |
|
4436 |
|
4437 TBool DMetroTrkChannel::IsAddressSecure(TUint32 aAddress) |
|
4438 { |
|
4439 LOG_MSG("DMetroTrkChannel::IsAddressInRom()"); |
|
4440 |
|
4441 // SHORT TERM FIX... |
|
4442 // For now, don't allow access to Kernel memory... |
|
4443 TLinAddr kernDataStartAddr = iMultipleMemModel ? KSuperPageMultipleLinAddr: KSuperPageMovingLinAddr; |
|
4444 TLinAddr kernDataEndAddr = iMultipleMemModel ? KKernDataEndMultipleLinAddr: KKernDataEndMovingLinAddr; |
|
4445 |
|
4446 if ((aAddress >= kernDataStartAddr) && (aAddress <= kernDataEndAddr)) |
|
4447 return ETrue; |
|
4448 |
|
4449 return EFalse; |
|
4450 } |
|
4451 |
|
4452 TBool DMetroTrkChannel::IsRegisterSecure(TInt registerIndex) |
|
4453 { |
|
4454 LOG_MSG("DMetroTrkChannel::IsRegisterSecure()"); |
|
4455 |
|
4456 if (registerIndex == SP_REGISTER || registerIndex == LINK_REGISTER || registerIndex == STATUS_REGISTER) |
|
4457 return ETrue; |
|
4458 |
|
4459 return EFalse; |
|
4460 } |
|
4461 |
|
4462 // |
|
4463 // DMetroTrkChannel::AllocateShadowPageIfNecessary |
|
4464 // |
|
4465 // Allocate a shadow page if the address is in ROM and no page has been allocated for that range yet |
|
4466 // |
|
4467 TInt DMetroTrkChannel::AllocateShadowPageIfNecessary(TUint32 aAddress, TUint32 &aPageAddress) |
|
4468 { |
|
4469 LOG_MSG("DMetroTrkChannel::AllocateShadowPageIfNecessary()"); |
|
4470 |
|
4471 // if this is in ROM, we need to shadow memory |
|
4472 TBool inRom = EFalse; |
|
4473 |
|
4474 //find out if M::IsRomAddress is available from ekern or any other library |
|
4475 //ReturnIfError(inRom = M::IsRomAddress((TAny *)aAddress)); |
|
4476 TRomHeader romHeader = Epoc::RomHeader(); |
|
4477 |
|
4478 if ((aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iRomSize))) |
|
4479 inRom = ETrue; |
|
4480 |
|
4481 TInt err = KErrNone; |
|
4482 |
|
4483 if (inRom) // && (TSuperPage().iRomConfig[0].iType != KBdbBankTypeRamAsRom)) |
|
4484 { |
|
4485 // if a shadow page has not already been allocated for this address range, do so now |
|
4486 TUint32 pageAddress = (aAddress & ~(iPageSize-1)); |
|
4487 |
|
4488 TBool found = EFalse; |
|
4489 for (TInt i=0; i<iBreakPointList.Count(); i++) |
|
4490 { |
|
4491 if (pageAddress == iBreakPointList[i].iPageAddress) |
|
4492 { |
|
4493 LOG_MSG2("Shadow page already allocated at address %x", pageAddress); |
|
4494 found = ETrue; |
|
4495 } |
|
4496 } |
|
4497 |
|
4498 if (!found) |
|
4499 { |
|
4500 LOG_MSG2("Allocating shadow page starting at address %x", pageAddress); |
|
4501 err = Epoc::AllocShadowPage(pageAddress); |
|
4502 if (KErrNone != err) |
|
4503 { |
|
4504 LOG_MSG2("Error %d allocating shadow page", err); |
|
4505 return KErrGeneral; |
|
4506 } |
|
4507 |
|
4508 //check to see if this is still necessary |
|
4509 //if ((ASSPID() & ASSP_ID_MASK) == XSCALE_ASSP_ID) |
|
4510 //FlushDataCache(); // workaround for cache flush problem on Lubbock/PXA255 base port |
|
4511 } |
|
4512 |
|
4513 // return the page address |
|
4514 aPageAddress = pageAddress; |
|
4515 } |
|
4516 |
|
4517 return err; |
|
4518 } |
|
4519 |
|
4520 // |
|
4521 // DMetroTrkChannel::FreeShadowPageIfNecessary |
|
4522 // |
|
4523 // Free a shadow page if the address is in ROM and no no other breakpoints are set in that page range |
|
4524 // |
|
4525 TInt DMetroTrkChannel::FreeShadowPageIfNecessary(TUint32 aAddress, TUint32 aPageAddress) |
|
4526 { |
|
4527 LOG_MSG("DMetroTrkChannel::FreeShadowPageIfNecessary()"); |
|
4528 |
|
4529 TInt err = KErrNone; |
|
4530 |
|
4531 TBool found = EFalse; |
|
4532 |
|
4533 TBool inRom = EFalse; |
|
4534 |
|
4535 //find out if M::IsRomAddress is available from ekern or any other library |
|
4536 //ReturnIfError(inRom = M::IsRomAddress((TAny *)aAddress)); |
|
4537 TRomHeader romHeader = Epoc::RomHeader(); |
|
4538 |
|
4539 if ((aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iRomSize))) |
|
4540 inRom = ETrue; |
|
4541 |
|
4542 if (inRom)// && (TSuperPage().iRomConfig[0].iType != KBdbBankTypeRamAsRom)) |
|
4543 { |
|
4544 // if there are no other breakpoints in this shadow page, we can free it now |
|
4545 for (TInt i = 0; i < iBreakPointList.Count(); i++) |
|
4546 { |
|
4547 if (aAddress != iBreakPointList[i].iAddress) // ignore the current entry |
|
4548 { |
|
4549 if ((iBreakPointList[i].iAddress >= aPageAddress) && |
|
4550 (iBreakPointList[i].iAddress < (aPageAddress + iPageSize))) |
|
4551 { |
|
4552 LOG_MSG("Still a breakpoint in this shadow page range"); |
|
4553 found = ETrue; |
|
4554 break; |
|
4555 } |
|
4556 } |
|
4557 } |
|
4558 |
|
4559 if (!found) |
|
4560 { |
|
4561 LOG_MSG2("Freeing shadow page starting at address %x", aPageAddress); |
|
4562 err = Epoc::FreeShadowPage(aPageAddress); |
|
4563 if (KErrNone != err) |
|
4564 { |
|
4565 LOG_MSG2("Error %d freeing shadow page", err); |
|
4566 return KErrGeneral; |
|
4567 } |
|
4568 } |
|
4569 } |
|
4570 |
|
4571 return err; |
|
4572 } |
|
4573 |
|
4574 |
|
4575 |
|
4576 // |
|
4577 // DMetroTrkChannel::NotifyEvent |
|
4578 // |
|
4579 void DMetroTrkChannel::NotifyEvent(SEventInfo aEventInfo, TBool isTraceEvent) |
|
4580 { |
|
4581 LOG_MSG("DMetroTrkChannel::NotifyEvent()"); |
|
4582 |
|
4583 if (iEventInfo) |
|
4584 { |
|
4585 LOG_MSG2("Completing event, type: %d", aEventInfo.iEventType); |
|
4586 |
|
4587 // iThread is the user side debugger thread, so use it to write the info to it memory |
|
4588 TInt err = Kern::ThreadRawWrite(iClientThread, iEventInfo, (TUint8 *)&aEventInfo, sizeof(SEventInfo), iClientThread); |
|
4589 |
|
4590 if (KErrNone != err) |
|
4591 LOG_MSG2("Error writing event info: %d", err); |
|
4592 |
|
4593 // clear this since we've completed the request |
|
4594 iEventInfo = NULL; |
|
4595 |
|
4596 // signal the debugger thread |
|
4597 Kern::RequestComplete(iClientThread, iRequestGetEventStatus, KErrNone); |
|
4598 } |
|
4599 else |
|
4600 { |
|
4601 if (isTraceEvent) |
|
4602 { |
|
4603 LOG_MSG("Queuing trace event\r\n"); |
|
4604 |
|
4605 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++) |
|
4606 { |
|
4607 if (SEventInfo::EUnknown == iTraceEventQueue[i].iEventType) |
|
4608 { |
|
4609 iTraceEventQueue[i] = aEventInfo; |
|
4610 break; |
|
4611 } |
|
4612 } |
|
4613 } |
|
4614 else |
|
4615 { |
|
4616 LOG_MSG2("Queuing event, type: %d", aEventInfo.iEventType); |
|
4617 |
|
4618 for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++) |
|
4619 { |
|
4620 if (SEventInfo::EUnknown == iEventQueue[i].iEventType) |
|
4621 { |
|
4622 iEventQueue[i] = aEventInfo; |
|
4623 break; |
|
4624 } |
|
4625 } |
|
4626 } |
|
4627 } |
|
4628 } |
|
4629 |
|
4630 |
|
4631 // |
|
4632 // DMetroTrkChannel::ThreadFromId |
|
4633 // |
|
4634 DThread* DMetroTrkChannel::ThreadFromId(TUint32 aId) |
|
4635 { |
|
4636 LOG_MSG("DMetroTrkChannel::ThreadFromId()"); |
|
4637 |
|
4638 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
4639 DObjectCon& threads = *Kern::Containers()[EThread]; // Get containing holding threads |
|
4640 threads.Wait(); // Obtain the container mutex so the list does get changed under us |
|
4641 |
|
4642 DThread* thread = Kern::ThreadFromId(aId); |
|
4643 |
|
4644 threads.Signal(); // Release the container mutex |
|
4645 NKern::ThreadLeaveCS(); // End of critical section |
|
4646 |
|
4647 return thread; |
|
4648 } |
|
4649 |
|
4650 // |
|
4651 // DMetroTrkChannel::ProcessFromId |
|
4652 // |
|
4653 DProcess* DMetroTrkChannel::ProcessFromId(TUint32 aId) |
|
4654 { |
|
4655 LOG_MSG("DMetroTrkChannel::ProcessFromId()"); |
|
4656 |
|
4657 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
4658 DObjectCon& processes = *Kern::Containers()[EProcess]; // Get containing holding threads |
|
4659 processes.Wait(); // Obtain the container mutex so the list does get changed under us |
|
4660 |
|
4661 DProcess* process = Kern::ProcessFromId(aId); |
|
4662 |
|
4663 processes.Signal(); // Release the container mutex |
|
4664 NKern::ThreadLeaveCS(); // End of critical section |
|
4665 |
|
4666 return process; |
|
4667 } |
|
4668 |
|
4669 // |
|
4670 // DMetroTrkChannel::GetSystemThreadRegisters |
|
4671 // |
|
4672 TBool DMetroTrkChannel::GetSystemThreadRegisters(TArmRegSet* aArmRegSet) |
|
4673 { |
|
4674 if (iExcInfoValid) |
|
4675 { |
|
4676 aArmRegSet->iR0 = iCurrentExcInfo.iR0; |
|
4677 aArmRegSet->iR1 = iCurrentExcInfo.iR1; |
|
4678 aArmRegSet->iR2 = iCurrentExcInfo.iR2; |
|
4679 aArmRegSet->iR3 = iCurrentExcInfo.iR3; |
|
4680 aArmRegSet->iR4 = iCurrentExcInfo.iR4; |
|
4681 aArmRegSet->iR5 = iCurrentExcInfo.iR5; |
|
4682 aArmRegSet->iR6 = iCurrentExcInfo.iR6; |
|
4683 aArmRegSet->iR7 = iCurrentExcInfo.iR7; |
|
4684 aArmRegSet->iR8 = iCurrentExcInfo.iR8; |
|
4685 aArmRegSet->iR9 = iCurrentExcInfo.iR9; |
|
4686 aArmRegSet->iR10 = iCurrentExcInfo.iR10; |
|
4687 aArmRegSet->iR11 = iCurrentExcInfo.iR11; |
|
4688 aArmRegSet->iR12 = iCurrentExcInfo.iR12; |
|
4689 aArmRegSet->iR13 = iCurrentExcInfo.iR13; |
|
4690 aArmRegSet->iR14 = iCurrentExcInfo.iR14; |
|
4691 aArmRegSet->iR15 = iCurrentExcInfo.iR15; |
|
4692 aArmRegSet->iFlags = iCurrentExcInfo.iCpsr; |
|
4693 |
|
4694 return ETrue; |
|
4695 } |
|
4696 |
|
4697 return EFalse; |
|
4698 |
|
4699 } |
|
4700 |
|
4701 TBool DMetroTrkChannel::HasManufacturerCaps(DThread* aThread) |
|
4702 { |
|
4703 if (aThread && (aThread->HasCapability(ECapabilityTCB) || |
|
4704 aThread->HasCapability(ECapabilityDRM) || |
|
4705 aThread->HasCapability(ECapabilityAllFiles))) |
|
4706 { |
|
4707 return ETrue; |
|
4708 } |
|
4709 return EFalse; |
|
4710 } |
|
4711 |
|
4712 TBool DMetroTrkChannel::IsBeingDebugged(const DThread* aThread) |
|
4713 { |
|
4714 TBool isDebugging = EFalse; |
|
4715 if (aThread) |
|
4716 { |
|
4717 for (TInt i = 0; i < iDebugProcessList.Count(); i++) |
|
4718 { |
|
4719 if (iDebugProcessList[i].iId == aThread->iOwningProcess->iId) |
|
4720 { |
|
4721 isDebugging = ETrue; |
|
4722 break; |
|
4723 } |
|
4724 } |
|
4725 } |
|
4726 return isDebugging; |
|
4727 } |
|
4728 |
|
4729 void DMetroTrkChannel::CheckLibraryNotifyList(TUint32 aProcessId) |
|
4730 { |
|
4731 SDblQue* codeSegList = Kern::CodeSegList(); |
|
4732 |
|
4733 for (TInt i=0; i<iLibraryNotifyList.Count(); i++) |
|
4734 { |
|
4735 if (!iLibraryNotifyList[i].iEmptySlot) |
|
4736 { |
|
4737 //iterate through the list |
|
4738 for (SDblQueLink* codeSegPtr = codeSegList->First(); codeSegPtr != (SDblQueLink*)(codeSegList); codeSegPtr = codeSegPtr->iNext) |
|
4739 { |
|
4740 DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr, DCodeSeg, iLink); |
|
4741 if (codeSeg && codeSeg->IsDll()) |
|
4742 { |
|
4743 SEventInfo info; |
|
4744 if (!_strnicmp(iLibraryNotifyList[i].iName.Ptr(), codeSeg->iRootName.Ptr(), codeSeg->iRootName.Length())) |
|
4745 { |
|
4746 info.iFileName.Copy((codeSeg->iRootName.Ptr())); |
|
4747 LOG_MSG2("library name match: %S", &info.iFileName); |
|
4748 TModuleMemoryInfo memoryInfo; |
|
4749 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); |
|
4750 if (err != KErrNone) |
|
4751 { |
|
4752 break; |
|
4753 } |
|
4754 // |
|
4755 // check the process id from the DCodeSeg instead of using aProcessId |
|
4756 // if the iAttachProcess from DCodeSeg is null, then we should use aProcessId |
|
4757 info.iProcessId = aProcessId; |
|
4758 info.iEventType = SEventInfo::ELibraryLoaded; |
|
4759 info.iCodeAddress = memoryInfo.iCodeBase; |
|
4760 info.iDataAddress = memoryInfo.iInitialisedDataBase; |
|
4761 info.iThreadId = 0xFFFFFFFF; |
|
4762 LOG_MSG2("info.iCodeAddress: %x", info.iCodeAddress); |
|
4763 LOG_MSG2("info.iDataAddress: %x", info.iDataAddress); |
|
4764 LOG_MSG2("info.iProcessId: %d", info.iProcessId); |
|
4765 NotifyEvent(info); |
|
4766 |
|
4767 // now reset this entry |
|
4768 iLibraryNotifyList[i].iEmptySlot = ETrue; |
|
4769 break; |
|
4770 } |
|
4771 } |
|
4772 } |
|
4773 } |
|
4774 } |
|
4775 } |
|
4776 |
|
4777 DECLARE_STANDARD_LDD() |
|
4778 { |
|
4779 return new DMetroTrkDriverFactory; |
|
4780 } |