Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

783 lines
18 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. mach.c
  5. Abstract:
  6. This file contains the ALPHA specific code for dealing with
  7. the process of stepping a single instruction. This includes
  8. determination of the next offset to be stopped at and if the
  9. instruction is all call type instruction.
  10. Author:
  11. Miche Baker-Harvey (miche) - stole the appropriate parts
  12. from ntsd for the alpha version.
  13. Environment:
  14. Win32 - User
  15. Notes:
  16. There are equivalent INTEL and MIPS files.
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. extern BOOL FVerbose;
  21. extern char rgchDebug[];
  22. extern LPDM_MSG LpDmMsg;
  23. extern CRITICAL_SECTION csContinueQueue;
  24. #define FALSE 0
  25. #define TRUE 1
  26. #define STATIC static
  27. void OutputHex(ULONG, ULONG, BOOLEAN);
  28. void OutputEffectiveAddress(ULONG);
  29. void OutputString(char *);
  30. void OutputReg(ULONG);
  31. void OutputFReg(ULONG);
  32. DWORD VirtualUnwind (HPRCX, HTHDX, DWORD, PRUNTIME_FUNCTION, PCONTEXT,
  33. PKNONVOLATILE_CONTEXT_POINTERS OPTIONAL);
  34. ALPHA_INSTRUCTION disinstr;
  35. ULONG findTypeFromOpcode(ULONG);
  36. BOOL
  37. IsRet(
  38. HTHDX hthd,
  39. LPADDR addr
  40. )
  41. {
  42. DWORD instr;
  43. DWORD cBytes;
  44. if (!AddrReadMemory( hthd->hprc, hthd, addr, &instr, 4, &cBytes )) {
  45. return FALSE;
  46. }
  47. return (instr == 0x6bfa8001);
  48. }
  49. void
  50. IsCall (
  51. HTHDX hthd,
  52. LPADDR lpaddr,
  53. LPINT lpf,
  54. BOOL fStepOver
  55. )
  56. /*++
  57. Routine Description:
  58. IsCall
  59. Arguments:
  60. hthd - Supplies the handle to the thread
  61. lpaddr - Supplies the address to be check for a call instruction
  62. lpf - Returns class of instruction:
  63. INSTR_IS_CALL
  64. INSTR_BREAKPOINT
  65. INSTR_SOFT_INTERRUPT
  66. INSTR_TRACE_BIT
  67. fStepOver - Supplies step over vs step into flag
  68. Side Effects:
  69. The value of lpaddr is set to point to the returned-to
  70. instruction when the instruction is type INSTR_IS_CALL.
  71. Return Value:
  72. lpf - see Arguments.
  73. --*/
  74. {
  75. HANDLE rwHand = hthd->hprc->rwHand;
  76. DWORD opcode, function;
  77. ADDR firaddr = *lpaddr;
  78. DWORD length;
  79. ALPHA_INSTRUCTION disinstr;
  80. BOOL r;
  81. if (hthd->fIsCallDone) {
  82. *lpaddr = hthd->addrIsCall;
  83. *lpf = hthd->iInstrIsCall;
  84. return;
  85. }
  86. /*
  87. * Assume that this is not a call instruction
  88. */
  89. *lpf = INSTR_TRACE_BIT;
  90. /*
  91. * Read in the dword which contains the instruction under
  92. * inspection.
  93. */
  94. r = AddrReadMemory(hthd->hprc,
  95. hthd,
  96. &firaddr,
  97. &disinstr.Long,
  98. sizeof(DWORD),
  99. &length );
  100. if (!r || length != sizeof(DWORD)) {
  101. DPRINT(1, ("AddrReadMemory in IsCall FAILED"));
  102. return;
  103. }
  104. /*
  105. * Assume that this is a jump instruction and get the opcode.
  106. * This is the top 6 bits of the instruction dword.
  107. */
  108. opcode = disinstr.Jump.Opcode;
  109. /*
  110. * Jump and Branch to Subroutine are CALLs
  111. */
  112. if (opcode == JMP_OP) {
  113. function = disinstr.Jump.Function;
  114. if (function == JSR_FUNC) {
  115. *lpf = INSTR_IS_CALL;
  116. }
  117. }
  118. if (opcode == BSR_OP) {
  119. *lpf = INSTR_IS_CALL;
  120. }
  121. /*
  122. * There are several PAL breakpoint operations,
  123. * and a couple operations redirect control
  124. */
  125. if (opcode == CALLPAL_OP) {
  126. function = disinstr.Pal.Function;
  127. switch(function) {
  128. case (BPT_FUNC):
  129. case (CALLKD_FUNC):
  130. case (KBPT_FUNC):
  131. *lpf = INSTR_BREAKPOINT;
  132. break;
  133. case (CALLSYS_FUNC):
  134. case (GENTRAP_FUNC):
  135. *lpf = INSTR_IS_CALL;
  136. break;
  137. default:
  138. break;
  139. }
  140. }
  141. DPRINT(1, ("(IsCall?) FIR=%08x Type=%s\n", firaddr,
  142. *lpf==INSTR_IS_CALL ? "CALL":
  143. (*lpf==INSTR_BREAKPOINT ? "BREAKPOINT":
  144. (*lpf==INSTR_SOFT_INTERRUPT ? "INTERRUPT":
  145. "NORMAL"))));
  146. if (*lpf==INSTR_IS_CALL) {
  147. lpaddr->addr.off += sizeof (disinstr);
  148. hthd->addrIsCall = *lpaddr;
  149. }
  150. hthd->iInstrIsCall = *lpf;
  151. return;
  152. } /* IsCall() */
  153. ULONG
  154. GetNextOffset (
  155. HTHDX hthd,
  156. BOOL fStep
  157. )
  158. /*++
  159. Routine Description:
  160. From a limited disassembly of the instruction pointed
  161. by the FIR register, compute the offset of the next
  162. instruction for either a trace or step operation.
  163. trace -> the next instruction to execute
  164. step -> the instruction in the next memory location or the
  165. next instruction executed due to a branch (step
  166. over subroutine calls).
  167. Arguments:
  168. hthd - Supplies the handle to the thread to get the next offset for
  169. fStep - Supplies TRUE for STEP offset and FALSE for trace offset
  170. Returns:
  171. step or trace offset if input is TRUE or FALSE, respectively
  172. Version Information:
  173. This copy of GetNextOffset is from ntsd\alpha\ntdis.c@v16 (11/14/92)
  174. --*/
  175. {
  176. ULONG returnvalue;
  177. ULONG opcode;
  178. ULONG updatedpc;
  179. ULONG branchTarget;
  180. BOOL r;
  181. ULONGLONG Rav;
  182. ULONGLONG Fav;
  183. ULONGLONG Rbv;
  184. DWORD length;
  185. PULONGLONG RegArray = &hthd->context.IntV0;
  186. ADDR firaddr;
  187. ALPHA_INSTRUCTION disinstr;
  188. AddrFromHthdx(&firaddr, hthd);
  189. //
  190. // relative addressing updates PC first
  191. // Assume next sequential instruction is next offset
  192. //
  193. updatedpc = firaddr.addr.off + sizeof(ULONG);
  194. r = AddrReadMemory(hthd->hprc,
  195. hthd,
  196. &firaddr,
  197. &disinstr.Long,
  198. sizeof(DWORD),
  199. &length );
  200. if (!r || length != sizeof(DWORD)) {
  201. DPRINT(1, ("GetNextOffset: failed AddrReadMemory %x\n", disinstr.Long));
  202. assert(FALSE);
  203. return 4;
  204. }
  205. opcode = disinstr.Memory.Opcode;
  206. returnvalue = updatedpc;
  207. switch(findTypeFromOpcode(opcode)) {
  208. case ALPHA_CALLPAL:
  209. if (disinstr.Pal.Function == CALLSYS_FUNC) {
  210. return (DWORD)RegArray[RA_REG];
  211. }
  212. break;
  213. case ALPHA_JUMP:
  214. switch(disinstr.Jump.Function) {
  215. case JSR_FUNC:
  216. case JSR_CO_FUNC:
  217. if (fStep) {
  218. //
  219. // Step over the subroutine call;
  220. //
  221. return(returnvalue);
  222. }
  223. //
  224. // fall through
  225. //
  226. case JMP_FUNC:
  227. case RET_FUNC:
  228. Rbv = RegArray[disinstr.Memory.Rb];
  229. return (DWORD)(Rbv & (~3));
  230. break;
  231. }
  232. break;
  233. case ALPHA_BRANCH:
  234. branchTarget = (updatedpc + (disinstr.Branch.BranchDisp * 4));
  235. Rav = RegArray[disinstr.Memory.Ra];
  236. if (FVerbose) {
  237. DPRINT(1, ("Rav %08Lx returnValue %08lx branchTarget %08lx\n",
  238. Rav, returnvalue, branchTarget));
  239. }
  240. switch(opcode) {
  241. case BR_OP: return(branchTarget); break;
  242. case BSR_OP: if (!fStep) return(branchTarget); break;
  243. case BEQ_OP: if (Rav == 0) return(branchTarget); break;
  244. case BLT_OP: if (Rav < 0) return(branchTarget); break;
  245. case BLE_OP: if (Rav <= 0) return(branchTarget); break;
  246. case BNE_OP: if (Rav != 0) return(branchTarget); break;
  247. case BGE_OP: if (Rav >= 0) return(branchTarget); break;
  248. case BGT_OP: if (Rav > 0) return(branchTarget); break;
  249. case BLBC_OP: if ((Rav & 0x1) == 0) return(branchTarget); break;
  250. case BLBS_OP: if ((Rav & 0x1) == 1) return(branchTarget); break;
  251. };
  252. return returnvalue;
  253. break;
  254. case ALPHA_FP_BRANCH:
  255. branchTarget = (updatedpc + (disinstr.Branch.BranchDisp * 4));
  256. RegArray = &hthd->context.FltF0;
  257. Fav = RegArray[disinstr.Branch.Ra];
  258. if (Fav == 0x8000000000000000) {
  259. Fav = 0;
  260. }
  261. if (FVerbose) {
  262. DPRINT(1, ("Fav %08Lx returnValue %08lx branchTarget %08lx\n",
  263. Fav, returnvalue, branchTarget));
  264. }
  265. switch(opcode) {
  266. case FBEQ_OP: if (Fav == 0) return (branchTarget); break;
  267. case FBLT_OP: if (Fav < 0) return (branchTarget); break;
  268. case FBNE_OP: if (Fav != 0) return (branchTarget); break;
  269. case FBLE_OP: if (Fav <= 0) return (branchTarget); break;
  270. case FBGE_OP: if (Fav >= 0) return (branchTarget); break;
  271. case FBGT_OP: if (Fav > 0) return (branchTarget); break;
  272. };
  273. return returnvalue;
  274. break;
  275. }
  276. return returnvalue;
  277. }
  278. XOSD
  279. SetupFunctionCall(
  280. LPEXECUTE_OBJECT_DM lpeo,
  281. LPEXECUTE_STRUCT lpes
  282. )
  283. {
  284. /*
  285. * Can only execute functions on the current stopped thread. Therefore
  286. * assert that the current thread is stopped.
  287. */
  288. assert(lpeo->hthd->tstate & ts_stopped);
  289. if (!(lpeo->hthd->tstate & ts_stopped)) {
  290. return xosdInvalidThread;
  291. }
  292. /*
  293. * Now get the current stack offset.
  294. */
  295. lpeo->addrStack.addr.off = (DWORD)lpeo->hthd->context.IntSp;
  296. /*
  297. * Now place the return address correctly
  298. */
  299. lpeo->hthd->context.Fir = lpeo->hthd->context.IntRa =
  300. (LONG)lpeo->addrStart.addr.off;
  301. /*
  302. * Set the instruction pointer to the starting addresses
  303. * and write the context back out
  304. */
  305. lpeo->hthd->context.Fir = (LONG)lpeo->addrStart.addr.off;
  306. lpeo->hthd->fContextDirty = TRUE;
  307. return xosdNone;
  308. }
  309. BOOL
  310. CompareStacks(
  311. LPEXECUTE_OBJECT_DM lpeo
  312. )
  313. /*++
  314. Routine Description:
  315. This routine is used to determine if the stack pointers are correct
  316. for terminating function evaluation.
  317. Arguments:
  318. lpeo - Supplies the pointer to the DM Execute Object description
  319. Return Value:
  320. TRUE if the evaluation is to be terminated and FALSE otherwise
  321. --*/
  322. {
  323. if (lpeo->addrStack.addr.off <= (DWORD)lpeo->hthd->context.IntSp) {
  324. return TRUE;
  325. }
  326. return FALSE;
  327. } /* CompareStacks() */
  328. BOOL
  329. ProcessFrameStackWalkNextCmd(
  330. HPRCX hprc,
  331. HTHDX hthd,
  332. PCONTEXT context,
  333. LPVOID pctxPtrs
  334. )
  335. {
  336. return FALSE;
  337. } // ProcessFrameStackWalkNextCmd
  338. #if DBG
  339. ULONG RtlDebugFlags = 0;
  340. #define RTL_DBG_VIRTUAL_UNWIND 1
  341. #define RTL_DBG_VIRTUAL_UNWIND_DETAIL 2
  342. //
  343. // Define an array of symbolic names for the integer registers.
  344. //
  345. PCHAR RtlpIntegerRegisterNames[32] = {
  346. "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", // 0 - 7
  347. "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", // 8 - 15
  348. "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", // 16 - 23
  349. "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", // 24 - 31
  350. };
  351. //
  352. // This function disassembles the instruction at the given address. It is
  353. // only used for debugging and recognizes only those few instructions that
  354. // are relevant during reverse execution of the prologue by virtual unwind.
  355. //
  356. VOID
  357. _RtlpDebugDisassemble (
  358. IN ULONG ControlPc,
  359. IN PCONTEXT ContextRecord
  360. )
  361. {
  362. UCHAR Comments[50];
  363. PULONGLONG FloatingRegister;
  364. ULONG Function;
  365. ULONG Hint;
  366. ULONG Literal8;
  367. ALPHA_INSTRUCTION Instruction;
  368. PULONGLONG IntegerRegister;
  369. LONG Offset16;
  370. UCHAR Operands[20];
  371. ULONG Opcode;
  372. PCHAR OpName;
  373. ULONG Ra;
  374. ULONG Rb;
  375. ULONG Rc;
  376. PCHAR RaName;
  377. PCHAR RbName;
  378. PCHAR RcName;
  379. if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND_DETAIL) {
  380. Instruction.Long = *((PULONG)ControlPc);
  381. Hint = Instruction.Jump.Hint;
  382. Literal8 = Instruction.OpLit.Literal;
  383. Offset16 = Instruction.Memory.MemDisp;
  384. Opcode = Instruction.Memory.Opcode;
  385. Ra = Instruction.OpReg.Ra;
  386. RaName = RtlpIntegerRegisterNames[Ra];
  387. Rb = Instruction.OpReg.Rb;
  388. RbName = RtlpIntegerRegisterNames[Rb];
  389. Rc = Instruction.OpReg.Rc;
  390. RcName = RtlpIntegerRegisterNames[Rc];
  391. IntegerRegister = &ContextRecord->IntV0;
  392. FloatingRegister = &ContextRecord->FltF0;
  393. OpName = NULL;
  394. switch (Opcode) {
  395. case JMP_OP :
  396. if (Instruction.Jump.Function == RET_FUNC) {
  397. OpName = "ret";
  398. sprintf(Operands, "%s, (%s), %04lx", RaName, RbName, Hint);
  399. sprintf(Comments, "%s = %Lx", RbName, IntegerRegister[Rb]);
  400. }
  401. break;
  402. case LDAH_OP :
  403. case LDA_OP :
  404. case STQ_OP :
  405. if (Opcode == LDA_OP) {
  406. OpName = "lda";
  407. } else if (Opcode == LDAH_OP) {
  408. OpName = "ldah";
  409. } else if (Opcode == STQ_OP) {
  410. OpName = "stq";
  411. }
  412. sprintf(Operands, "%s, $%d(%s)", RaName, Offset16, RbName);
  413. sprintf(Comments, "%s = %Lx", RaName, IntegerRegister[Ra]);
  414. break;
  415. case ARITH_OP :
  416. case BIT_OP :
  417. Function = Instruction.OpReg.Function;
  418. if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC)) {
  419. OpName = "addq";
  420. } else if ((Opcode == ARITH_OP) && (Function == SUBQ_FUNC)) {
  421. OpName = "subq";
  422. } else if ((Opcode == BIT_OP) && (Function == BIS_FUNC)) {
  423. OpName = "bis";
  424. } else {
  425. break;
  426. }
  427. if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) {
  428. sprintf(Operands, "%s, %s, %s", RaName, RbName, RcName);
  429. } else {
  430. sprintf(Operands, "%s, $%d, %s", RaName, Literal8, RcName);
  431. }
  432. sprintf(Comments, "%s = %Lx", RcName, IntegerRegister[Rc]);
  433. break;
  434. case FPOP_OP :
  435. if (Instruction.FpOp.Function == CPYS_FUNC) {
  436. OpName = "cpys";
  437. sprintf(Operands, "f%d, f%d, f%d", Ra, Rb, Rc);
  438. sprintf(Comments, "f%d = %Lx", Rc, FloatingRegister[Rc]);
  439. }
  440. break;
  441. case STT_OP :
  442. OpName = "stt";
  443. sprintf(Operands, "f%d, $%d(%s)", Ra, Offset16, RbName);
  444. sprintf(Comments, "f%d = %Lx", Ra, FloatingRegister[Ra]);
  445. break;
  446. }
  447. if (OpName == NULL) {
  448. OpName = "???";
  449. sprintf(Operands, "...");
  450. sprintf(Comments, "Unknown to virtual unwind.");
  451. }
  452. DEBUG_PRINT_5(" %08lx: %08lx %-5s %-16s // %s\n",
  453. ControlPc, Instruction.Long, OpName, Operands, Comments);
  454. }
  455. return;
  456. }
  457. #define _RtlpFoundTrapFrame(NextPc) \
  458. if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) { \
  459. DEBUG_PRINT_1(" *** Looks like a trap frame (fake prologue), Fir = %lx\n", \
  460. NextPc); \
  461. }
  462. #else
  463. #define _RtlpDebugDisassemble(ControlPc, ContextRecord)
  464. #define _RtlpFoundTrapFrame(NextPc)
  465. #endif
  466. //
  467. // MBH - this value is redefined in windbg common code to be IntSp.
  468. //
  469. #define SP_REG 30
  470. DWORD
  471. BranchUnassemble(
  472. void *Memory,
  473. ADDR *Addr,
  474. BOOL *IsBranch,
  475. BOOL *TargetKnown,
  476. BOOL *IsCall,
  477. BOOL *IsTable,
  478. ADDR *Target
  479. )
  480. {
  481. ULONG OpCode;
  482. ALPHA_INSTRUCTION *Instr;
  483. UOFF32 TargetOffset;
  484. UNREFERENCED_PARAMETER( Addr );
  485. assert( Memory );
  486. assert( IsBranch );
  487. assert( TargetKnown );
  488. assert( IsCall );
  489. assert( Target );
  490. *IsBranch = FALSE;
  491. *IsTable = FALSE;
  492. TargetOffset = 0;
  493. Instr = (ALPHA_INSTRUCTION *)Memory;
  494. OpCode = Instr->Jump.Opcode;
  495. switch ( OpCode ) {
  496. case JMP_OP:
  497. switch ( Instr->Jump.Function ) {
  498. case JMP_FUNC:
  499. case RET_FUNC:
  500. *IsBranch = TRUE;
  501. *IsCall = FALSE;
  502. *TargetKnown = FALSE;
  503. break;
  504. case JSR_FUNC:
  505. case JSR_CO_FUNC:
  506. ;*IsBranch = TRUE;
  507. *IsCall = TRUE;
  508. *TargetKnown = FALSE;
  509. break;
  510. }
  511. break;
  512. case CALLPAL_OP:
  513. switch( Instr->Pal.Function ) {
  514. case CALLSYS_FUNC:
  515. case GENTRAP_FUNC:
  516. *IsBranch = TRUE;
  517. *IsCall = TRUE;
  518. *TargetKnown = FALSE;
  519. break;
  520. }
  521. break;
  522. case BSR_OP:
  523. *IsBranch = TRUE;
  524. *IsCall = TRUE;
  525. *TargetKnown = TRUE;
  526. TargetOffset = (GetAddrOff(*Addr) + 4) + (Instr->Branch.BranchDisp << 2);
  527. break;
  528. case BR_OP:
  529. case FBEQ_OP:
  530. case FBLT_OP:
  531. case FBLE_OP:
  532. case FBNE_OP:
  533. case FBGE_OP:
  534. case FBGT_OP:
  535. case BLBC_OP:
  536. case BEQ_OP:
  537. case BLT_OP:
  538. case BLE_OP:
  539. case BLBS_OP:
  540. case BNE_OP:
  541. case BGE_OP:
  542. case BGT_OP:
  543. *IsBranch = TRUE;
  544. *IsCall = FALSE;
  545. *TargetKnown = TRUE;
  546. TargetOffset = (GetAddrOff(*Addr) + 4) + (Instr->Branch.BranchDisp << 2);
  547. break;
  548. default:
  549. break;
  550. }
  551. AddrInit( Target, 0, 0, TargetOffset, TRUE, TRUE, FALSE, FALSE );
  552. return sizeof( DWORD );
  553. }
  554. #ifndef KERNEL
  555. VOID
  556. MakeThreadSuspendItselfHelper(
  557. HTHDX hthd,
  558. FARPROC lpSuspendThread
  559. )
  560. {
  561. //
  562. // set up the args to SuspendThread
  563. //
  564. // GetCurrentThread always returns a magic cookie, safe for any thread.
  565. hthd->context.IntA0 = (DWORD)GetCurrentThread();
  566. hthd->context.IntRa = PC(hthd);
  567. PC(hthd) = (LONG)lpSuspendThread;
  568. hthd->fContextDirty = TRUE;
  569. }
  570. #endif // !KERNEL
  571. BOOL
  572. DecodeSingleStepEvent(
  573. HTHDX hthd,
  574. DEBUG_EVENT *de,
  575. PDWORD eventCode,
  576. PDWORD subClass
  577. )
  578. /*++
  579. Routine Description:
  580. Arguments:
  581. hthd - Supplies thread that has a single step exception pending
  582. de - Supplies the DEBUG_EVENT structure for the exception
  583. eventCode - Returns the remapped debug event id
  584. subClass - Returns the remapped subClass id
  585. Return Value:
  586. TRUE if event was a real single step or was successfully mapped
  587. to a breakpoint. FALSE if a register breakpoint occurred which was
  588. not expected.
  589. --*/
  590. {
  591. return FALSE;
  592. }