metasm 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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