Unreviewed, rolling out r237084, r237088, r237098, and
[WebKit-https.git] / Source / JavaScriptCore / offlineasm / offsets.rb
1 # Copyright (C) 2011 Apple Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1. Redistributions of source code must retain the above copyright
7 #    notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 #    notice, this list of conditions and the following disclaimer in the
10 #    documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22 # THE POSSIBILITY OF SUCH DAMAGE.
23
24 require "config"
25 require "ast"
26
27 OFFSET_HEADER_MAGIC_NUMBERS = [ 0x2e43fd66, 0x4379bfba ]
28 OFFSET_MAGIC_NUMBERS = [ 0x5c577ac7, 0x0ff5e755 ]
29
30 #
31 # MissingMagicValuesException
32 #
33 # Thrown when magic values are missing from the binary.
34 #
35
36 class MissingMagicValuesException < Exception
37 end
38
39 #
40 # offsetsList(ast)
41 # sizesList(ast)
42 # constsLists(ast)
43 #
44 # Returns a list of offsets, sizeofs, and consts used by the AST.
45 #
46
47 def offsetsList(ast)
48     ast.filter(StructOffset).uniq.sort
49 end
50
51 def sizesList(ast)
52     ast.filter(Sizeof).uniq.sort
53 end
54
55 def constsList(ast)
56     ast.filter(ConstExpr).uniq.sort
57 end
58
59 #
60 # offsetsAndConfigurationIndex(ast, file) ->
61 #     [[offsets, index], ...]
62 #
63 # Parses the offsets from a file and returns a list of offsets and the
64 # index of the configuration that is valid in this build target.
65 #
66
67 def offsetsAndConfigurationIndex(file)
68     endiannessMarkerBytes = nil
69     result = {}
70     
71     def readInt(endianness, bytes)
72         if endianness == :little
73             # Little endian
74             number = (bytes[0] << 0  |
75                       bytes[1] << 8  |
76                       bytes[2] << 16 |
77                       bytes[3] << 24 |
78                       bytes[4] << 32 |
79                       bytes[5] << 40 |
80                       bytes[6] << 48 |
81                       bytes[7] << 56)
82         else
83             # Big endian
84             number = (bytes[0] << 56 |
85                       bytes[1] << 48 |
86                       bytes[2] << 40 |
87                       bytes[3] << 32 |
88                       bytes[4] << 24 |
89                       bytes[5] << 16 |
90                       bytes[6] << 8  |
91                       bytes[7] << 0)
92         end
93         if number > 0x7fffffff_ffffffff
94             number -= 1 << 64
95         end
96         number
97     end
98     
99     def prepareMagic(endianness, numbers)
100         magicBytes = []
101         numbers.each {
102             | number |
103             currentBytes = []
104             8.times {
105                 currentBytes << (number & 0xff)
106                 number >>= 8
107             }
108             if endianness == :big
109                 currentBytes.reverse!
110             end
111             magicBytes += currentBytes
112         }
113         magicBytes
114     end
115     
116     fileBytes = []
117     
118     File.open(file, "rb") {
119         | inp |
120         loop {
121             byte = inp.getbyte
122             break unless byte
123             fileBytes << byte
124         }
125     }
126     
127     def sliceByteArrays(byteArray, pattern)
128         result = []
129         lastSlicePoint = 0
130         (byteArray.length - pattern.length + 1).times {
131             | index |
132             foundOne = true
133             pattern.length.times {
134                 | subIndex |
135                 if byteArray[index + subIndex] != pattern[subIndex]
136                     foundOne = false
137                     break
138                 end
139             }
140             if foundOne
141                 result << byteArray[lastSlicePoint...index]
142                 lastSlicePoint = index + pattern.length
143             end
144         }
145         
146         result << byteArray[lastSlicePoint...(byteArray.length)]
147         
148         result
149     end
150     
151     [:little, :big].each {
152         | endianness |
153         headerMagicBytes = prepareMagic(endianness, OFFSET_HEADER_MAGIC_NUMBERS)
154         magicBytes = prepareMagic(endianness, OFFSET_MAGIC_NUMBERS)
155         
156         bigArray = sliceByteArrays(fileBytes, headerMagicBytes)
157         unless bigArray.size <= 1
158             bigArray[1..-1].each {
159                 | configArray |
160                 array = sliceByteArrays(configArray, magicBytes)
161                 index = readInt(endianness, array[1])
162                 offsets = []
163                 array[2..-1].each {
164                     | data |
165                     offsets << readInt(endianness, data)
166                 }
167                 result[index] = offsets
168             }
169         end
170     }
171     
172     raise MissingMagicValuesException unless result.length >= 1
173     
174     # result is {index1=>offsets1, index2=>offsets2} but we want to return
175     # [[offsets1, index1], [offsets2, index2]].
176     return result.map {
177         | pair |
178         pair.reverse
179     }
180 end
181
182 #
183 # buildOffsetsMap(ast, extractedConstants) -> map
184 #
185 # Builds a mapping between StructOffset, Sizeof, and ConstExpr nodes and their values.
186 #
187
188 def buildOffsetsMap(ast, extractedConstants)
189     map = {}
190     astOffsetsList = offsetsList(ast)
191     astSizesList = sizesList(ast)
192     astConstsList = constsList(ast)
193
194     raise unless astOffsetsList.size + astSizesList.size + astConstsList.size == extractedConstants.size
195     astOffsetsList.each_with_index {
196         | structOffset, index |
197         map[structOffset] = extractedConstants.shift
198     }
199     astSizesList.each_with_index {
200         | sizeof, index |
201         map[sizeof] = extractedConstants.shift
202     }
203     astConstsList.each_with_index {
204         | const, index |
205         map[const] = extractedConstants.shift
206     }
207     map
208 end
209