metasm 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -740,6 +740,147 @@ EOL
740
740
  end
741
741
 
742
742
  patch_rubylib_to_current_interpreter
743
+
744
+ # mandiant import hash crap with ordinal imports (from pefile.py)
745
+ ih_ws232 = {
746
+ 1 => 'accept', 2 => 'bind', 3 => 'closesocket', 4 => 'connect',
747
+ 5 => 'getpeername', 6 => 'getsockname', 7 => 'getsockopt', 8 => 'htonl',
748
+ 9 => 'htons', 10 => 'ioctlsocket', 11 => 'inet_addr', 12 => 'inet_ntoa',
749
+ 13 => 'listen', 14 => 'ntohl', 15 => 'ntohs', 16 => 'recv',
750
+ 17 => 'recvfrom', 18 => 'select', 19 => 'send', 20 => 'sendto',
751
+ 21 => 'setsockopt', 22 => 'shutdown', 23 => 'socket', 24 => 'GetAddrInfoW',
752
+ 25 => 'GetNameInfoW', 26 => 'WSApSetPostRoutine', 27 => 'FreeAddrInfoW', 28 => 'WPUCompleteOverlappedRequest',
753
+ 29 => 'WSAAccept', 30 => 'WSAAddressToStringA', 31 => 'WSAAddressToStringW', 32 => 'WSACloseEvent',
754
+ 33 => 'WSAConnect', 34 => 'WSACreateEvent', 35 => 'WSADuplicateSocketA', 36 => 'WSADuplicateSocketW',
755
+ 37 => 'WSAEnumNameSpaceProvidersA', 38 => 'WSAEnumNameSpaceProvidersW', 39 => 'WSAEnumNetworkEvents', 40 => 'WSAEnumProtocolsA',
756
+ 41 => 'WSAEnumProtocolsW', 42 => 'WSAEventSelect', 43 => 'WSAGetOverlappedResult', 44 => 'WSAGetQOSByName',
757
+ 45 => 'WSAGetServiceClassInfoA', 46 => 'WSAGetServiceClassInfoW', 47 => 'WSAGetServiceClassNameByClassIdA', 48 => 'WSAGetServiceClassNameByClassIdW',
758
+ 49 => 'WSAHtonl', 50 => 'WSAHtons', 51 => 'gethostbyaddr', 52 => 'gethostbyname',
759
+ 53 => 'getprotobyname', 54 => 'getprotobynumber', 55 => 'getservbyname', 56 => 'getservbyport',
760
+ 57 => 'gethostname', 58 => 'WSAInstallServiceClassA', 59 => 'WSAInstallServiceClassW', 60 => 'WSAIoctl',
761
+ 61 => 'WSAJoinLeaf', 62 => 'WSALookupServiceBeginA', 63 => 'WSALookupServiceBeginW', 64 => 'WSALookupServiceEnd',
762
+ 65 => 'WSALookupServiceNextA', 66 => 'WSALookupServiceNextW', 67 => 'WSANSPIoctl', 68 => 'WSANtohl',
763
+ 69 => 'WSANtohs', 70 => 'WSAProviderConfigChange', 71 => 'WSARecv', 72 => 'WSARecvDisconnect',
764
+ 73 => 'WSARecvFrom', 74 => 'WSARemoveServiceClass', 75 => 'WSAResetEvent', 76 => 'WSASend',
765
+ 77 => 'WSASendDisconnect', 78 => 'WSASendTo', 79 => 'WSASetEvent', 80 => 'WSASetServiceA',
766
+ 81 => 'WSASetServiceW', 82 => 'WSASocketA', 83 => 'WSASocketW', 84 => 'WSAStringToAddressA',
767
+ 85 => 'WSAStringToAddressW', 86 => 'WSAWaitForMultipleEvents', 87 => 'WSCDeinstallProvider', 88 => 'WSCEnableNSProvider',
768
+ 89 => 'WSCEnumProtocols', 90 => 'WSCGetProviderPath', 91 => 'WSCInstallNameSpace', 92 => 'WSCInstallProvider',
769
+ 93 => 'WSCUnInstallNameSpace', 94 => 'WSCUpdateProvider', 95 => 'WSCWriteNameSpaceOrder', 96 => 'WSCWriteProviderOrder',
770
+ 97 => 'freeaddrinfo', 98 => 'getaddrinfo', 99 => 'getnameinfo', 101 => 'WSAAsyncSelect',
771
+ 102 => 'WSAAsyncGetHostByAddr', 103 => 'WSAAsyncGetHostByName', 104 => 'WSAAsyncGetProtoByNumber', 105 => 'WSAAsyncGetProtoByName',
772
+ 106 => 'WSAAsyncGetServByPort', 107 => 'WSAAsyncGetServByName', 108 => 'WSACancelAsyncRequest', 109 => 'WSASetBlockingHook',
773
+ 110 => 'WSAUnhookBlockingHook', 111 => 'WSAGetLastError', 112 => 'WSASetLastError', 113 => 'WSACancelBlockingCall',
774
+ 114 => 'WSAIsBlocking', 115 => 'WSAStartup', 116 => 'WSACleanup', 151 => '__WSAFDIsSet',
775
+ 500 => 'WEP',
776
+ }
777
+
778
+ IMPORT_HASH = {
779
+ 'ws2_32' => ih_ws232,
780
+ 'wsock2' => ih_ws232,
781
+ 'oleaut' => {
782
+ 2 => 'SysAllocString', 3 => 'SysReAllocString', 4 => 'SysAllocStringLen', 5 => 'SysReAllocStringLen',
783
+ 6 => 'SysFreeString', 7 => 'SysStringLen', 8 => 'VariantInit', 9 => 'VariantClear',
784
+ 10 => 'VariantCopy', 11 => 'VariantCopyInd', 12 => 'VariantChangeType', 13 => 'VariantTimeToDosDateTime',
785
+ 14 => 'DosDateTimeToVariantTime', 15 => 'SafeArrayCreate', 16 => 'SafeArrayDestroy', 17 => 'SafeArrayGetDim',
786
+ 18 => 'SafeArrayGetElemsize', 19 => 'SafeArrayGetUBound', 20 => 'SafeArrayGetLBound', 21 => 'SafeArrayLock',
787
+ 22 => 'SafeArrayUnlock', 23 => 'SafeArrayAccessData', 24 => 'SafeArrayUnaccessData', 25 => 'SafeArrayGetElement',
788
+ 26 => 'SafeArrayPutElement', 27 => 'SafeArrayCopy', 28 => 'DispGetParam', 29 => 'DispGetIDsOfNames',
789
+ 30 => 'DispInvoke', 31 => 'CreateDispTypeInfo', 32 => 'CreateStdDispatch', 33 => 'RegisterActiveObject',
790
+ 34 => 'RevokeActiveObject', 35 => 'GetActiveObject', 36 => 'SafeArrayAllocDescriptor', 37 => 'SafeArrayAllocData',
791
+ 38 => 'SafeArrayDestroyDescriptor', 39 => 'SafeArrayDestroyData', 40 => 'SafeArrayRedim', 41 => 'SafeArrayAllocDescriptorEx',
792
+ 42 => 'SafeArrayCreateEx', 43 => 'SafeArrayCreateVectorEx', 44 => 'SafeArraySetRecordInfo', 45 => 'SafeArrayGetRecordInfo',
793
+ 46 => 'VarParseNumFromStr', 47 => 'VarNumFromParseNum', 48 => 'VarI2FromUI1', 49 => 'VarI2FromI4',
794
+ 50 => 'VarI2FromR4', 51 => 'VarI2FromR8', 52 => 'VarI2FromCy', 53 => 'VarI2FromDate',
795
+ 54 => 'VarI2FromStr', 55 => 'VarI2FromDisp', 56 => 'VarI2FromBool', 57 => 'SafeArraySetIID',
796
+ 58 => 'VarI4FromUI1', 59 => 'VarI4FromI2', 60 => 'VarI4FromR4', 61 => 'VarI4FromR8',
797
+ 62 => 'VarI4FromCy', 63 => 'VarI4FromDate', 64 => 'VarI4FromStr', 65 => 'VarI4FromDisp',
798
+ 66 => 'VarI4FromBool', 67 => 'SafeArrayGetIID', 68 => 'VarR4FromUI1', 69 => 'VarR4FromI2',
799
+ 70 => 'VarR4FromI4', 71 => 'VarR4FromR8', 72 => 'VarR4FromCy', 73 => 'VarR4FromDate',
800
+ 74 => 'VarR4FromStr', 75 => 'VarR4FromDisp', 76 => 'VarR4FromBool', 77 => 'SafeArrayGetVartype',
801
+ 78 => 'VarR8FromUI1', 79 => 'VarR8FromI2', 80 => 'VarR8FromI4', 81 => 'VarR8FromR4',
802
+ 82 => 'VarR8FromCy', 83 => 'VarR8FromDate', 84 => 'VarR8FromStr', 85 => 'VarR8FromDisp',
803
+ 86 => 'VarR8FromBool', 87 => 'VarFormat', 88 => 'VarDateFromUI1', 89 => 'VarDateFromI2',
804
+ 90 => 'VarDateFromI4', 91 => 'VarDateFromR4', 92 => 'VarDateFromR8', 93 => 'VarDateFromCy',
805
+ 94 => 'VarDateFromStr', 95 => 'VarDateFromDisp', 96 => 'VarDateFromBool', 97 => 'VarFormatDateTime',
806
+ 98 => 'VarCyFromUI1', 99 => 'VarCyFromI2', 100 => 'VarCyFromI4', 101 => 'VarCyFromR4',
807
+ 102 => 'VarCyFromR8', 103 => 'VarCyFromDate', 104 => 'VarCyFromStr', 105 => 'VarCyFromDisp',
808
+ 106 => 'VarCyFromBool', 107 => 'VarFormatNumber', 108 => 'VarBstrFromUI1', 109 => 'VarBstrFromI2',
809
+ 110 => 'VarBstrFromI4', 111 => 'VarBstrFromR4', 112 => 'VarBstrFromR8', 113 => 'VarBstrFromCy',
810
+ 114 => 'VarBstrFromDate', 115 => 'VarBstrFromDisp', 116 => 'VarBstrFromBool', 117 => 'VarFormatPercent',
811
+ 118 => 'VarBoolFromUI1', 119 => 'VarBoolFromI2', 120 => 'VarBoolFromI4', 121 => 'VarBoolFromR4',
812
+ 122 => 'VarBoolFromR8', 123 => 'VarBoolFromDate', 124 => 'VarBoolFromCy', 125 => 'VarBoolFromStr',
813
+ 126 => 'VarBoolFromDisp', 127 => 'VarFormatCurrency', 128 => 'VarWeekdayName', 129 => 'VarMonthName',
814
+ 130 => 'VarUI1FromI2', 131 => 'VarUI1FromI4', 132 => 'VarUI1FromR4', 133 => 'VarUI1FromR8',
815
+ 134 => 'VarUI1FromCy', 135 => 'VarUI1FromDate', 136 => 'VarUI1FromStr', 137 => 'VarUI1FromDisp',
816
+ 138 => 'VarUI1FromBool', 139 => 'VarFormatFromTokens', 140 => 'VarTokenizeFormatString', 141 => 'VarAdd',
817
+ 142 => 'VarAnd', 143 => 'VarDiv', 144 => 'DllCanUnloadNow', 145 => 'DllGetClassObject',
818
+ 146 => 'DispCallFunc', 147 => 'VariantChangeTypeEx', 148 => 'SafeArrayPtrOfIndex', 149 => 'SysStringByteLen',
819
+ 150 => 'SysAllocStringByteLen', 151 => 'DllRegisterServer', 152 => 'VarEqv', 153 => 'VarIdiv',
820
+ 154 => 'VarImp', 155 => 'VarMod', 156 => 'VarMul', 157 => 'VarOr',
821
+ 158 => 'VarPow', 159 => 'VarSub', 160 => 'CreateTypeLib', 161 => 'LoadTypeLib',
822
+ 162 => 'LoadRegTypeLib', 163 => 'RegisterTypeLib', 164 => 'QueryPathOfRegTypeLib', 165 => 'LHashValOfNameSys',
823
+ 166 => 'LHashValOfNameSysA', 167 => 'VarXor', 168 => 'VarAbs', 169 => 'VarFix',
824
+ 170 => 'OaBuildVersion', 171 => 'ClearCustData', 172 => 'VarInt', 173 => 'VarNeg',
825
+ 174 => 'VarNot', 175 => 'VarRound', 176 => 'VarCmp', 177 => 'VarDecAdd',
826
+ 178 => 'VarDecDiv', 179 => 'VarDecMul', 180 => 'CreateTypeLib2', 181 => 'VarDecSub',
827
+ 182 => 'VarDecAbs', 183 => 'LoadTypeLibEx', 184 => 'SystemTimeToVariantTime', 185 => 'VariantTimeToSystemTime',
828
+ 186 => 'UnRegisterTypeLib', 187 => 'VarDecFix', 188 => 'VarDecInt', 189 => 'VarDecNeg',
829
+ 190 => 'VarDecFromUI1', 191 => 'VarDecFromI2', 192 => 'VarDecFromI4', 193 => 'VarDecFromR4',
830
+ 194 => 'VarDecFromR8', 195 => 'VarDecFromDate', 196 => 'VarDecFromCy', 197 => 'VarDecFromStr',
831
+ 198 => 'VarDecFromDisp', 199 => 'VarDecFromBool', 200 => 'GetErrorInfo', 201 => 'SetErrorInfo',
832
+ 202 => 'CreateErrorInfo', 203 => 'VarDecRound', 204 => 'VarDecCmp', 205 => 'VarI2FromI1',
833
+ 206 => 'VarI2FromUI2', 207 => 'VarI2FromUI4', 208 => 'VarI2FromDec', 209 => 'VarI4FromI1',
834
+ 210 => 'VarI4FromUI2', 211 => 'VarI4FromUI4', 212 => 'VarI4FromDec', 213 => 'VarR4FromI1',
835
+ 214 => 'VarR4FromUI2', 215 => 'VarR4FromUI4', 216 => 'VarR4FromDec', 217 => 'VarR8FromI1',
836
+ 218 => 'VarR8FromUI2', 219 => 'VarR8FromUI4', 220 => 'VarR8FromDec', 221 => 'VarDateFromI1',
837
+ 222 => 'VarDateFromUI2', 223 => 'VarDateFromUI4', 224 => 'VarDateFromDec', 225 => 'VarCyFromI1',
838
+ 226 => 'VarCyFromUI2', 227 => 'VarCyFromUI4', 228 => 'VarCyFromDec', 229 => 'VarBstrFromI1',
839
+ 230 => 'VarBstrFromUI2', 231 => 'VarBstrFromUI4', 232 => 'VarBstrFromDec', 233 => 'VarBoolFromI1',
840
+ 234 => 'VarBoolFromUI2', 235 => 'VarBoolFromUI4', 236 => 'VarBoolFromDec', 237 => 'VarUI1FromI1',
841
+ 238 => 'VarUI1FromUI2', 239 => 'VarUI1FromUI4', 240 => 'VarUI1FromDec', 241 => 'VarDecFromI1',
842
+ 242 => 'VarDecFromUI2', 243 => 'VarDecFromUI4', 244 => 'VarI1FromUI1', 245 => 'VarI1FromI2',
843
+ 246 => 'VarI1FromI4', 247 => 'VarI1FromR4', 248 => 'VarI1FromR8', 249 => 'VarI1FromDate',
844
+ 250 => 'VarI1FromCy', 251 => 'VarI1FromStr', 252 => 'VarI1FromDisp', 253 => 'VarI1FromBool',
845
+ 254 => 'VarI1FromUI2', 255 => 'VarI1FromUI4', 256 => 'VarI1FromDec', 257 => 'VarUI2FromUI1',
846
+ 258 => 'VarUI2FromI2', 259 => 'VarUI2FromI4', 260 => 'VarUI2FromR4', 261 => 'VarUI2FromR8',
847
+ 262 => 'VarUI2FromDate', 263 => 'VarUI2FromCy', 264 => 'VarUI2FromStr', 265 => 'VarUI2FromDisp',
848
+ 266 => 'VarUI2FromBool', 267 => 'VarUI2FromI1', 268 => 'VarUI2FromUI4', 269 => 'VarUI2FromDec',
849
+ 270 => 'VarUI4FromUI1', 271 => 'VarUI4FromI2', 272 => 'VarUI4FromI4', 273 => 'VarUI4FromR4',
850
+ 274 => 'VarUI4FromR8', 275 => 'VarUI4FromDate', 276 => 'VarUI4FromCy', 277 => 'VarUI4FromStr',
851
+ 278 => 'VarUI4FromDisp', 279 => 'VarUI4FromBool', 280 => 'VarUI4FromI1', 281 => 'VarUI4FromUI2',
852
+ 282 => 'VarUI4FromDec', 283 => 'BSTR_UserSize', 284 => 'BSTR_UserMarshal', 285 => 'BSTR_UserUnmarshal',
853
+ 286 => 'BSTR_UserFree', 287 => 'VARIANT_UserSize', 288 => 'VARIANT_UserMarshal', 289 => 'VARIANT_UserUnmarshal',
854
+ 290 => 'VARIANT_UserFree', 291 => 'LPSAFEARRAY_UserSize', 292 => 'LPSAFEARRAY_UserMarshal', 293 => 'LPSAFEARRAY_UserUnmarshal',
855
+ 294 => 'LPSAFEARRAY_UserFree', 295 => 'LPSAFEARRAY_Size', 296 => 'LPSAFEARRAY_Marshal', 297 => 'LPSAFEARRAY_Unmarshal',
856
+ 298 => 'VarDecCmpR8', 299 => 'VarCyAdd', 300 => 'DllUnregisterServer', 301 => 'OACreateTypeLib2',
857
+ 303 => 'VarCyMul', 304 => 'VarCyMulI4', 305 => 'VarCySub', 306 => 'VarCyAbs',
858
+ 307 => 'VarCyFix', 308 => 'VarCyInt', 309 => 'VarCyNeg', 310 => 'VarCyRound',
859
+ 311 => 'VarCyCmp', 312 => 'VarCyCmpR8', 313 => 'VarBstrCat', 314 => 'VarBstrCmp',
860
+ 315 => 'VarR8Pow', 316 => 'VarR4CmpR8', 317 => 'VarR8Round', 318 => 'VarCat',
861
+ 319 => 'VarDateFromUdateEx', 322 => 'GetRecordInfoFromGuids', 323 => 'GetRecordInfoFromTypeInfo', 325 => 'SetVarConversionLocaleSetting',
862
+ 326 => 'GetVarConversionLocaleSetting', 327 => 'SetOaNoCache', 329 => 'VarCyMulI8', 330 => 'VarDateFromUdate',
863
+ 331 => 'VarUdateFromDate', 332 => 'GetAltMonthNames', 333 => 'VarI8FromUI1', 334 => 'VarI8FromI2',
864
+ 335 => 'VarI8FromR4', 336 => 'VarI8FromR8', 337 => 'VarI8FromCy', 338 => 'VarI8FromDate',
865
+ 339 => 'VarI8FromStr', 340 => 'VarI8FromDisp', 341 => 'VarI8FromBool', 342 => 'VarI8FromI1',
866
+ 343 => 'VarI8FromUI2', 344 => 'VarI8FromUI4', 345 => 'VarI8FromDec', 346 => 'VarI2FromI8',
867
+ 347 => 'VarI2FromUI8', 348 => 'VarI4FromI8', 349 => 'VarI4FromUI8', 360 => 'VarR4FromI8',
868
+ 361 => 'VarR4FromUI8', 362 => 'VarR8FromI8', 363 => 'VarR8FromUI8', 364 => 'VarDateFromI8',
869
+ 365 => 'VarDateFromUI8', 366 => 'VarCyFromI8', 367 => 'VarCyFromUI8', 368 => 'VarBstrFromI8',
870
+ 369 => 'VarBstrFromUI8', 370 => 'VarBoolFromI8', 371 => 'VarBoolFromUI8', 372 => 'VarUI1FromI8',
871
+ 373 => 'VarUI1FromUI8', 374 => 'VarDecFromI8', 375 => 'VarDecFromUI8', 376 => 'VarI1FromI8',
872
+ 377 => 'VarI1FromUI8', 378 => 'VarUI2FromI8', 379 => 'VarUI2FromUI8', 401 => 'OleLoadPictureEx',
873
+ 402 => 'OleLoadPictureFileEx', 411 => 'SafeArrayCreateVector', 412 => 'SafeArrayCopyData', 413 => 'VectorFromBstr',
874
+ 414 => 'BstrFromVector', 415 => 'OleIconToCursor', 416 => 'OleCreatePropertyFrameIndirect', 417 => 'OleCreatePropertyFrame',
875
+ 418 => 'OleLoadPicture', 419 => 'OleCreatePictureIndirect', 420 => 'OleCreateFontIndirect', 421 => 'OleTranslateColor',
876
+ 422 => 'OleLoadPictureFile', 423 => 'OleSavePictureFile', 424 => 'OleLoadPicturePath', 425 => 'VarUI4FromI8',
877
+ 426 => 'VarUI4FromUI8', 427 => 'VarI8FromUI8', 428 => 'VarUI8FromI8', 429 => 'VarUI8FromUI1',
878
+ 430 => 'VarUI8FromI2', 431 => 'VarUI8FromR4', 432 => 'VarUI8FromR8', 433 => 'VarUI8FromCy',
879
+ 434 => 'VarUI8FromDate', 435 => 'VarUI8FromStr', 436 => 'VarUI8FromDisp', 437 => 'VarUI8FromBool',
880
+ 438 => 'VarUI8FromI1', 439 => 'VarUI8FromUI2', 440 => 'VarUI8FromUI4', 441 => 'VarUI8FromDec',
881
+ 442 => 'RegisterTypeLibForUser', 443 => 'UnRegisterTypeLibForUser',
882
+ },
883
+ }
743
884
  end
744
885
  end
745
886
 
@@ -159,13 +159,20 @@ class AsmPreprocessor < Preprocessor
159
159
  end
160
160
  end
161
161
 
162
+ class Preprocessor::Token
163
+ # token already preprocessed for macro def/expansion
164
+ attr_accessor :alreadyapp
165
+ end
166
+
162
167
  # the program (used to create new label names)
163
168
  attr_accessor :program
164
169
  # hash macro name => Macro
165
170
  attr_accessor :macro
171
+ attr_accessor :may_apreprocess
166
172
 
167
173
  def initialize(text='', program=nil)
168
174
  @program = program
175
+ @may_apreprocess = false
169
176
  @macro = {}
170
177
  super(text)
171
178
  end
@@ -184,13 +191,21 @@ class AsmPreprocessor < Preprocessor
184
191
  t
185
192
  end
186
193
 
187
- # reads a token, handles macros/comments/integers/etc
188
- # argument is for internal use
189
- def readtok(rec = false)
194
+ def feed!(*a)
195
+ super(*a)
196
+ if not @may_apreprocess and (@text =~ / (macro|equ) / or not @macro.empty?)
197
+ @may_apreprocess = true
198
+ end
199
+ self
200
+ end
201
+
202
+ # reads a token, handles macros/comments/etc
203
+ def readtok
190
204
  tok = super()
205
+ return tok if not tok or tok.alreadyapp
191
206
 
192
207
  # handle ; comments
193
- if tok and tok.type == :punct and tok.raw == ';'
208
+ if tok.type == :punct and tok.raw[0] == ?;
194
209
  tok.type = :eol
195
210
  begin
196
211
  tok = tok.dup
@@ -203,30 +218,13 @@ class AsmPreprocessor < Preprocessor
203
218
  end
204
219
  end
205
220
 
206
- # aggregate space/eol
207
- if tok and (tok.type == :space or tok.type == :eol)
208
- if ntok = readtok(true) and ntok.type == :space
209
- tok = tok.dup
210
- tok.raw << ntok.raw
211
- elsif ntok and ntok.type == :eol
212
- tok = tok.dup
213
- tok.raw << ntok.raw
214
- tok.type = :eol
215
- else
216
- unreadtok ntok
217
- end
218
- end
219
-
220
-
221
221
  # handle macros
222
- # the rec parameter is used to avoid reading the whole text at once when reading ahead to check 'macro' keyword
223
- if not rec and tok and tok.type == :string
222
+ if @may_apreprocess and tok.type == :string
224
223
  if @macro[tok.raw]
225
224
  @macro[tok.raw].apply(tok, self, @program).reverse_each { |t| unreadtok t }
226
225
  tok = readtok
227
-
228
226
  else
229
- if ntok = readtok(true) and ntok.type == :space and nntok = readtok(true) and nntok.type == :string and (nntok.raw == 'macro' or nntok.raw == 'equ')
227
+ if ntok = super() and ntok.type == :space and nntok = super() and nntok.type == :string and (nntok.raw == 'macro' or nntok.raw == 'equ')
230
228
  puts "W: asm: redefinition of macro #{tok.raw} at #{tok.backtrace_str}, previous definition at #{@macro[tok.raw].name.backtrace_str}" if @macro[tok.raw]
231
229
  m = Macro.new tok
232
230
  # XXX this allows nested macro definition..
@@ -252,6 +250,7 @@ class AsmPreprocessor < Preprocessor
252
250
  end
253
251
  end
254
252
 
253
+ tok.alreadyapp = true if tok
255
254
  tok
256
255
  end
257
256
  end
@@ -314,6 +313,7 @@ class ExeFormat
314
313
  lname = @locallabels_bkw[tok.raw] = @locallabels_fwd.delete(tok.raw) || new_label('local_'+tok.raw)
315
314
  else
316
315
  lname = tok.raw
316
+ raise tok, "invalid label name: #{lname.inspect} is reserved" if @cpu.check_reserved_name(lname)
317
317
  raise tok, "label redefinition" if new_label(lname) != lname
318
318
  end
319
319
  l = Label.new(lname)
@@ -780,7 +780,7 @@ class Expression
780
780
  pp = Preprocessor.new(str)
781
781
 
782
782
  e = parse(pp, &b)
783
-
783
+
784
784
  # update arg
785
785
  len = pp.pos
786
786
  pp.queue.each { |t| len -= t.raw.length }
@@ -821,6 +821,8 @@ class IndExpression < Expression
821
821
  break
822
822
  when ':' # symbols, eg ':eax'
823
823
  n = lexer.readtok
824
+ nil while tok = lexer.readtok and tok.type == :space
825
+ lexer.unreadtok tok
824
826
  return n.raw.to_sym
825
827
  else
826
828
  lexer.unreadtok tok
@@ -249,7 +249,7 @@ module C
249
249
  end
250
250
 
251
251
  def findmember(name, igncase=false)
252
- raise parser, 'undefined structure' if not @members
252
+ raise 'undefined structure' if not members
253
253
  return @fldlist[name] if fldlist and @fldlist[name]
254
254
 
255
255
  name = name.downcase if igncase
@@ -267,7 +267,7 @@ module C
267
267
  end
268
268
 
269
269
  def offsetof(parser, name)
270
- raise parser, 'undefined structure' if not @members
270
+ raise parser, 'undefined structure' if not members
271
271
  update_member_cache(parser) if not fldlist
272
272
  return 0 if @fldlist[name]
273
273
 
@@ -284,7 +284,7 @@ module C
284
284
  end
285
285
 
286
286
  def bitoffsetof(parser, name)
287
- raise parser, 'undefined structure' if not @members
287
+ raise parser, 'undefined structure' if not members
288
288
  update_member_cache(parser) if not fldlist
289
289
  return if @fldlist[name] or @members.include?(name)
290
290
  raise parser, 'undefined union' if not @members
@@ -390,6 +390,22 @@ module C
390
390
  end
391
391
  idx + 1
392
392
  end
393
+
394
+ # resolve structptr + offset into 'str.membername'
395
+ # handles 'var.substruct1.array[12].foo'
396
+ # updates str
397
+ # returns the final member type itself
398
+ # works for Struct/Union/Array
399
+ def expand_member_offset(c_parser, off, str)
400
+ # XXX choose in members, check sizeof / prefer structs
401
+ m = @members.first
402
+ str << '.' << m.name if m.name
403
+ if m.type.respond_to?(:expand_member_offset)
404
+ m.type.expand_member_offset(c_parser, off, str)
405
+ else
406
+ m.type
407
+ end
408
+ end
393
409
  end
394
410
  class Struct < Union
395
411
  attr_accessor :pack
@@ -397,9 +413,10 @@ module C
397
413
  def align(parser) [@members.to_a.map { |m| m.type.align(parser) }.max || 1, (pack || 8)].min end
398
414
 
399
415
  def offsetof(parser, name)
400
- raise parser, 'undefined structure' if not @members
416
+ raise parser, 'undefined structure' if not members
401
417
  update_member_cache(parser) if not fldlist
402
418
  return @fldoffset[name] if @fldoffset[name]
419
+ return @fldoffset[name.name] if name.respond_to?(:name) and @fldoffset[name.name]
403
420
 
404
421
  # this is almost never reached, only for <struct>.offsetof(anonymoussubstructmembername)
405
422
  raise parser, 'unknown structure member' if (name.kind_of?(::String) ? !findmember(name) : !@members.include?(name))
@@ -433,7 +450,7 @@ module C
433
450
  end
434
451
  mal = [m.type.align(parser), al].min
435
452
  off = (off + mal - 1) / mal * mal
436
- if m.name == name or m == name
453
+ if m.name == name or m == name
437
454
  break
438
455
  elsif indirect and m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
439
456
  off += m.type.untypedef.offsetof(parser, name)
@@ -449,18 +466,28 @@ module C
449
466
  # returns the [bitoffset, bitlength] of the field if it is a bitfield
450
467
  # this should be added to the offsetof(field)
451
468
  def bitoffsetof(parser, name)
452
- raise parser, 'undefined structure' if not @members
469
+ raise parser, 'undefined structure' if not members
453
470
  update_member_cache(parser) if not fldlist
454
471
  return @fldbitoffset[name] if fldbitoffset and @fldbitoffset[name]
472
+ return @fldbitoffset[name.name] if fldbitoffset and name.respond_to?(:name) and @fldbitoffset[name.name]
455
473
  return if @fldlist[name] or @members.include?(name)
456
474
  raise parser, 'undefined union' if not @members
457
475
  raise parser, 'unknown union member' if not findmember(name)
458
476
 
459
477
  @members.find { |m|
460
- m.type.untypedef.kind_of? Union and m.type.untypedef.findmember(name)
478
+ m.type.untypedef.kind_of?(Union) and m.type.untypedef.findmember(name)
461
479
  }.type.untypedef.bitoffsetof(parser, name)
462
480
  end
463
481
 
482
+ # returns the @member element that has offsetof(m) == off
483
+ def findmember_atoffset(parser, off)
484
+ return if not members
485
+ update_member_cache(parser) if not fldlist
486
+ if m = @fldoffset.index(off)
487
+ @fldlist[m]
488
+ end
489
+ end
490
+
464
491
  def parse_members(parser, scope)
465
492
  super(parser, scope)
466
493
 
@@ -515,6 +542,32 @@ module C
515
542
  end
516
543
  }
517
544
  end
545
+
546
+ # see Union#expand_member_offset
547
+ def expand_member_offset(c_parser, off, str)
548
+ members.to_a.each { |m|
549
+ mo = offsetof(c_parser, m)
550
+ if mo == off or mo + c_parser.sizeof(m) > off
551
+ if bitoffsetof(c_parser, m)
552
+ # ignore bitfields
553
+ str << "+#{off}" if off > 0
554
+ return self
555
+ end
556
+
557
+ str << '.' << m.name if m.name
558
+ if m.type.respond_to?(:expand_member_offset)
559
+ return m.type.expand_member_offset(c_parser, off-mo, str)
560
+ else
561
+ return m.type
562
+ end
563
+ elsif mo > off
564
+ break
565
+ end
566
+ }
567
+ # XXX that works only for pointer-style str
568
+ str << "+#{off}" if off > 0
569
+ nil
570
+ end
518
571
  end
519
572
  class Enum < Type
520
573
  # name => value
@@ -557,6 +610,11 @@ module C
557
610
  parse_attributes(parser)
558
611
  end
559
612
 
613
+ def compare_deep(o)
614
+ return true if o.object_id == self.object_id
615
+ return if o.class != self.class or o.name != self.name or o.attributes != self.attributes
616
+ members == o.members
617
+ end
560
618
  end
561
619
  class Pointer < Type
562
620
  attr_accessor :type
@@ -684,6 +742,17 @@ module C
684
742
  end
685
743
  idx + 1
686
744
  end
745
+
746
+ # see Union#expand_member_offset
747
+ def expand_member_offset(c_parser, off, str)
748
+ tsz = c_parser.sizeof(@type)
749
+ str << "[#{off/tsz}]"
750
+ if @type.respond_to?(:expand_member_offset)
751
+ @type.expand_member_offset(c_parser, off%tsz, str)
752
+ else
753
+ @type
754
+ end
755
+ end
687
756
  end
688
757
 
689
758
  class Variable
@@ -880,7 +949,7 @@ module C
880
949
  when :space; body << ' '
881
950
  when :eol; body << "\n"
882
951
  when :punct; body << tok.raw
883
- when :quoted; body << tok.value.inspect # concat adjacent c strings
952
+ when :quoted; body << CExpression.string_inspect(tok.value) # concat adjacent c strings
884
953
  when :string
885
954
  body << \
886
955
  case tok.raw
@@ -923,7 +992,7 @@ module C
923
992
  break
924
993
  else body << tok.raw
925
994
  end
926
- when :quoted; body << (body.empty? ? tok.value : tok.value.inspect) # asm "pop\nret" VS asm add al, 'z'
995
+ when :quoted; body << (body.empty? ? tok.value : CExpression.string_inspect(tok.value)) # asm "pop\nret" VS asm add al, 'z'
927
996
  when :string
928
997
  body << \
929
998
  case tok.raw
@@ -997,7 +1066,7 @@ module C
997
1066
  raise "invalid CExpr #{[l, o, r, t].inspect}" if (o and not o.kind_of? ::Symbol) or not t.kind_of? Type
998
1067
  @lexpr, @op, @rexpr, @type = l, o, r, t
999
1068
  end
1000
-
1069
+
1001
1070
  # overwrites @lexpr @op @rexpr @type from the arg
1002
1071
  def replace(o)
1003
1072
  @lexpr, @op, @rexpr, @type = o.lexpr, o.op, o.rexpr, o.type
@@ -1033,7 +1102,7 @@ module C
1033
1102
  else
1034
1103
  x2 = splat[args[2]]
1035
1104
  end
1036
- new(splat[args[0]], op, x2, args[3])
1105
+ new(splat[args[0]], op, x2, args[3])
1037
1106
  when 3
1038
1107
  op = args[1]
1039
1108
  x1 = splat[args[0]]
@@ -1047,7 +1116,7 @@ module C
1047
1116
  when :funcall
1048
1117
  rt = x1.type.untypedef
1049
1118
  rt = rt.type.untypedef if rt.pointer?
1050
- new(x1, op, x2, rt.type)
1119
+ new(x1, op, x2, rt.type)
1051
1120
  when :[]; new(x1, op, x2, x1.type.untypedef.type)
1052
1121
  when :+; new(x1, op, x2, (x2.type.pointer? ? x2.type : x1.type))
1053
1122
  when :-; new(x1, op, x2, ((x1.type.pointer? and x2.type.pointer?) ? BaseType.new(:int) : x2.type.pointer? ? x2.type : x1.type))
@@ -1111,13 +1180,14 @@ module C
1111
1180
  attr_accessor :lexer, :toplevel, :typesize, :pragma_pack
1112
1181
  attr_accessor :endianness
1113
1182
  attr_accessor :allow_bad_c
1183
+ attr_accessor :program
1114
1184
  # allowed arguments: ExeFormat, CPU, Preprocessor, Symbol (for the data model)
1115
1185
  def initialize(*args)
1116
1186
  model = args.grep(Symbol).first || :ilp32
1117
1187
  lexer = args.grep(Preprocessor).first || Preprocessor.new
1118
- exe = args.grep(ExeFormat).first
1188
+ @program = args.grep(ExeFormat).first
1119
1189
  cpu = args.grep(CPU).first
1120
- cpu ||= exe.cpu if exe
1190
+ cpu ||= @program.cpu if @program
1121
1191
  @lexer = lexer
1122
1192
  @prev_pragma_callback = @lexer.pragma_callback
1123
1193
  @lexer.pragma_callback = lambda { |tok| parse_pragma_callback(tok) }
@@ -1128,7 +1198,7 @@ module C
1128
1198
  :char => 1, :float => 4, :double => 8, :longdouble => 12 }
1129
1199
  send model
1130
1200
  cpu.tune_cparser(self) if cpu
1131
- exe.tune_cparser(self) if exe
1201
+ @program.tune_cparser(self) if @program
1132
1202
  end
1133
1203
 
1134
1204
  def ilp16
@@ -1513,6 +1583,7 @@ EOH
1513
1583
  when Struct
1514
1584
  raise self, "unknown structure size #{type.name}" if not type.members
1515
1585
  al = type.align(self)
1586
+ al = 1 if (var.kind_of?(Attributes) and var.has_attribute('sizeof_packed')) or type.has_attribute('sizeof_packed')
1516
1587
  lm = type.members.last
1517
1588
  lm ? (type.offsetof(self, lm) + sizeof(lm) + al - 1) / al * al : 0
1518
1589
  when Union
@@ -1703,6 +1774,7 @@ EOH
1703
1774
  Goto.new name
1704
1775
  when 'return'
1705
1776
  expr = CExpression.parse(self, scope) # nil allowed
1777
+ raise tok || self, "cannot return #{expr} in function returning void" if expr and nest[0].kind_of?(Type) and nest[0].void?
1706
1778
  p, i = nest[0].pointer?, nest[0].integral? if expr
1707
1779
  r = expr.reduce(self) if p or i
1708
1780
  if (not p and not i) or (i and not r.kind_of? ::Integer) or (p and r != 0)
@@ -1770,6 +1842,7 @@ EOH
1770
1842
  end
1771
1843
 
1772
1844
  # returns all numeric constants defined with their value, either macros or enums
1845
+ # for enums, also return the enum name
1773
1846
  def numeric_constants
1774
1847
  ret = []
1775
1848
  # macros
@@ -1779,8 +1852,17 @@ EOH
1779
1852
  end
1780
1853
  }
1781
1854
  # enums
1855
+ seen_enum = {}
1856
+ @toplevel.struct.each { |k, v|
1857
+ if v.kind_of?(Enum)
1858
+ v.members.each { |kk, vv|
1859
+ ret << [kk, vv, k]
1860
+ seen_enum[kk] = true
1861
+ }
1862
+ end
1863
+ }
1782
1864
  @toplevel.symbol.each { |k, v|
1783
- ret << [k, v] if v.kind_of? ::Numeric
1865
+ ret << [k, v] if v.kind_of?(::Numeric) and not seen_enum[k]
1784
1866
  }
1785
1867
  ret
1786
1868
  end
@@ -1933,7 +2015,10 @@ EOH
1933
2015
  name = :int
1934
2016
  tok = nil
1935
2017
  loop do
1936
- raise parser if not tok = parser.skipspaces
2018
+ if not tok = parser.skipspaces
2019
+ raise parser if specifier.empty?
2020
+ break
2021
+ end
1937
2022
  if tok.type != :string
1938
2023
  parser.unreadtok tok
1939
2024
  break
@@ -2239,12 +2324,13 @@ EOH
2239
2324
  else
2240
2325
  l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2241
2326
  r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2242
- CExpression.new(l, @op, r, @type)
2327
+ CExpression.new(l, @op, r, @type)
2243
2328
  end
2244
2329
  when :'.'
2245
2330
  le = CExpression.reduce(parser, @lexpr)
2246
2331
  if le.kind_of? Variable and le.initializer.kind_of? ::Array
2247
- midx = le.type.members.index(le.type.findmember(@rexpr))
2332
+ t = le.type.untypedef
2333
+ midx = t.members.index(t.findmember(@rexpr))
2248
2334
  CExpression.reduce(parser, le.initializer[midx] || 0)
2249
2335
  else
2250
2336
  CExpression.new(le, @op, @rexpr, @type)
@@ -2282,7 +2368,7 @@ EOH
2282
2368
  end
2283
2369
  else
2284
2370
  l = CExpression.reduce(parser, @lexpr)
2285
- if not l.kind_of?(::Numeric) or not r.kind_of?(::Numeric)
2371
+ if not l.kind_of?(::Numeric) or not r.kind_of?(::Numeric)
2286
2372
  l = CExpression.new(nil, nil, l, BaseType.new(:int)) if l.kind_of? ::Integer
2287
2373
  r = CExpression.new(nil, nil, r, BaseType.new(:int)) if r.kind_of? ::Integer
2288
2374
  return CExpression.new(l, @op, r, @type)
@@ -2325,7 +2411,7 @@ EOH
2325
2411
  o.object_id == self.object_id or
2326
2412
  (self.class == o.class and op == o.op and lexpr == o.lexpr and rexpr == o.rexpr)
2327
2413
  end
2328
-
2414
+
2329
2415
  def ===(o)
2330
2416
  (self.class == o.class and op == o.op and lexpr === o.lexpr and rexpr === o.rexpr) or
2331
2417
  (o.class == Variable and not @op and @rexpr == o)
@@ -2506,6 +2592,7 @@ EOH
2506
2592
  type = :long if suffix.count('l') == 1
2507
2593
  end
2508
2594
  val = CExpression[val, BaseType.new(type, *specifier)]
2595
+ val = parse_value_postfix(parser, scope, val)
2509
2596
  else raise parser, "internal error #{val.inspect}"
2510
2597
  end
2511
2598
 
@@ -2513,6 +2600,7 @@ EOH
2513
2600
  if tok.raw[0] == ?'
2514
2601
  raise tok, 'invalid character constant' if not [1, 2, 4, 8].include? tok.value.length # TODO 0fill
2515
2602
  val = CExpression[Expression.decode_imm(tok.value, tok.value.length, :big), BaseType.new(:int)]
2603
+ val = parse_value_postfix(parser, scope, val)
2516
2604
  else
2517
2605
  val = CExpression[tok.value, Pointer.new(BaseType.new(tok.raw[0, 2] == 'L"' ? :short : :char))]
2518
2606
  val = parse_value_postfix(parser, scope, val)
@@ -2712,96 +2800,109 @@ EOH
2712
2800
  end
2713
2801
  end
2714
2802
 
2715
- def parse(parser, scope, allow_coma = true)
2716
- opstack = []
2717
- stack = []
2718
-
2719
- popstack = lambda {
2720
- r, l = stack.pop, stack.pop
2721
- case op = opstack.pop
2722
- when :'?:'
2723
- stack << CExpression.new(stack.pop, op, [l, r], l.type)
2724
- when :','
2725
- stack << CExpression.new(l, op, r, r.type)
2726
- when :'='
2803
+ def parse_popstack(parser, stack, opstack)
2804
+ r = stack.pop
2805
+ l = stack.pop
2806
+ case op = opstack.pop
2807
+ when :'?:'
2808
+ stack << CExpression.new(stack.pop, op, [l, r], l.type)
2809
+ when :','
2810
+ stack << CExpression.new(l, op, r, r.type)
2811
+ when :'='
2812
+ unless r.kind_of?(CExpression) and not r.lexpr and r.type.kind_of?(BaseType) and
2813
+ ((not r.op and r.rexpr.kind_of?(Integer)) or
2814
+ (r.op == :- and r.rexpr.kind_of?(CExpression) and not r.rexpr.op and not r.rexpr.lexpr and r.rexpr.rexpr.kind_of?(Integer))) and
2815
+ l.kind_of?(Typed) and (l.type.untypedef.kind_of?(BaseType) or (l.type.untypedef.kind_of?(Pointer) and r.rexpr == 0))
2816
+ # avoid useless warnings on unsigned foo = -1 / void *foo = 0
2727
2817
  parser.check_compatible_type(parser, r.type, l.type)
2728
- stack << CExpression.new(l, op, r, l.type)
2729
- when :'&&', :'||'
2730
- stack << CExpression.new(l, op, r, BaseType.new(:int))
2818
+ end
2819
+ if l.kind_of?(Typed) and (lt = l.type.untypedef).kind_of?(BaseType) and r.kind_of?(Typed) and (rt = r.type.untypedef).kind_of?(BaseType) and lt.specifier != :unsigned and rt.specifier == :unsigned and parser.typesize[lt.name] > parser.typesize[rt.name]
2820
+ # (int32)i = (uchar)255 => 255, not -1
2821
+ r = CExpression.new(nil, nil, r, BaseType.new(lt.name, :unsigned))
2822
+ end
2823
+ stack << CExpression.new(l, op, r, l.type)
2824
+ when :'&&', :'||'
2825
+ stack << CExpression.new(l, op, r, BaseType.new(:int))
2826
+ else
2827
+ # XXX struct == struct ?
2828
+ raise parser, "invalid type #{l.type} #{l} for #{op.inspect}" if not l.type.arithmetic? and not parser.allow_bad_c
2829
+ raise parser, "invalid type #{r.type} #{r} for #{op.inspect}" if not r.type.arithmetic? and not parser.allow_bad_c
2830
+
2831
+ if l.type.pointer? and r.type.pointer?
2832
+ type = \
2833
+ case op
2834
+ when :'-'; BaseType.new(:long) # addr_t or sumthin ?
2835
+ when :'-='; l.type
2836
+ when :'>', :'>=', :'<', :'<=', :'==', :'!='; BaseType.new(:long)
2837
+ else raise parser, "cannot do #{op.inspect} on pointers" unless parser.allow_bad_c ; l.type
2838
+ end
2839
+ elsif l.type.pointer? or r.type.pointer?
2840
+ puts parser.exception("should not #{op.inspect} a pointer").message if $VERBOSE and not [:'+', :'-', :'=', :'+=', :'-=', :==, :'!='].include? op
2841
+ type = l.type.pointer? ? l.type : r.type
2842
+ elsif RIGHTASSOC[op] and op != :'?:' # += etc
2843
+ type = l.type
2731
2844
  else
2732
- # XXX struct == struct ?
2733
- raise parser, "invalid type #{l.type} #{l} for #{op.inspect}" if not l.type.arithmetic? and not parser.allow_bad_c
2734
- raise parser, "invalid type #{r.type} #{r} for #{op.inspect}" if not r.type.arithmetic? and not parser.allow_bad_c
2735
-
2736
- if l.type.pointer? and r.type.pointer?
2737
- type = \
2738
- case op
2739
- when :'-'; BaseType.new(:long) # addr_t or sumthin ?
2740
- when :'-='; l.type
2741
- when :'>', :'>=', :'<', :'<=', :'==', :'!='; BaseType.new(:long)
2742
- else raise parser, "cannot do #{op.inspect} on pointers" unless parser.allow_bad_c ; l.type
2743
- end
2744
- elsif l.type.pointer? or r.type.pointer?
2745
- puts parser.exception("should not #{op.inspect} a pointer").message if $VERBOSE and not [:'+', :'-', :'=', :'+=', :'-=', :==, :'!='].include? op
2746
- type = l.type.pointer? ? l.type : r.type
2747
- else
2748
- # yay integer promotion
2749
- lt = l.type.untypedef
2750
- rt = r.type.untypedef
2751
- if (t = lt).name == :longdouble or (t = rt).name == :longdouble or
2752
- (t = lt).name == :double or (t = rt).name == :double or
2753
- (t = lt).name == :float or (t = rt).name == :float
2754
- # long double > double > float ...
2755
- type = t
2756
- elsif true
2757
- # custom integer rules based on type sizes
2758
- lts = parser.typesize[lt.name]
2759
- rts = parser.typesize[rt.name]
2760
- its = parser.typesize[:int]
2761
- if not lts or not rts
2762
- type = BaseType.new(:int)
2763
- elsif lts > rts and lts >= its
2764
- type = lt
2765
- elsif rts > lts and rts >= its
2766
- type = rt
2767
- elsif lts == rts and lts >= its
2768
- type = lt
2769
- type = rt if rt.specifier == :unsigned
2770
- else
2771
- type = BaseType.new(:int)
2772
- end
2773
- # end of custom rules
2774
- elsif ((t = lt).name == :long and t.specifier == :unsigned) or
2775
- ((t = rt).name == :long and t.specifier == :unsigned)
2776
- # ... ulong ...
2777
- type = t
2778
- elsif (lt.name == :long and rt.name == :int and rt.specifier == :unsigned) or
2779
- (rt.name == :long and lt.name == :int and lt.specifier == :unsigned)
2780
- # long+uint => ulong
2781
- type = BaseType.new(:long, :unsigned)
2782
- elsif (t = lt).name == :long or (t = rt).name == :long or
2783
- ((t = lt).name == :int and t.specifier == :unsigned) or
2784
- ((t = rt).name == :int and t.specifier == :unsigned)
2785
- # ... long > uint ...
2786
- type = t
2845
+ # yay integer promotion
2846
+ lt = l.type.untypedef
2847
+ rt = r.type.untypedef
2848
+ if (t = lt).name == :longdouble or (t = rt).name == :longdouble or
2849
+ (t = lt).name == :double or (t = rt).name == :double or
2850
+ (t = lt).name == :float or (t = rt).name == :float
2851
+ # long double > double > float ...
2852
+ type = t
2853
+ elsif true
2854
+ # custom integer rules based on type sizes
2855
+ lts = parser.typesize[lt.name]
2856
+ rts = parser.typesize[rt.name]
2857
+ its = parser.typesize[:int]
2858
+ if not lts or not rts
2859
+ type = BaseType.new(:int)
2860
+ elsif lts > rts and lts >= its
2861
+ type = lt
2862
+ elsif rts > lts and rts >= its
2863
+ type = rt
2864
+ elsif lts == rts and lts >= its
2865
+ type = lt
2866
+ type = rt if rt.specifier == :unsigned
2787
2867
  else
2788
- # int
2789
2868
  type = BaseType.new(:int)
2790
2869
  end
2791
- end
2792
-
2793
- case op
2794
- when :'>', :'>=', :'<', :'<=', :'==', :'!='
2795
- # cast both sides
2796
- l = CExpression[l, type] if l.type != type
2797
- r = CExpression[r, type] if r.type != type
2798
- stack << CExpression.new(l, op, r, BaseType.new(:int))
2870
+ # end of custom rules
2871
+ elsif ((t = lt).name == :long and t.specifier == :unsigned) or
2872
+ ((t = rt).name == :long and t.specifier == :unsigned)
2873
+ # ... ulong ...
2874
+ type = t
2875
+ elsif (lt.name == :long and rt.name == :int and rt.specifier == :unsigned) or
2876
+ (rt.name == :long and lt.name == :int and lt.specifier == :unsigned)
2877
+ # long+uint => ulong
2878
+ type = BaseType.new(:long, :unsigned)
2879
+ elsif (t = lt).name == :long or (t = rt).name == :long or
2880
+ ((t = lt).name == :int and t.specifier == :unsigned) or
2881
+ ((t = rt).name == :int and t.specifier == :unsigned)
2882
+ # ... long > uint ...
2883
+ type = t
2799
2884
  else
2800
- # promote result
2801
- stack << CExpression.new(l, op, r, type)
2885
+ # int
2886
+ type = BaseType.new(:int)
2802
2887
  end
2803
2888
  end
2804
- }
2889
+
2890
+ case op
2891
+ when :'>', :'>=', :'<', :'<=', :'==', :'!='
2892
+ # cast both sides
2893
+ l = CExpression[l, type] if l.type != type
2894
+ r = CExpression[r, type] if r.type != type
2895
+ stack << CExpression.new(l, op, r, BaseType.new(:int))
2896
+ else
2897
+ # promote result
2898
+ stack << CExpression.new(l, op, r, type)
2899
+ end
2900
+ end
2901
+ end
2902
+
2903
+ def parse(parser, scope, allow_coma = true)
2904
+ opstack = []
2905
+ stack = []
2805
2906
 
2806
2907
  return if not e = parse_value(parser, scope)
2807
2908
 
@@ -2812,7 +2913,7 @@ EOH
2812
2913
  when :'?'
2813
2914
  # a, b ? c, d : e, f == a, (b ? (c, d) : e), f
2814
2915
  until opstack.empty? or OP_PRIO[opstack.last][:'?:']
2815
- popstack[]
2916
+ parse_popstack(parser, stack, opstack)
2816
2917
  end
2817
2918
  stack << parse(parser, scope)
2818
2919
  raise op || parser, '":" expected' if not op = readop(parser) or op.value != :':'
@@ -2827,7 +2928,7 @@ EOH
2827
2928
  break
2828
2929
  end
2829
2930
  until opstack.empty? or OP_PRIO[op.value][opstack.last]
2830
- popstack[]
2931
+ parse_popstack(parser, stack, opstack)
2831
2932
  end
2832
2933
  end
2833
2934
 
@@ -2837,7 +2938,7 @@ EOH
2837
2938
  end
2838
2939
 
2839
2940
  until opstack.empty?
2840
- popstack[]
2941
+ parse_popstack(parser, stack, opstack)
2841
2942
  end
2842
2943
 
2843
2944
  CExpression[stack.first]
@@ -2929,8 +3030,9 @@ EOH
2929
3030
  end
2930
3031
 
2931
3032
  a, val = a
2932
- raise "#{a.inspect} not a struct member" if not a.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
2933
- a = f.name if a.kind_of? String or a.kind_of? Symbol
3033
+ f = a
3034
+ raise "#{a.inspect} not a struct member" if not f.kind_of? C::Variable and not f = @struct.findmember(a.to_s, true)
3035
+ a = f.name || f
2934
3036
  val = sizeof if val == :size
2935
3037
  off = @stroff + @struct.offsetof(@cp, a)
2936
3038
 
@@ -2972,7 +3074,6 @@ EOH
2972
3074
  str.last << "struct #{@struct.name || '_'} x = " if not off
2973
3075
  @struct.update_member_cache(@cp) if not @struct.fldlist
2974
3076
  fldoff = @struct.fldoffset
2975
- fbo = @struct.fldbitoffset || {}
2976
3077
  mlist = @struct.members.map { |m| m.name || m }
2977
3078
  else
2978
3079
  str.last << "union #{@struct.name || '_'} x = " if not off
@@ -3203,8 +3304,7 @@ EOH
3203
3304
  all = @toplevel.struct.values + @toplevel.symbol.values
3204
3305
  all -= all.grep(::Integer) # Enum values
3205
3306
 
3206
- r, dep = @toplevel.dump_reorder(all, todo_rndr, todo_deps)
3207
- r.join("\n")
3307
+ @toplevel.dump_reorder(all, todo_rndr, todo_deps)[0].join("\n")
3208
3308
  end
3209
3309
 
3210
3310
  # returns a string containing the C definition(s) of toplevel functions, with their dependencies
@@ -3783,7 +3883,7 @@ EOH
3783
3883
  r.last << 'asm '
3784
3884
  r.last << 'volatile ' if @volatile
3785
3885
  r.last << '('
3786
- r.last << @body.inspect
3886
+ r.last << CExpression.string_inspect(@body)
3787
3887
  if @output or @input or @clobber
3788
3888
  if @output and @output != []
3789
3889
  # TODO
@@ -3801,13 +3901,18 @@ EOH
3801
3901
  end
3802
3902
  end
3803
3903
  if @clobber and @clobber != []
3804
- r << (': ' << @clobber.map { |c| c.inspect }.join(', '))
3904
+ r << (': ' << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
3805
3905
  end
3806
3906
  r.last << ');'
3807
3907
  [r, dep]
3808
3908
  end
3809
3909
  end
3810
3910
  class CExpression
3911
+ def self.string_inspect(s)
3912
+ # keep all ascii printable except \ and "
3913
+ '"' + s.gsub(/[^ !\x23-\x5b\x5d-\x7e]/) { |o| '\\x' + o.unpack('H*').first } + '"'
3914
+ end
3915
+
3811
3916
  def self.dump(e, scope, r=[''], dep=[], brace = false)
3812
3917
  if $DEBUG
3813
3918
  brace = false
@@ -3820,7 +3925,7 @@ EOH
3820
3925
  r, dep = \
3821
3926
  case e
3822
3927
  when ::Numeric; r.last << e.to_s ; [r, dep]
3823
- when ::String; r.last << e.inspect ; [r, dep]
3928
+ when ::String; r.last << string_inspect(e) ; [r, dep]
3824
3929
  when CExpression; e.dump_inner(scope, r, dep, brace)
3825
3930
  when Variable; e.dump(scope, r, dep)
3826
3931
  when nil; [r, dep]
@@ -3865,7 +3970,7 @@ EOH
3865
3970
  end
3866
3971
  when ::String
3867
3972
  r.last << 'L' if @type.kind_of? Pointer and @type.type.kind_of? BaseType and @type.type.name == :short
3868
- r.last << @rexpr.inspect
3973
+ r.last << CExpression.string_inspect(@rexpr)
3869
3974
  when CExpression # cast
3870
3975
  r, dep = @type.dump_cast(scope, r, dep)
3871
3976
  r, dep = CExpression.dump(@rexpr, scope, r, dep, true)
@@ -3899,7 +4004,7 @@ EOH
3899
4004
  l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of? CExpression and lexpr.op == :'->'
3900
4005
  # honor __attribute__((indexenum(enumname)))
3901
4006
  if l and l.attributes and rexpr.kind_of? CExpression and not rexpr.op and rexpr.rexpr.kind_of? ::Integer and
3902
- n = l.has_attribute_var('indexenum') and enum = scope.struct_ancestors[n] and i = enum.members.index(rexpr.rexpr)
4007
+ n = l.has_attribute_var('indexenum') and enum = scope.struct_ancestors[n] and i = enum.members.index(rexpr.rexpr)
3903
4008
  r.last << i
3904
4009
  dep |= [enum]
3905
4010
  else