1
0

frame_info.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. // Copyright (C) 2012 Y_Less
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a
  4. // copy of this software and associated documentation files (the "Software"),
  5. // to deal in the Software without restriction, including without limitation
  6. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7. // and/or sell copies of the Software, and to permit persons to whom the
  8. // Software is furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  14. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19. // DEALINGS IN THE SOFTWARE.
  20. #if defined FRAME_INFO_INC
  21. #endinput
  22. #endif
  23. #define FRAME_INFO_INC
  24. #include "amx_header"
  25. #include "amx_base"
  26. #include "opcode"
  27. stock GetCurrentFrame() {
  28. #emit lctrl 5
  29. #emit push.pri
  30. #emit lref.s.pri 0xfffffffc
  31. #emit stack 4
  32. #emit retn
  33. return 0; // make compiler happy
  34. }
  35. stock GetFramePreviousFrame(frm_addr) {
  36. #emit lref.s.pri frm_addr
  37. #emit retn
  38. return 0; // make compiler happy
  39. }
  40. stock GetFrameReturn(frm_addr) {
  41. #emit load.s.pri frm_addr
  42. #emit add.c 4
  43. #emit push.pri
  44. #emit lref.s.pri 0xfffffffc
  45. #emit stack 4
  46. #emit retn
  47. return 0; // make compiler happy
  48. }
  49. stock SetFramePreviousFrame(frm_addr, addr) {
  50. #emit load.s.pri frm_addr
  51. #emit push.pri
  52. #emit load.s.alt addr
  53. #emit sref.s.alt 0xfffffffc
  54. #emit stack 4
  55. #emit retn
  56. }
  57. stock SetFrameReturn(frm_addr, addr) {
  58. #emit load.s.pri frm_addr
  59. #emit add.c 4
  60. #emit push.pri
  61. #emit load.s.alt addr
  62. #emit sref.s.alt 0xfffffffc
  63. #emit stack 4
  64. #emit retn
  65. }
  66. stock SetFrameParameterSize(frm_addr, size) {
  67. #emit load.s.pri frm_addr
  68. #emit add.c 8
  69. #emit push.pri
  70. #emit load.s.pri size
  71. #emit sref.s.pri 0xfffffffc
  72. #emit stack 4
  73. #emit retn
  74. }
  75. stock SetFrameParameterCount(frm_addr, count) {
  76. SetFrameParameterSize(frm_addr, count << 2);
  77. }
  78. stock GetFrameTotalSize(frm_addr) {
  79. return GetFrameLocalSize(frm_addr) + GetFrameHeaderSize(frm_addr) + GetFrameParameterSize(frm_addr);
  80. }
  81. stock GetFrameTotalCount(frm_addr) {
  82. return GetFrameTotalSize(frm_addr) / 4;
  83. }
  84. stock GetFrameNextFrame(frm_addr) {
  85. // this function always works because it is at the top of the stack
  86. // run back through the stack
  87. new cur_frm = GetCurrentFrame();
  88. while (cur_frm != 0) {
  89. new prev_frm = GetFramePreviousFrame(cur_frm);
  90. if (prev_frm == frm_addr) {
  91. break;
  92. }
  93. cur_frm = prev_frm;
  94. }
  95. return cur_frm;
  96. }
  97. stock GetFrameLocalSize(frm_addr) {
  98. // run back through the stack
  99. new next_frm = GetFrameNextFrame(frm_addr);
  100. // find the size of local variables in the selected frame
  101. new frm_bottom = next_frm + GetFrameHeaderSize(next_frm) + GetFrameParameterSize(next_frm);
  102. return frm_addr - frm_bottom;
  103. }
  104. stock GetFrameLocalCount(frm_addr) {
  105. return GetFrameLocalSize(frm_addr) / 4;
  106. }
  107. stock GetFrameHeaderSize(frm_addr) {
  108. #pragma unused frm_addr
  109. return 12;
  110. }
  111. stock GetFrameHeaderCount(frm_addr) {
  112. return GetFrameHeaderSize(frm_addr) / 4;
  113. }
  114. stock GetFrameParameterSize(frm_addr) {
  115. #emit load.s.pri frm_addr
  116. #emit add.c 8
  117. #emit push.pri
  118. #emit lref.s.pri 0xfffffffc
  119. #emit stack 4
  120. #emit retn
  121. return 0; // make compiler happy
  122. }
  123. stock GetFrameParameterCount(frm_addr) {
  124. return GetFrameParameterSize(frm_addr) / 4;
  125. }
  126. stock GetFrameParameter(frm_addr, param, idx = -1) {
  127. if (idx == -1) {
  128. #emit load.s.pri param
  129. #emit shl.c.pri 2
  130. #emit load.s.alt frm_addr
  131. #emit add
  132. #emit add.c 12
  133. #emit push.pri
  134. #emit lref.s.pri 0xfffffffc
  135. #emit stack 4
  136. #emit retn
  137. } else {
  138. #emit load.s.pri param
  139. #emit shl.c.pri 2
  140. #emit load.s.alt frm_addr
  141. #emit add
  142. #emit add.c 12
  143. #emit push.pri
  144. #emit lref.s.alt 0xfffffffc
  145. #emit load.s.pri idx
  146. #emit lidx
  147. #emit stack 4
  148. #emit retn
  149. }
  150. return 0; // make compiler happy
  151. }
  152. stock GetFrameVariable(frm_addr, param, idx = -1) {
  153. if (idx == -1) {
  154. #emit load.s.pri param
  155. #emit load.s.alt frm_addr
  156. #emit add
  157. #emit push.pri
  158. #emit lref.s.pri 0xfffffffc
  159. #emit stack 4
  160. #emit retn
  161. } else {
  162. #emit load.s.pri param
  163. #emit load.s.alt frm_addr
  164. #emit add
  165. #emit push.pri
  166. #emit lref.s.alt 0xfffffffc
  167. #emit load.s.pri idx
  168. #emit lidx
  169. #emit stack 4
  170. #emit retn
  171. }
  172. return 0; // make compiler happy
  173. }
  174. stock GetFrameLocal(frm_addr, param) {
  175. if (param < 0) {
  176. // probably in correct format for negative offsets
  177. #emit load.s.pri param
  178. #emit load.s.alt frm_addr
  179. #emit add
  180. #emit push.pri
  181. #emit lref.s.pri 0xfffffffc
  182. #emit stack 4
  183. #emit retn
  184. } else {
  185. #emit load.s.pri param
  186. #emit shl.c.pri 2
  187. #emit const.alt 0xfffffffc
  188. #emit sub.alt
  189. #emit load.s.alt frm_addr
  190. #emit add
  191. #emit push.pri
  192. #emit lref.s.pri 0xfffffffc
  193. #emit stack 4
  194. #emit retn
  195. }
  196. return 0; // make compiler happy
  197. }
  198. stock SetFrameParameter(frm_addr, param, value, idx = -1) {
  199. if (idx == -1) {
  200. #emit load.s.pri param
  201. #emit shl.c.pri 2
  202. #emit load.s.alt frm_addr
  203. #emit add
  204. #emit add.c 12
  205. #emit push.pri
  206. #emit load.s.pri value
  207. #emit sref.s.pri 0xfffffffc
  208. #emit stack 4
  209. #emit retn
  210. } else {
  211. #emit load.s.pri param
  212. #emit shl.c.pri 2
  213. #emit load.s.alt frm_addr
  214. #emit add
  215. #emit add.c 12
  216. #emit push.pri
  217. #emit lref.s.alt 0xfffffffc
  218. #emit load.s.pri idx
  219. #emit idxaddr
  220. #emit load.s.alt value
  221. #emit xchg
  222. #emit stor.i
  223. #emit stack 4
  224. #emit retn
  225. }
  226. return 0; // make compiler happy
  227. }
  228. stock SetFrameVariable(frm_addr, param, value, idx = -1) {
  229. if (idx == -1) {
  230. #emit load.s.pri param
  231. #emit load.s.alt frm_addr
  232. #emit add
  233. #emit push.pri
  234. #emit load.s.pri value
  235. #emit sref.s.pri 0xfffffffc
  236. #emit stack 4
  237. #emit retn
  238. } else {
  239. #emit load.s.pri param
  240. #emit load.s.alt frm_addr
  241. #emit add
  242. #emit push.pri
  243. #emit lref.s.alt 0xfffffffc
  244. #emit load.s.pri idx
  245. #emit idxaddr
  246. #emit load.s.alt value
  247. #emit xchg
  248. #emit stor.i
  249. #emit stack 4
  250. #emit retn
  251. }
  252. return 0; // make compiler happy
  253. }
  254. stock SetFrameLocal(frm_addr, param, value) {
  255. if (param < 0) {
  256. // probably in correct format for negative offsets
  257. #emit load.s.pri param
  258. #emit load.s.alt frm_addr
  259. #emit add
  260. #emit push.pri
  261. #emit load.s.pri value
  262. #emit sref.s.pri 0xfffffffc
  263. #emit stack 4
  264. #emit retn
  265. } else {
  266. #emit load.s.pri param
  267. #emit shl.c.pri 2
  268. #emit const.alt 0xfffffffc
  269. #emit sub.alt
  270. #emit load.s.alt frm_addr
  271. #emit add
  272. #emit push.pri
  273. #emit load.s.pri value
  274. #emit sref.s.pri 0xfffffffc
  275. #emit stack 4
  276. #emit retn
  277. }
  278. return 0; // make compiler happy
  279. }
  280. static stock GetCallerFrame() {
  281. #emit lctrl 5
  282. #emit push.pri
  283. #emit lref.s.pri 0xfffffffc
  284. #emit push.pri
  285. #emit lref.s.pri 0xfffffff8
  286. #emit stack 8
  287. #emit retn
  288. return 0; // make compiler happy
  289. }
  290. stock GetCurrentFramePreviousFrame() {
  291. return GetFramePreviousFrame(GetCallerFrame());
  292. }
  293. stock GetCurrentFrameReturn() {
  294. return GetFrameReturn(GetCallerFrame());
  295. }
  296. stock GetCurrentFrameTotalSize() {
  297. return GetFrameTotalSize(GetCallerFrame());
  298. }
  299. stock GetCurrentFrameTotalCount() {
  300. return GetFrameTotalCount(GetCallerFrame());
  301. }
  302. stock GetCurrentFrameLocalSize() {
  303. return GetFrameLocalSize(GetCallerFrame());
  304. }
  305. stock GetCurrentFrameLocalCount() {
  306. return GetFrameLocalCount(GetCallerFrame());
  307. }
  308. stock GetCurrentFrameHeaderSize() {
  309. return GetFrameHeaderSize(GetCallerFrame());
  310. }
  311. stock GetCurrentFrameHeaderCount() {
  312. return GetFrameHeaderCount(GetCallerFrame());
  313. }
  314. stock GetCurrentFrameParameterSize() {
  315. return GetFrameParameterSize(GetCallerFrame());
  316. }
  317. stock GetCurrentFrameParameter(param, idx = -1) {
  318. return GetFrameParameter(GetCallerFrame(), param, idx);
  319. }
  320. stock GetCurrentFrameLocal(param) {
  321. return GetFrameLocal(GetCallerFrame(), param);
  322. }
  323. stock GetCurrentFrameParameterCount() {
  324. return GetFrameParameterCount(GetCallerFrame());
  325. }
  326. stock SetCurrentFrameReturn(addr) {
  327. SetFrameReturn(GetCallerFrame(), addr);
  328. }
  329. stock SetCurrentFramePreviousFrame(addr) {
  330. SetFramePreviousFrame(GetCallerFrame(), addr);
  331. }
  332. stock SetCurrentParameterSize(size) {
  333. SetFrameParameterSize(GetCallerFrame(), size);
  334. }
  335. stock SetCurrentParameterCount(count) {
  336. SetFrameParameterCount(GetCallerFrame(), count);
  337. }
  338. stock GetFrameFunction(frm_addr) {
  339. // try to determine the start address of the function this frame is for
  340. new prev_frm = GetFramePreviousFrame(frm_addr);
  341. new amxhdr[AMX_HDR];
  342. GetAmxHeader(amxhdr);
  343. if (prev_frm == 0) {
  344. // public entry point
  345. new call_addr = GetFrameReturn(GetFrameNextFrame(frm_addr));
  346. // find the closest public/main
  347. new highest_found = 0;
  348. new defsize = amxhdr[AMX_HDR_DEFSIZE];
  349. new num_publics = (amxhdr[AMX_HDR_NATIVES] - amxhdr[AMX_HDR_PUBLICS]) / defsize;
  350. new off = amxhdr[AMX_HDR_PUBLICS] - amxhdr[AMX_HDR_DAT];
  351. for (new i = 0; i != num_publics; ++i) {
  352. new addr = ReadAmxMemory(off);
  353. off += defsize;
  354. if (highest_found < addr < call_addr) {
  355. highest_found = addr;
  356. }
  357. }
  358. if (highest_found < amxhdr[AMX_HDR_CIP] < call_addr) {
  359. highest_found = amxhdr[AMX_HDR_CIP];
  360. }
  361. // return the best found match
  362. return highest_found;
  363. } else {
  364. // called from inside the script
  365. new ret_addr = (GetFrameReturn(frm_addr) - 8) + (amxhdr[AMX_HDR_COD] - amxhdr[AMX_HDR_DAT]);
  366. new Opcode:opcode = UnrelocateOpcode(Opcode:ReadAmxMemory(ret_addr));
  367. if (opcode == OP_CALL) {
  368. // standard function call, get the call address
  369. return ReadAmxMemory(ret_addr + 4) - amxhdr[AMX_HDR_COD] - GetAmxBaseAddress();
  370. } else if (opcode == OP_SCTRL) {
  371. // modified code to call a function by pointer
  372. opcode = UnrelocateOpcode(Opcode:ReadAmxMemory(ret_addr - 8));
  373. if (opcode == OP_LOAD_PRI) {
  374. return ReadAmxMemory(ReadAmxMemory(ret_addr - 4));
  375. } else if (opcode == OP_LOAD_S_PRI) {
  376. return GetFrameVariable(prev_frm, ReadAmxMemory(ret_addr - 4));
  377. } else if (opcode == OP_CONST_PRI) {
  378. return ReadAmxMemory(ret_addr - 4);
  379. }
  380. }
  381. // guess!
  382. new end = amxhdr[AMX_HDR_COD] - amxhdr[AMX_HDR_DAT] + 8; // "halt"
  383. ret_addr = GetFrameReturn(GetFrameNextFrame(frm_addr)) + end;
  384. opcode = RelocateOpcode(OP_RETN);
  385. new Opcode:proc = RelocateOpcode(OP_PROC);
  386. while (ret_addr >= end) {
  387. if (Opcode:ReadAmxMemory(ret_addr) == proc) {
  388. if (ret_addr == end || Opcode:ReadAmxMemory(ret_addr - 4) == opcode) {
  389. // found a retn/proc pair.
  390. return ret_addr;
  391. }
  392. }
  393. ret_addr -= 4;
  394. }
  395. }
  396. // give up...
  397. return 0;
  398. }
  399. stock GetCurrentFrameFunction() {
  400. // this function gets its own caller - pointless but here for completeness
  401. return GetFrameFunction(GetCallerFrame());
  402. }