1 # Copyright (C) 2011 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
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.
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.
27 OFFSET_HEADER_MAGIC_NUMBERS = [ 0x2e43fd66, 0x4379bfba ]
28 OFFSET_MAGIC_NUMBERS = [ 0x5c577ac7, 0x0ff5e755 ]
31 # MissingMagicValuesException
33 # Thrown when magic values are missing from the binary.
36 class MissingMagicValuesException < Exception
44 # Returns a list of offsets, sizeofs, and consts used by the AST.
48 ast.filter(StructOffset).uniq.sort
52 ast.filter(Sizeof).uniq.sort
56 ast.filter(ConstExpr).uniq.sort
59 def readInt(endianness, bytes)
60 if endianness == :little
62 number = (bytes[0] << 0 |
72 number = (bytes[0] << 56 |
81 if number > 0x7fffffff_ffffffff
87 def prepareMagic(endianness, numbers)
93 currentBytes << (number & 0xff)
99 magicBytes += currentBytes
106 File.open(file, "rb") {
117 def sliceByteArrays(byteArray, pattern)
120 (byteArray.length - pattern.length + 1).times {
123 pattern.length.times {
125 if byteArray[index + subIndex] != pattern[subIndex]
131 result << byteArray[lastSlicePoint...index]
132 lastSlicePoint = index + pattern.length
136 result << byteArray[lastSlicePoint...(byteArray.length)]
142 # offsetsAndConfigurationIndex(ast, file) ->
143 # [[offsets, index], ...]
145 # Parses the offsets from a file and returns a list of offsets and the
146 # index of the configuration that is valid in this build target.
149 def offsetsAndConfigurationIndex(file)
150 fileBytes = fileBytes(file)
153 [:little, :big].each {
155 headerMagicBytes = prepareMagic(endianness, OFFSET_HEADER_MAGIC_NUMBERS)
156 magicBytes = prepareMagic(endianness, OFFSET_MAGIC_NUMBERS)
158 bigArray = sliceByteArrays(fileBytes, headerMagicBytes)
159 unless bigArray.size <= 1
160 bigArray[1..-1].each {
162 array = sliceByteArrays(configArray, magicBytes)
163 index = readInt(endianness, array[1])
167 offsets << readInt(endianness, data)
169 result[index] = offsets
174 raise MissingMagicValuesException unless result.length >= 1
176 # result is {index1=>offsets1, index2=>offsets2} but we want to return
177 # [[offsets1, index1], [offsets2, index2]].
185 # configurationIndices(ast, file) ->
186 # [[offsets, index], ...]
188 # Parses the configurations from a file and returns a list of the indices of
189 # the configurations that are valid in this build target.
192 def configurationIndices(file)
193 fileBytes = fileBytes(file)
196 [:little, :big].each {
198 headerMagicBytes = prepareMagic(endianness, OFFSET_HEADER_MAGIC_NUMBERS)
200 bigArray = sliceByteArrays(fileBytes, headerMagicBytes)
201 unless bigArray.size <= 1
202 bigArray[1..-1].each {
204 result << readInt(endianness, configArray)
209 raise MissingMagicValuesException unless result.length >= 1
215 # buildOffsetsMap(ast, extractedConstants) -> map
217 # Builds a mapping between StructOffset, Sizeof, and ConstExpr nodes and their values.
220 def buildOffsetsMap(ast, extractedConstants)
222 astOffsetsList = offsetsList(ast)
223 astSizesList = sizesList(ast)
224 astConstsList = constsList(ast)
226 raise unless astOffsetsList.size + astSizesList.size + astConstsList.size == extractedConstants.size
227 astOffsetsList.each_with_index {
228 | structOffset, index |
229 map[structOffset] = extractedConstants.shift
231 astSizesList.each_with_index {
233 map[sizeof] = extractedConstants.shift
235 astConstsList.each_with_index {
237 map[const] = extractedConstants.shift