frame_info.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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 load.s.pri 0
  29. #emit retn
  30. return 0; // make compiler happy
  31. }
  32. stock GetFramePreviousFrame(frm_addr) {
  33. #emit lref.s.pri frm_addr
  34. #emit retn
  35. return 0; // make compiler happy
  36. }
  37. stock GetFrameReturn(frm_addr) {
  38. #emit load.s.pri frm_addr
  39. #emit add.c 4
  40. #emit load.i
  41. #emit retn
  42. return 0; // make compiler happy
  43. }
  44. stock SetFramePreviousFrame(frm_addr, addr) {
  45. #emit load.s.pri addr
  46. #emit sref.s.pri frm_addr
  47. #emit retn
  48. }
  49. stock SetFrameReturn(frm_addr, addr) {
  50. #emit load.s.alt addr
  51. #emit load.s.pri frm_addr
  52. #emit add.c 4
  53. #emit xchg
  54. #emit stor.i
  55. #emit retn
  56. }
  57. stock SetFrameParameterSize(frm_addr, size) {
  58. #emit load.s.alt size
  59. #emit load.s.pri frm_addr
  60. #emit add.c 8
  61. #emit xchg
  62. #emit stor.i
  63. #emit retn
  64. }
  65. stock SetFrameParameterCount(frm_addr, count) {
  66. SetFrameParameterSize(frm_addr, count << 2);
  67. }
  68. stock GetFrameTotalSize(frm_addr) {
  69. return GetFrameLocalSize(frm_addr) + GetFrameHeaderSize(frm_addr) + GetFrameParameterSize(frm_addr);
  70. }
  71. stock GetFrameTotalCount(frm_addr) {
  72. return GetFrameTotalSize(frm_addr) / 4;
  73. }
  74. stock GetFrameNextFrame(frm_addr) {
  75. // this function always works because it is at the top of the stack
  76. // run back through the stack
  77. new cur_frm = GetCurrentFrame();
  78. while (cur_frm != 0) {
  79. new prev_frm = GetFramePreviousFrame(cur_frm);
  80. if (prev_frm == frm_addr) {
  81. break;
  82. }
  83. cur_frm = prev_frm;
  84. }
  85. return cur_frm;
  86. }
  87. stock GetFrameLocalSize(frm_addr) {
  88. // run back through the stack
  89. new next_frm = GetFrameNextFrame(frm_addr);
  90. // find the size of local variables in the selected frame
  91. new frm_bottom = next_frm + GetFrameHeaderSize(next_frm) + GetFrameParameterSize(next_frm);
  92. return frm_addr - frm_bottom;
  93. }
  94. stock GetFrameLocalCount(frm_addr) {
  95. return GetFrameLocalSize(frm_addr) / 4;
  96. }
  97. stock GetFrameHeaderSize(frm_addr) {
  98. #pragma unused frm_addr
  99. return 12;
  100. }
  101. stock GetFrameHeaderCount(frm_addr) {
  102. return GetFrameHeaderSize(frm_addr) / 4;
  103. }
  104. stock GetFrameParameterSize(frm_addr) {
  105. #emit load.s.pri frm_addr
  106. #emit add.c 8
  107. #emit load.i
  108. #emit retn
  109. return 0; // make compiler happy
  110. }
  111. stock GetFrameParameterCount(frm_addr) {
  112. return GetFrameParameterSize(frm_addr) / 4;
  113. }
  114. stock GetFrameParameter(frm_addr, param, idx = -1) {
  115. if (idx == -1) {
  116. #emit load.s.pri param
  117. #emit shl.c.pri 2
  118. #emit load.s.alt frm_addr
  119. #emit add
  120. #emit add.c 12
  121. #emit push.pri
  122. #emit lref.s.pri 0xfffffffc
  123. #emit stack 4
  124. #emit retn
  125. } else {
  126. #emit load.s.pri param
  127. #emit shl.c.pri 2
  128. #emit load.s.alt frm_addr
  129. #emit add
  130. #emit add.c 12
  131. #emit push.pri
  132. #emit lref.s.alt 0xfffffffc
  133. #emit load.s.pri idx
  134. #emit lidx
  135. #emit stack 4
  136. #emit retn
  137. }
  138. return 0; // make compiler happy
  139. }
  140. stock GetFrameVariable(frm_addr, param, idx = -1) {
  141. if (idx == -1) {
  142. #emit load.s.pri param
  143. #emit load.s.alt frm_addr
  144. #emit add
  145. #emit push.pri
  146. #emit lref.s.pri 0xfffffffc
  147. #emit stack 4
  148. #emit retn
  149. } else {
  150. #emit load.s.pri param
  151. #emit load.s.alt frm_addr
  152. #emit add
  153. #emit push.pri
  154. #emit lref.s.alt 0xfffffffc
  155. #emit load.s.pri idx
  156. #emit lidx
  157. #emit stack 4
  158. #emit retn
  159. }
  160. return 0; // make compiler happy
  161. }
  162. stock GetFrameLocal(frm_addr, param) {
  163. if (param < 0) {
  164. // probably in correct format for negative offsets
  165. #emit load.s.pri param
  166. #emit load.s.alt frm_addr
  167. #emit add
  168. #emit push.pri
  169. #emit lref.s.pri 0xfffffffc
  170. #emit stack 4
  171. #emit retn
  172. } else {
  173. #emit load.s.pri param
  174. #emit shl.c.pri 2
  175. #emit const.alt 0xfffffffc
  176. #emit sub.alt
  177. #emit load.s.alt frm_addr
  178. #emit add
  179. #emit push.pri
  180. #emit lref.s.pri 0xfffffffc
  181. #emit stack 4
  182. #emit retn
  183. }
  184. return 0; // make compiler happy
  185. }
  186. stock SetFrameParameter(frm_addr, param, value, idx = -1) {
  187. if (idx == -1) {
  188. #emit load.s.pri param
  189. #emit shl.c.pri 2
  190. #emit load.s.alt frm_addr
  191. #emit add
  192. #emit add.c 12
  193. #emit push.pri
  194. #emit load.s.pri value
  195. #emit sref.s.pri 0xfffffffc
  196. #emit stack 4
  197. #emit retn
  198. } else {
  199. #emit load.s.pri param
  200. #emit shl.c.pri 2
  201. #emit load.s.alt frm_addr
  202. #emit add
  203. #emit add.c 12
  204. #emit push.pri
  205. #emit lref.s.alt 0xfffffffc
  206. #emit load.s.pri idx
  207. #emit idxaddr
  208. #emit load.s.alt value
  209. #emit xchg
  210. #emit stor.i
  211. #emit stack 4
  212. #emit retn
  213. }
  214. return 0; // make compiler happy
  215. }
  216. stock SetFrameVariable(frm_addr, param, value, idx = -1) {
  217. if (idx == -1) {
  218. #emit load.s.pri param
  219. #emit load.s.alt frm_addr
  220. #emit add
  221. #emit push.pri
  222. #emit load.s.pri value
  223. #emit sref.s.pri 0xfffffffc
  224. #emit stack 4
  225. #emit retn
  226. } else {
  227. #emit load.s.pri param
  228. #emit load.s.alt frm_addr
  229. #emit add
  230. #emit push.pri
  231. #emit lref.s.alt 0xfffffffc
  232. #emit load.s.pri idx
  233. #emit idxaddr
  234. #emit load.s.alt value
  235. #emit xchg
  236. #emit stor.i
  237. #emit stack 4
  238. #emit retn
  239. }
  240. return 0; // make compiler happy
  241. }
  242. stock SetFrameLocal(frm_addr, param, value) {
  243. if (param < 0) {
  244. // probably in correct format for negative offsets
  245. #emit load.s.pri param
  246. #emit load.s.alt frm_addr
  247. #emit add
  248. #emit push.pri
  249. #emit load.s.pri value
  250. #emit sref.s.pri 0xfffffffc
  251. #emit stack 4
  252. #emit retn
  253. } else {
  254. #emit load.s.pri param
  255. #emit shl.c.pri 2
  256. #emit const.alt 0xfffffffc
  257. #emit sub.alt
  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. }
  266. return 0; // make compiler happy
  267. }
  268. static stock GetCallerFrame() {
  269. #emit lctrl 5
  270. #emit push.pri
  271. #emit lref.s.pri 0xfffffffc
  272. #emit push.pri
  273. #emit lref.s.pri 0xfffffff8
  274. #emit stack 8
  275. #emit retn
  276. return 0; // make compiler happy
  277. }
  278. stock GetCurrentFramePreviousFrame() {
  279. return GetFramePreviousFrame(GetCallerFrame());
  280. }
  281. stock GetCurrentFrameReturn() {
  282. return GetFrameReturn(GetCallerFrame());
  283. }
  284. stock GetCurrentFrameTotalSize() {
  285. return GetFrameTotalSize(GetCallerFrame());
  286. }
  287. stock GetCurrentFrameTotalCount() {
  288. return GetFrameTotalCount(GetCallerFrame());
  289. }
  290. stock GetCurrentFrameLocalSize() {
  291. return GetFrameLocalSize(GetCallerFrame());
  292. }
  293. stock GetCurrentFrameLocalCount() {
  294. return GetFrameLocalCount(GetCallerFrame());
  295. }
  296. stock GetCurrentFrameHeaderSize() {
  297. return GetFrameHeaderSize(GetCallerFrame());
  298. }
  299. stock GetCurrentFrameHeaderCount() {
  300. return GetFrameHeaderCount(GetCallerFrame());
  301. }
  302. stock GetCurrentFrameParameterSize() {
  303. return GetFrameParameterSize(GetCallerFrame());
  304. }
  305. stock GetCurrentFrameParameter(param, idx = -1) {
  306. return GetFrameParameter(GetCallerFrame(), param, idx);
  307. }
  308. stock GetCurrentFrameLocal(param) {
  309. return GetFrameLocal(GetCallerFrame(), param);
  310. }
  311. stock GetCurrentFrameParameterCount() {
  312. return GetFrameParameterCount(GetCallerFrame());
  313. }
  314. stock SetCurrentFrameReturn(addr) {
  315. SetFrameReturn(GetCallerFrame(), addr);
  316. }
  317. stock SetCurrentFramePreviousFrame(addr) {
  318. SetFramePreviousFrame(GetCallerFrame(), addr);
  319. }
  320. stock SetCurrentParameterSize(size) {
  321. SetFrameParameterSize(GetCallerFrame(), size);
  322. }
  323. stock SetCurrentParameterCount(count) {
  324. SetFrameParameterCount(GetCallerFrame(), count);
  325. }
  326. stock GetFrameFunction(frm_addr) {
  327. // try to determine the start address of the function this frame is for
  328. new prev_frm = GetFramePreviousFrame(frm_addr);
  329. new amxhdr[AMX_HDR];
  330. GetAmxHeader(amxhdr);
  331. if (prev_frm == 0) {
  332. // public entry point
  333. new call_addr = GetFrameReturn(GetFrameNextFrame(frm_addr));
  334. // find the closest public/main
  335. new highest_found = 0;
  336. new defsize = amxhdr[AMX_HDR_DEFSIZE];
  337. new num_publics = (amxhdr[AMX_HDR_NATIVES] - amxhdr[AMX_HDR_PUBLICS]) / defsize;
  338. new off = amxhdr[AMX_HDR_PUBLICS] - amxhdr[AMX_HDR_DAT];
  339. for (new i = 0; i != num_publics; ++i) {
  340. new addr = ReadAmxMemory(off);
  341. off += defsize;
  342. if (highest_found < addr < call_addr) {
  343. highest_found = addr;
  344. }
  345. }
  346. if (highest_found < amxhdr[AMX_HDR_CIP] < call_addr) {
  347. highest_found = amxhdr[AMX_HDR_CIP];
  348. }
  349. // return the best found match
  350. return highest_found;
  351. } else {
  352. // called from inside the script
  353. new ret_addr = (GetFrameReturn(frm_addr) - 8) + (amxhdr[AMX_HDR_COD] - amxhdr[AMX_HDR_DAT]);
  354. new Opcode:opcode = UnrelocateOpcode(Opcode:ReadAmxMemory(ret_addr));
  355. if (opcode == OP_CALL) {
  356. // standard function call, get the call address
  357. return ReadAmxMemory(ret_addr + 4) - amxhdr[AMX_HDR_COD] - GetAmxBaseAddress();
  358. } else if (opcode == OP_SCTRL) {
  359. // modified code to call a function by pointer
  360. opcode = UnrelocateOpcode(Opcode:ReadAmxMemory(ret_addr - 8));
  361. if (opcode == OP_LOAD_PRI) {
  362. return ReadAmxMemory(ReadAmxMemory(ret_addr - 4));
  363. } else if (opcode == OP_LOAD_S_PRI) {
  364. return GetFrameVariable(prev_frm, ReadAmxMemory(ret_addr - 4));
  365. } else if (opcode == OP_CONST_PRI) {
  366. return ReadAmxMemory(ret_addr - 4);
  367. }
  368. }
  369. // guess!
  370. new end = amxhdr[AMX_HDR_COD] - amxhdr[AMX_HDR_DAT] + 8; // "halt"
  371. ret_addr = GetFrameReturn(GetFrameNextFrame(frm_addr)) + end;
  372. opcode = RelocateOpcode(OP_RETN);
  373. new Opcode:proc = RelocateOpcode(OP_PROC);
  374. while (ret_addr >= end) {
  375. if (Opcode:ReadAmxMemory(ret_addr) == proc) {
  376. if (ret_addr == end || Opcode:ReadAmxMemory(ret_addr - 4) == opcode) {
  377. // found a retn/proc pair.
  378. return ret_addr;
  379. }
  380. }
  381. ret_addr -= 4;
  382. }
  383. }
  384. // give up...
  385. return 0;
  386. }
  387. stock GetCurrentFrameFunction() {
  388. // this function gets its own caller - pointless but here for completeness
  389. return GetFrameFunction(GetCallerFrame());
  390. }