My Marlin configs for Fabrikator Mini and CTC i3 Pro B
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.

unwarm_thumb.cpp 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  1. /***************************************************************************
  2. * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
  3. * Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
  4. *
  5. * This program is PUBLIC DOMAIN.
  6. * This means that there is no copyright and anyone is able to take a copy
  7. * for free and use it as they wish, with or without modifications, and in
  8. * any context, commercially or otherwise. The only limitation is that I
  9. * don't guarantee that the software is fit for any purpose or accept any
  10. * liability for it's use or misuse - this software is without warranty.
  11. ***************************************************************************
  12. * File Description: Abstract interpretation for Thumb mode.
  13. **************************************************************************/
  14. #if defined(__arm__) || defined(__thumb__)
  15. #define MODULE_NAME "UNWARM_THUMB"
  16. #include <stdio.h>
  17. #include "unwarm.h"
  18. /** Sign extend an 11 bit value.
  19. * This function simply inspects bit 11 of the input \a value, and if
  20. * set, the top 5 bits are set to give a 2's compliment signed value.
  21. * \param value The value to sign extend.
  22. * \return The signed-11 bit value stored in a 16bit data type.
  23. */
  24. static int32_t signExtend11(uint16_t value) {
  25. if(value & 0x400) {
  26. value |= 0xFFFFF800;
  27. }
  28. return value;
  29. }
  30. UnwResult UnwStartThumb(UnwState * const state) {
  31. bool found = false;
  32. uint16_t t = UNW_MAX_INSTR_COUNT;
  33. uint32_t lastJumpAddr = 0; // Last JUMP address, to try to detect infinite loops
  34. bool loopDetected = false; // If a loop was detected
  35. do {
  36. uint16_t instr;
  37. /* Attempt to read the instruction */
  38. if(!state->cb->readH(state->regData[15].v & (~0x1), &instr)) {
  39. return UNWIND_IREAD_H_FAIL;
  40. }
  41. UnwPrintd4("T %x %x %04x:", state->regData[13].v, state->regData[15].v, instr);
  42. /* Check that the PC is still on Thumb alignment */
  43. if(!(state->regData[15].v & 0x1)) {
  44. UnwPrintd1("\nError: PC misalignment\n");
  45. return UNWIND_INCONSISTENT;
  46. }
  47. /* Check that the SP and PC have not been invalidated */
  48. if(!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) {
  49. UnwPrintd1("\nError: PC or SP invalidated\n");
  50. return UNWIND_INCONSISTENT;
  51. }
  52. /*
  53. * Detect 32bit thumb instructions
  54. */
  55. if ((instr & 0xE000) == 0xE000 && (instr & 0x1800) != 0) {
  56. uint16_t instr2;
  57. /* Check next address */
  58. state->regData[15].v += 2;
  59. /* Attempt to read the 2nd part of the instruction */
  60. if(!state->cb->readH(state->regData[15].v & (~0x1), &instr2)) {
  61. return UNWIND_IREAD_H_FAIL;
  62. }
  63. UnwPrintd3(" %x %04x:", state->regData[15].v, instr2);
  64. /*
  65. * Load/Store multiple: Only interpret
  66. * PUSH and POP
  67. */
  68. if ((instr & 0xFE6F) == 0xE82D) {
  69. bool L = (instr & 0x10) ? true : false;
  70. uint16_t rList = instr2;
  71. if(L) {
  72. uint8_t r;
  73. /* Load from memory: POP */
  74. UnwPrintd1("POP {Rlist}\n");
  75. /* Load registers from stack */
  76. for(r = 0; r < 16; r++) {
  77. if(rList & (0x1 << r)) {
  78. /* Read the word */
  79. if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
  80. return UNWIND_DREAD_W_FAIL;
  81. }
  82. /* Alter the origin to be from the stack if it was valid */
  83. if(M_IsOriginValid(state->regData[r].o)) {
  84. state->regData[r].o = REG_VAL_FROM_STACK;
  85. /* If restoring the PC */
  86. if (r == 15) {
  87. /* The bottom bit should have been set to indicate that
  88. * the caller was from Thumb. This would allow return
  89. * by BX for interworking APCS.
  90. */
  91. if((state->regData[15].v & 0x1) == 0) {
  92. UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
  93. /* Pop into the PC will not switch mode */
  94. return UNWIND_INCONSISTENT;
  95. }
  96. /* Store the return address */
  97. if(!UnwReportRetAddr(state, state->regData[15].v)) {
  98. return UNWIND_TRUNCATED;
  99. }
  100. /* Now have the return address */
  101. UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
  102. /* Compensate for the auto-increment, which isn't needed here */
  103. state->regData[15].v -= 2;
  104. }
  105. } else {
  106. if (r == 15) {
  107. /* Return address is not valid */
  108. UnwPrintd1("PC popped with invalid address\n");
  109. return UNWIND_FAILURE;
  110. }
  111. }
  112. state->regData[13].v += 4;
  113. UnwPrintd3(" r%d = 0x%08x\n", r, state->regData[r].v);
  114. }
  115. }
  116. }
  117. else {
  118. int8_t r;
  119. /* Store to memory: PUSH */
  120. UnwPrintd1("PUSH {Rlist}");
  121. for(r = 15; r >= 0; r--) {
  122. if(rList & (0x1 << r)) {
  123. UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
  124. state->regData[13].v -= 4;
  125. if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
  126. return UNWIND_DWRITE_W_FAIL;
  127. }
  128. }
  129. }
  130. }
  131. }
  132. /*
  133. * PUSH register
  134. */
  135. else if (instr == 0xF84D && (instr2 & 0x0FFF) == 0x0D04) {
  136. uint8_t r = instr2 >> 12;
  137. /* Store to memory: PUSH */
  138. UnwPrintd2("PUSH {R%d}\n", r);
  139. UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
  140. state->regData[13].v -= 4;
  141. if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
  142. return UNWIND_DWRITE_W_FAIL;
  143. }
  144. }
  145. /*
  146. * POP register
  147. */
  148. else if (instr == 0xF85D && (instr2 & 0x0FFF) == 0x0B04) {
  149. uint8_t r = instr2 >> 12;
  150. /* Load from memory: POP */
  151. UnwPrintd2("POP {R%d}\n", r);
  152. /* Read the word */
  153. if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
  154. return UNWIND_DREAD_W_FAIL;
  155. }
  156. /* Alter the origin to be from the stack if it was valid */
  157. if(M_IsOriginValid(state->regData[r].o)) {
  158. state->regData[r].o = REG_VAL_FROM_STACK;
  159. /* If restoring the PC */
  160. if (r == 15) {
  161. /* The bottom bit should have been set to indicate that
  162. * the caller was from Thumb. This would allow return
  163. * by BX for interworking APCS.
  164. */
  165. if((state->regData[15].v & 0x1) == 0) {
  166. UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
  167. /* Pop into the PC will not switch mode */
  168. return UNWIND_INCONSISTENT;
  169. }
  170. /* Store the return address */
  171. if(!UnwReportRetAddr(state, state->regData[15].v)) {
  172. return UNWIND_TRUNCATED;
  173. }
  174. /* Now have the return address */
  175. UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
  176. /* Compensate for the auto-increment, which isn't needed here */
  177. state->regData[15].v -= 2;
  178. }
  179. } else {
  180. if (r == 15) {
  181. /* Return address is not valid */
  182. UnwPrintd1("PC popped with invalid address\n");
  183. return UNWIND_FAILURE;
  184. }
  185. }
  186. state->regData[13].v += 4;
  187. UnwPrintd3(" r%d = 0x%08x\n", r, state->regData[r].v);
  188. }
  189. /*
  190. * TBB / TBH
  191. */
  192. else if ((instr & 0xFFF0) == 0xE8D0 && (instr2 & 0xFFE0) == 0xF000) {
  193. /* We are only interested in
  194. * the forms
  195. * TBB [PC, ...]
  196. * TBH [PC, ..., LSL #1]
  197. * as those are used by the C compiler to implement
  198. * the switch clauses
  199. */
  200. uint8_t rn = instr & 0xF;
  201. bool H = (instr2 & 0x10) ? true : false;
  202. UnwPrintd5("TB%c [r%d,r%d%s]\n", H ? 'H' : 'B', rn, (instr2 & 0xF), H ? ",LSL #1" : "");
  203. // We are only interested if the RN is the PC. Let's choose the 1st destination
  204. if (rn == 15) {
  205. if (H) {
  206. uint16_t rv;
  207. if(!state->cb->readH((state->regData[15].v & (~1)) + 2, &rv)) {
  208. return UNWIND_DREAD_H_FAIL;
  209. }
  210. state->regData[15].v += rv * 2;
  211. } else {
  212. uint8_t rv;
  213. if(!state->cb->readB((state->regData[15].v & (~1)) + 2, &rv)) {
  214. return UNWIND_DREAD_B_FAIL;
  215. }
  216. state->regData[15].v += rv * 2;
  217. }
  218. }
  219. }
  220. /*
  221. * Unconditional branch
  222. */
  223. else if ((instr & 0xF800) == 0xF000 && (instr2 & 0xD000) == 0x9000) {
  224. uint32_t v;
  225. uint8_t S = (instr & 0x400) >> 10;
  226. uint16_t imm10 = (instr & 0x3FF);
  227. uint8_t J1 = (instr2 & 0x2000) >> 13;
  228. uint8_t J2 = (instr2 & 0x0800) >> 11;
  229. uint16_t imm11 = (instr2 & 0x7FF);
  230. uint8_t I1 = J1 ^ S ^ 1;
  231. uint8_t I2 = J2 ^ S ^ 1;
  232. uint32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) |(imm10 << 12) | (imm11 << 1);
  233. if (S) imm32 |= 0xFE000000;
  234. UnwPrintd2("B %d \n", imm32);
  235. /* Update PC */
  236. state->regData[15].v += imm32;
  237. /* Need to advance by a word to account for pre-fetch.
  238. * Advance by a half word here, allowing the normal address
  239. * advance to account for the other half word.
  240. */
  241. state->regData[15].v += 2;
  242. /* Compute the jump address */
  243. v = state->regData[15].v + 2;
  244. /* Display PC of next instruction */
  245. UnwPrintd2(" New PC=%x", v);
  246. /* Did we detect an infinite loop ? */
  247. loopDetected = lastJumpAddr == v;
  248. /* Remember the last address we jumped to */
  249. lastJumpAddr = v;
  250. }
  251. /*
  252. * Branch with link
  253. */
  254. else if ((instr & 0xF800) == 0xF000 && (instr2 & 0xD000) == 0xD000) {
  255. uint8_t S = (instr & 0x400) >> 10;
  256. uint16_t imm10 = (instr & 0x3FF);
  257. uint8_t J1 = (instr2 & 0x2000) >> 13;
  258. uint8_t J2 = (instr2 & 0x0800) >> 11;
  259. uint16_t imm11 = (instr2 & 0x7FF);
  260. uint8_t I1 = J1 ^ S ^ 1;
  261. uint8_t I2 = J2 ^ S ^ 1;
  262. uint32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) |(imm10 << 12) | (imm11 << 1);
  263. if (S) imm32 |= 0xFE000000;
  264. UnwPrintd2("BL %d \n", imm32);
  265. /* Never taken, as we are unwinding the stack */
  266. if (0) {
  267. /* Store return address in LR register */
  268. state->regData[14].v = state->regData[15].v + 2;
  269. state->regData[14].o = REG_VAL_FROM_CONST;
  270. /* Update PC */
  271. state->regData[15].v += imm32;
  272. /* Need to advance by a word to account for pre-fetch.
  273. * Advance by a half word here, allowing the normal address
  274. * advance to account for the other half word.
  275. */
  276. state->regData[15].v += 2;
  277. /* Display PC of next instruction */
  278. UnwPrintd2(" Return PC=%x", state->regData[15].v);
  279. /* Report the return address, including mode bit */
  280. if(!UnwReportRetAddr(state, state->regData[15].v)) {
  281. return UNWIND_TRUNCATED;
  282. }
  283. /* Determine the new mode */
  284. if(state->regData[15].v & 0x1) {
  285. /* Branching to THUMB */
  286. /* Account for the auto-increment which isn't needed */
  287. state->regData[15].v -= 2;
  288. }
  289. else {
  290. /* Branch to ARM */
  291. return UnwStartArm(state);
  292. }
  293. }
  294. }
  295. /*
  296. * Conditional branches. Usually not taken, unless infinite loop is detected
  297. */
  298. else if ((instr & 0xF800) == 0xF000 && (instr2 & 0xD000) == 0x8000) {
  299. uint8_t S = (instr & 0x400) >> 10;
  300. uint16_t imm6 = (instr & 0x3F);
  301. uint8_t J1 = (instr2 & 0x2000) >> 13;
  302. uint8_t J2 = (instr2 & 0x0800) >> 11;
  303. uint16_t imm11 = (instr2 & 0x7FF);
  304. uint8_t I1 = J1 ^ S ^ 1;
  305. uint8_t I2 = J2 ^ S ^ 1;
  306. uint32_t imm32 = (S << 20) | (I1 << 19) | (I2 << 18) |(imm6 << 12) | (imm11 << 1);
  307. if (S) imm32 |= 0xFFE00000;
  308. UnwPrintd2("Bcond %d\n", imm32);
  309. /* Take the jump only if a loop is detected */
  310. if (loopDetected) {
  311. /* Update PC */
  312. state->regData[15].v += imm32;
  313. /* Need to advance by a word to account for pre-fetch.
  314. * Advance by a half word here, allowing the normal address
  315. * advance to account for the other half word.
  316. */
  317. state->regData[15].v += 2;
  318. /* Display PC of next instruction */
  319. UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
  320. }
  321. }
  322. /*
  323. * PC-relative load
  324. * LDR Rd,[PC, #+/-imm]
  325. */
  326. else if((instr & 0xFF7F) == 0xF85F) {
  327. uint8_t rt = (instr2 & 0xF000) >> 12;
  328. uint8_t imm12 = (instr2 & 0x0FFF);
  329. bool A = (instr & 0x80) ? true : false;
  330. uint32_t address;
  331. /* Compute load address, adding a word to account for prefetch */
  332. address = (state->regData[15].v & (~0x3)) + 4;
  333. if (A) address += imm12;
  334. else address -= imm12;
  335. UnwPrintd4("LDR r%d,[PC #%c0x%08x]", rt, A?'+':'-', address);
  336. if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
  337. return UNWIND_DREAD_W_FAIL;
  338. }
  339. }
  340. /*
  341. * LDR immediate.
  342. * We are only interested when destination is PC.
  343. * LDR Rt,[Rn , #n]
  344. */
  345. else if ((instr & 0xFFF0) == 0xF8D0) {
  346. uint8_t rn = (instr & 0xF);
  347. uint8_t rt = (instr2 & 0xF000) >> 12;
  348. uint16_t imm12 = (instr2 & 0xFFF);
  349. /* If destination is PC and we don't know the source value, then fail */
  350. if (!M_IsOriginValid(state->regData[rn].o)) {
  351. state->regData[rt].o = state->regData[rn].o;
  352. } else {
  353. uint32_t address = state->regData[rn].v + imm12;
  354. if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
  355. return UNWIND_DREAD_W_FAIL;
  356. }
  357. }
  358. }
  359. /*
  360. * LDR immediate
  361. * We are only interested when destination is PC.
  362. * LDR Rt,[Rn , #-n]
  363. * LDR Rt,[Rn], #+/-n]
  364. * LDR Rt,[Rn, #+/-n]!
  365. */
  366. else if ((instr & 0xFFF0) == 0xF850 && (instr2 & 0x0800) == 0x0800) {
  367. uint8_t rn = (instr & 0xF);
  368. uint8_t rt = (instr2 & 0xF000) >> 12;
  369. uint16_t imm8 = (instr2 & 0xFF);
  370. bool P = (instr2 & 0x400) ? true : false;
  371. bool U = (instr2 & 0x200) ? true : false;
  372. bool W = (instr2 & 0x100) ? true : false;
  373. if (!M_IsOriginValid(state->regData[rn].o)) {
  374. state->regData[rt].o = state->regData[rn].o;
  375. } else {
  376. uint32_t offaddress = state->regData[rn].v + imm8;
  377. if (U) offaddress += imm8;
  378. else offaddress -= imm8;
  379. uint32_t address;
  380. if (P) {
  381. address = offaddress;
  382. } else {
  383. address = state->regData[rn].v;
  384. }
  385. if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
  386. return UNWIND_DREAD_W_FAIL;
  387. }
  388. if (W) {
  389. state->regData[rn].v = offaddress;
  390. }
  391. }
  392. }
  393. /*
  394. * LDR (register).
  395. * We are interested in the form
  396. * ldr Rt, [Rn, Rm, lsl #x]
  397. * Where Rt is PC, Rn value is known, Rm is not known or unknown
  398. */
  399. else if ((instr & 0xFFF0) == 0xF850 && (instr2 & 0x0FC0) == 0x0000) {
  400. uint8_t rn = (instr & 0xF);
  401. uint8_t rt = (instr2 & 0xF000) >> 12;
  402. uint8_t rm = (instr2 & 0xF);
  403. uint8_t imm2 = (instr2 & 0x30) >> 4;
  404. if (!M_IsOriginValid(state->regData[rn].o) ||
  405. !M_IsOriginValid(state->regData[rm].o)) {
  406. /* If Rt is PC, and Rn is known, then do an exception and assume
  407. Rm equals 0 => This takes the first case in a switch() */
  408. if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
  409. uint32_t address = state->regData[rn].v;
  410. if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
  411. return UNWIND_DREAD_W_FAIL;
  412. }
  413. } else {
  414. /* Propagate unknown value */
  415. state->regData[rt].o = state->regData[rn].o;
  416. }
  417. } else {
  418. uint32_t address = state->regData[rn].v + (state->regData[rm].v << imm2);
  419. if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
  420. return UNWIND_DREAD_W_FAIL;
  421. }
  422. }
  423. }
  424. else {
  425. UnwPrintd1("???? (32)");
  426. /* Unknown/undecoded. May alter some register, so invalidate file */
  427. UnwInvalidateRegisterFile(state->regData);
  428. }
  429. /* End of thumb 32bit code */
  430. }
  431. /* Format 1: Move shifted register
  432. * LSL Rd, Rs, #Offset5
  433. * LSR Rd, Rs, #Offset5
  434. * ASR Rd, Rs, #Offset5
  435. */
  436. else if((instr & 0xE000) == 0x0000 && (instr & 0x1800) != 0x1800) {
  437. bool signExtend;
  438. uint8_t op = (instr & 0x1800) >> 11;
  439. uint8_t offset5 = (instr & 0x07C0) >> 6;
  440. uint8_t rs = (instr & 0x0038) >> 3;
  441. uint8_t rd = (instr & 0x0007);
  442. switch(op) {
  443. case 0: /* LSL */
  444. UnwPrintd6("LSL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
  445. state->regData[rd].v = state->regData[rs].v << offset5;
  446. state->regData[rd].o = state->regData[rs].o;
  447. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  448. break;
  449. case 1: /* LSR */
  450. UnwPrintd6("LSR r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
  451. state->regData[rd].v = state->regData[rs].v >> offset5;
  452. state->regData[rd].o = state->regData[rs].o;
  453. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  454. break;
  455. case 2: /* ASR */
  456. UnwPrintd6("ASL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o));
  457. signExtend = (state->regData[rs].v & 0x8000) ? true : false;
  458. state->regData[rd].v = state->regData[rs].v >> offset5;
  459. if(signExtend) {
  460. state->regData[rd].v |= 0xFFFFFFFF << (32 - offset5);
  461. }
  462. state->regData[rd].o = state->regData[rs].o;
  463. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  464. break;
  465. }
  466. }
  467. /* Format 2: add/subtract
  468. * ADD Rd, Rs, Rn
  469. * ADD Rd, Rs, #Offset3
  470. * SUB Rd, Rs, Rn
  471. * SUB Rd, Rs, #Offset3
  472. */
  473. else if((instr & 0xF800) == 0x1800) {
  474. bool I = (instr & 0x0400) ? true : false;
  475. bool op = (instr & 0x0200) ? true : false;
  476. uint8_t rn = (instr & 0x01C0) >> 6;
  477. uint8_t rs = (instr & 0x0038) >> 3;
  478. uint8_t rd = (instr & 0x0007);
  479. /* Print decoding */
  480. UnwPrintd6("%s r%d, r%d, %c%d\t;",op ? "SUB" : "ADD",rd, rs,I ? '#' : 'r',rn);
  481. UnwPrintd5("r%d %s, r%d %s",rd, M_Origin2Str(state->regData[rd].o),rs, M_Origin2Str(state->regData[rs].o));
  482. if(!I) {
  483. UnwPrintd3(", r%d %s", rn, M_Origin2Str(state->regData[rn].o));
  484. /* Perform calculation */
  485. if(op) {
  486. state->regData[rd].v = state->regData[rs].v - state->regData[rn].v;
  487. }
  488. else {
  489. state->regData[rd].v = state->regData[rs].v + state->regData[rn].v;
  490. }
  491. /* Propagate the origin */
  492. if(M_IsOriginValid(state->regData[rs].o) &&
  493. M_IsOriginValid(state->regData[rn].o)) {
  494. state->regData[rd].o = state->regData[rs].o;
  495. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  496. }
  497. else {
  498. state->regData[rd].o = REG_VAL_INVALID;
  499. }
  500. }
  501. else {
  502. /* Perform calculation */
  503. if(op) {
  504. state->regData[rd].v = state->regData[rs].v - rn;
  505. }
  506. else {
  507. state->regData[rd].v = state->regData[rs].v + rn;
  508. }
  509. /* Propagate the origin */
  510. state->regData[rd].o = state->regData[rs].o;
  511. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  512. }
  513. }
  514. /* Format 3: move/compare/add/subtract immediate
  515. * MOV Rd, #Offset8
  516. * CMP Rd, #Offset8
  517. * ADD Rd, #Offset8
  518. * SUB Rd, #Offset8
  519. */
  520. else if((instr & 0xE000) == 0x2000) {
  521. uint8_t op = (instr & 0x1800) >> 11;
  522. uint8_t rd = (instr & 0x0700) >> 8;
  523. uint8_t offset8 = (instr & 0x00FF);
  524. switch(op) {
  525. case 0: /* MOV */
  526. UnwPrintd3("MOV r%d, #0x%x", rd, offset8);
  527. state->regData[rd].v = offset8;
  528. state->regData[rd].o = REG_VAL_FROM_CONST;
  529. break;
  530. case 1: /* CMP */
  531. /* Irrelevant to unwinding */
  532. UnwPrintd1("CMP ???");
  533. break;
  534. case 2: /* ADD */
  535. UnwPrintd5("ADD r%d, #0x%x\t; r%d %s", rd, offset8, rd, M_Origin2Str(state->regData[rd].o));
  536. state->regData[rd].v += offset8;
  537. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  538. break;
  539. case 3: /* SUB */
  540. UnwPrintd5("SUB r%d, #0x%d\t; r%d %s", rd, offset8, rd, M_Origin2Str(state->regData[rd].o));
  541. state->regData[rd].v -= offset8;
  542. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  543. break;
  544. }
  545. }
  546. /* Format 4: ALU operations
  547. * AND Rd, Rs
  548. * EOR Rd, Rs
  549. * LSL Rd, Rs
  550. * LSR Rd, Rs
  551. * ASR Rd, Rs
  552. * ADC Rd, Rs
  553. * SBC Rd, Rs
  554. * ROR Rd, Rs
  555. * TST Rd, Rs
  556. * NEG Rd, Rs
  557. * CMP Rd, Rs
  558. * CMN Rd, Rs
  559. * ORR Rd, Rs
  560. * MUL Rd, Rs
  561. * BIC Rd, Rs
  562. * MVN Rd, Rs
  563. */
  564. else if((instr & 0xFC00) == 0x4000) {
  565. uint8_t op = (instr & 0x03C0) >> 6;
  566. uint8_t rs = (instr & 0x0038) >> 3;
  567. uint8_t rd = (instr & 0x0007);
  568. #if defined(UNW_DEBUG)
  569. static const char * const mnu[16] = {
  570. "AND", "EOR", "LSL", "LSR",
  571. "ASR", "ADC", "SBC", "ROR",
  572. "TST", "NEG", "CMP", "CMN",
  573. "ORR", "MUL", "BIC", "MVN" };
  574. #endif
  575. /* Print the mnemonic and registers */
  576. switch(op) {
  577. case 0: /* AND */
  578. case 1: /* EOR */
  579. case 2: /* LSL */
  580. case 3: /* LSR */
  581. case 4: /* ASR */
  582. case 7: /* ROR */
  583. case 9: /* NEG */
  584. case 12: /* ORR */
  585. case 13: /* MUL */
  586. case 15: /* MVN */
  587. UnwPrintd8("%s r%d ,r%d\t; r%d %s, r%d %s",mnu[op],rd, rs, rd, M_Origin2Str(state->regData[rd].o), rs, M_Origin2Str(state->regData[rs].o));
  588. break;
  589. case 5: /* ADC */
  590. case 6: /* SBC */
  591. UnwPrintd4("%s r%d, r%d", mnu[op], rd, rs);
  592. break;
  593. case 8: /* TST */
  594. case 10: /* CMP */
  595. case 11: /* CMN */
  596. /* Irrelevant to unwinding */
  597. UnwPrintd2("%s ???", mnu[op]);
  598. break;
  599. case 14: /* BIC */
  600. UnwPrintd5("r%d ,r%d\t; r%d %s", rd, rs, rs, M_Origin2Str(state->regData[rs].o));
  601. break;
  602. }
  603. /* Perform operation */
  604. switch(op) {
  605. case 0: /* AND */
  606. state->regData[rd].v &= state->regData[rs].v;
  607. break;
  608. case 1: /* EOR */
  609. state->regData[rd].v ^= state->regData[rs].v;
  610. break;
  611. case 2: /* LSL */
  612. state->regData[rd].v <<= state->regData[rs].v;
  613. break;
  614. case 3: /* LSR */
  615. state->regData[rd].v >>= state->regData[rs].v;
  616. break;
  617. case 4: /* ASR */
  618. if(state->regData[rd].v & 0x80000000) {
  619. state->regData[rd].v >>= state->regData[rs].v;
  620. state->regData[rd].v |= 0xFFFFFFFF << (32 - state->regData[rs].v);
  621. }
  622. else {
  623. state->regData[rd].v >>= state->regData[rs].v;
  624. }
  625. break;
  626. case 5: /* ADC */
  627. case 6: /* SBC */
  628. case 8: /* TST */
  629. case 10: /* CMP */
  630. case 11: /* CMN */
  631. break;
  632. case 7: /* ROR */
  633. state->regData[rd].v = (state->regData[rd].v >> state->regData[rs].v) |
  634. (state->regData[rd].v << (32 - state->regData[rs].v));
  635. break;
  636. case 9: /* NEG */
  637. state->regData[rd].v = -state->regData[rs].v;
  638. break;
  639. case 12: /* ORR */
  640. state->regData[rd].v |= state->regData[rs].v;
  641. break;
  642. case 13: /* MUL */
  643. state->regData[rd].v *= state->regData[rs].v;
  644. break;
  645. case 14: /* BIC */
  646. state->regData[rd].v &= ~state->regData[rs].v;
  647. break;
  648. case 15: /* MVN */
  649. state->regData[rd].v = ~state->regData[rs].v;
  650. break;
  651. }
  652. /* Propagate data origins */
  653. switch(op) {
  654. case 0: /* AND */
  655. case 1: /* EOR */
  656. case 2: /* LSL */
  657. case 3: /* LSR */
  658. case 4: /* ASR */
  659. case 7: /* ROR */
  660. case 12: /* ORR */
  661. case 13: /* MUL */
  662. case 14: /* BIC */
  663. if(M_IsOriginValid(state->regData[rd].o) && M_IsOriginValid(state->regData[rs].o)) {
  664. state->regData[rd].o = state->regData[rs].o;
  665. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  666. }
  667. else {
  668. state->regData[rd].o = REG_VAL_INVALID;
  669. }
  670. break;
  671. case 5: /* ADC */
  672. case 6: /* SBC */
  673. /* C-bit not tracked */
  674. state->regData[rd].o = REG_VAL_INVALID;
  675. break;
  676. case 8: /* TST */
  677. case 10: /* CMP */
  678. case 11: /* CMN */
  679. /* Nothing propagated */
  680. break;
  681. case 9: /* NEG */
  682. case 15: /* MVN */
  683. state->regData[rd].o = state->regData[rs].o;
  684. state->regData[rd].o |= REG_VAL_ARITHMETIC;
  685. break;
  686. }
  687. }
  688. /* Format 5: Hi register operations/branch exchange
  689. * ADD Rd, Hs
  690. * CMP Hd, Rs
  691. * MOV Hd, Hs
  692. */
  693. else if((instr & 0xFC00) == 0x4400) {
  694. uint8_t op = (instr & 0x0300) >> 8;
  695. bool h1 = (instr & 0x0080) ? true: false;
  696. bool h2 = (instr & 0x0040) ? true: false;
  697. uint8_t rhs = (instr & 0x0038) >> 3;
  698. uint8_t rhd = (instr & 0x0007);
  699. /* Adjust the register numbers */
  700. if(h2)
  701. rhs += 8;
  702. if(h1)
  703. rhd += 8;
  704. switch(op) {
  705. case 0: /* ADD */
  706. UnwPrintd5("ADD r%d, r%d\t; r%d %s", rhd, rhs, rhs, M_Origin2Str(state->regData[rhs].o));
  707. state->regData[rhd].v += state->regData[rhs].v;
  708. state->regData[rhd].o = state->regData[rhs].o;
  709. state->regData[rhd].o |= REG_VAL_ARITHMETIC;
  710. break;
  711. case 1: /* CMP */
  712. /* Irrelevant to unwinding */
  713. UnwPrintd1("CMP ???");
  714. break;
  715. case 2: /* MOV */
  716. UnwPrintd5("MOV r%d, r%d\t; r%d %s", rhd, rhs, rhd, M_Origin2Str(state->regData[rhs].o));
  717. state->regData[rhd].v = state->regData[rhs].v;
  718. state->regData[rhd].o = state->regData[rhd].o;
  719. break;
  720. case 3: /* BX */
  721. UnwPrintd4("BX r%d\t; r%d %s\n", rhs, rhs, M_Origin2Str(state->regData[rhs].o));
  722. /* Only follow BX if the data was from the stack or BX LR */
  723. if(rhs == 14 || state->regData[rhs].o == REG_VAL_FROM_STACK) {
  724. UnwPrintd2(" Return PC=0x%x\n", state->regData[rhs].v & (~0x1));
  725. /* Report the return address, including mode bit */
  726. if(!UnwReportRetAddr(state, state->regData[rhs].v)) {
  727. return UNWIND_TRUNCATED;
  728. }
  729. /* Update the PC */
  730. state->regData[15].v = state->regData[rhs].v;
  731. /* Determine the new mode */
  732. if(state->regData[rhs].v & 0x1) {
  733. /* Branching to THUMB */
  734. /* Account for the auto-increment which isn't needed */
  735. state->regData[15].v -= 2;
  736. }
  737. else {
  738. /* Branch to ARM */
  739. return UnwStartArm(state);
  740. }
  741. }
  742. else {
  743. UnwPrintd4("\nError: BX to invalid register: r%d = 0x%x (%s)\n", rhs, state->regData[rhs].o, M_Origin2Str(state->regData[rhs].o));
  744. return UNWIND_FAILURE;
  745. }
  746. }
  747. }
  748. /* Format 9: PC-relative load
  749. * LDR Rd,[PC, #imm]
  750. */
  751. else if((instr & 0xF800) == 0x4800) {
  752. uint8_t rd = (instr & 0x0700) >> 8;
  753. uint8_t word8 = (instr & 0x00FF);
  754. uint32_t address;
  755. /* Compute load address, adding a word to account for prefetch */
  756. address = (state->regData[15].v & (~0x3)) + 4 + (word8 << 2);
  757. UnwPrintd3("LDR r%d, 0x%08x", rd, address);
  758. if(!UnwMemReadRegister(state, address, &state->regData[rd])) {
  759. return UNWIND_DREAD_W_FAIL;
  760. }
  761. }
  762. /* Format 13: add offset to Stack Pointer
  763. * ADD sp,#+imm
  764. * ADD sp,#-imm
  765. */
  766. else if((instr & 0xFF00) == 0xB000) {
  767. uint8_t value = (instr & 0x7F) * 4;
  768. /* Check the negative bit */
  769. if((instr & 0x80) != 0) {
  770. UnwPrintd2("SUB sp,#0x%x", value);
  771. state->regData[13].v -= value;
  772. }
  773. else {
  774. UnwPrintd2("ADD sp,#0x%x", value);
  775. state->regData[13].v += value;
  776. }
  777. }
  778. /* Format 14: push/pop registers
  779. * PUSH {Rlist}
  780. * PUSH {Rlist, LR}
  781. * POP {Rlist}
  782. * POP {Rlist, PC}
  783. */
  784. else if((instr & 0xF600) == 0xB400) {
  785. bool L = (instr & 0x0800) ? true : false;
  786. bool R = (instr & 0x0100) ? true : false;
  787. uint8_t rList = (instr & 0x00FF);
  788. if(L) {
  789. uint8_t r;
  790. /* Load from memory: POP */
  791. UnwPrintd2("POP {Rlist%s}\n", R ? ", PC" : "");
  792. for(r = 0; r < 8; r++) {
  793. if(rList & (0x1 << r)) {
  794. /* Read the word */
  795. if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[r])) {
  796. return UNWIND_DREAD_W_FAIL;
  797. }
  798. /* Alter the origin to be from the stack if it was valid */
  799. if(M_IsOriginValid(state->regData[r].o)) {
  800. state->regData[r].o = REG_VAL_FROM_STACK;
  801. }
  802. state->regData[13].v += 4;
  803. UnwPrintd3(" r%d = 0x%08x\n", r, state->regData[r].v);
  804. }
  805. }
  806. /* Check if the PC is to be popped */
  807. if(R) {
  808. /* Get the return address */
  809. if(!UnwMemReadRegister(state, state->regData[13].v, &state->regData[15])) {
  810. return UNWIND_DREAD_W_FAIL;
  811. }
  812. /* Alter the origin to be from the stack if it was valid */
  813. if(!M_IsOriginValid(state->regData[15].o)) {
  814. /* Return address is not valid */
  815. UnwPrintd1("PC popped with invalid address\n");
  816. return UNWIND_FAILURE;
  817. }
  818. else {
  819. /* The bottom bit should have been set to indicate that
  820. * the caller was from Thumb. This would allow return
  821. * by BX for interworking APCS.
  822. */
  823. if((state->regData[15].v & 0x1) == 0) {
  824. UnwPrintd2("Warning: Return address not to Thumb: 0x%08x\n", state->regData[15].v);
  825. /* Pop into the PC will not switch mode */
  826. return UNWIND_INCONSISTENT;
  827. }
  828. /* Store the return address */
  829. if(!UnwReportRetAddr(state, state->regData[15].v)) {
  830. return UNWIND_TRUNCATED;
  831. }
  832. /* Now have the return address */
  833. UnwPrintd2(" Return PC=%x\n", state->regData[15].v);
  834. /* Update the pc */
  835. state->regData[13].v += 4;
  836. /* Compensate for the auto-increment, which isn't needed here */
  837. state->regData[15].v -= 2;
  838. }
  839. }
  840. }
  841. else {
  842. int8_t r;
  843. /* Store to memory: PUSH */
  844. UnwPrintd2("PUSH {Rlist%s}", R ? ", LR" : "");
  845. /* Check if the LR is to be pushed */
  846. if(R) {
  847. UnwPrintd3("\n lr = 0x%08x\t; %s", state->regData[14].v, M_Origin2Str(state->regData[14].o));
  848. state->regData[13].v -= 4;
  849. /* Write the register value to memory */
  850. if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[14])) {
  851. return UNWIND_DWRITE_W_FAIL;
  852. }
  853. }
  854. for(r = 7; r >= 0; r--) {
  855. if(rList & (0x1 << r)) {
  856. UnwPrintd4("\n r%d = 0x%08x\t; %s", r, state->regData[r].v, M_Origin2Str(state->regData[r].o));
  857. state->regData[13].v -= 4;
  858. if(!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
  859. return UNWIND_DWRITE_W_FAIL;
  860. }
  861. }
  862. }
  863. }
  864. }
  865. /*
  866. * Conditional branches
  867. * Bcond
  868. */
  869. else if((instr & 0xF000) == 0xD000) {
  870. int32_t branchValue = (instr & 0xFF);
  871. if (branchValue & 0x80) branchValue |= 0xFFFFFF00;
  872. /* Branch distance is twice that specified in the instruction. */
  873. branchValue *= 2;
  874. UnwPrintd2("Bcond %d \n", branchValue);
  875. /* Only take the branch if a loop was detected */
  876. if (loopDetected) {
  877. /* Update PC */
  878. state->regData[15].v += branchValue;
  879. /* Need to advance by a word to account for pre-fetch.
  880. * Advance by a half word here, allowing the normal address
  881. * advance to account for the other half word.
  882. */
  883. state->regData[15].v += 2;
  884. /* Display PC of next instruction */
  885. UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
  886. }
  887. }
  888. /* Format 18: unconditional branch
  889. * B label
  890. */
  891. else if((instr & 0xF800) == 0xE000) {
  892. uint32_t v;
  893. int32_t branchValue = signExtend11(instr & 0x07FF);
  894. /* Branch distance is twice that specified in the instruction. */
  895. branchValue *= 2;
  896. UnwPrintd2("B %d \n", branchValue);
  897. /* Update PC */
  898. state->regData[15].v += branchValue;
  899. /* Need to advance by a word to account for pre-fetch.
  900. * Advance by a half word here, allowing the normal address
  901. * advance to account for the other half word.
  902. */
  903. state->regData[15].v += 2;
  904. /* Compute the jump address */
  905. v = state->regData[15].v + 2;
  906. /* Display PC of next instruction */
  907. UnwPrintd2(" New PC=%x", v);
  908. /* Did we detect an infinite loop ? */
  909. loopDetected = lastJumpAddr == v;
  910. /* Remember the last address we jumped to */
  911. lastJumpAddr = v;
  912. }
  913. else {
  914. UnwPrintd1("????");
  915. /* Unknown/undecoded. May alter some register, so invalidate file */
  916. UnwInvalidateRegisterFile(state->regData);
  917. }
  918. UnwPrintd1("\n");
  919. /* Should never hit the reset vector */
  920. if(state->regData[15].v == 0)
  921. return UNWIND_RESET;
  922. /* Check next address */
  923. state->regData[15].v += 2;
  924. /* Garbage collect the memory hash (used only for the stack) */
  925. UnwMemHashGC(state);
  926. t--;
  927. if(t == 0)
  928. return UNWIND_EXHAUSTED;
  929. } while(!found);
  930. return UNWIND_SUCCESS;
  931. }
  932. #endif