mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2024-11-23 12:19:46 +00:00
284 lines
7.7 KiB
Ruby
284 lines
7.7 KiB
Ruby
# Copyright (C) 2011 Apple Inc. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
# THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
require "config"
|
|
require "ast"
|
|
|
|
OFFSET_HEADER_MAGIC_NUMBERS = [ 0x2e43fd66, 0x4379bfba ]
|
|
OFFSET_MAGIC_NUMBERS = [ 0x5c577ac7, 0x0ff5e755 ]
|
|
|
|
#
|
|
# MissingMagicValuesException
|
|
#
|
|
# Thrown when magic values are missing from the binary.
|
|
#
|
|
|
|
class MissingMagicValuesException < Exception
|
|
end
|
|
|
|
#
|
|
# offsetsList(ast)
|
|
# sizesList(ast)
|
|
# constsLists(ast)
|
|
#
|
|
# Returns a list of offsets, sizeofs, and consts used by the AST.
|
|
#
|
|
|
|
def offsetsList(ast)
|
|
ast.filter(StructOffset).uniq.sort
|
|
end
|
|
|
|
def sizesList(ast)
|
|
ast.filter(Sizeof).uniq.sort
|
|
end
|
|
|
|
def constsList(ast)
|
|
ast.filter(ConstExpr).uniq.sort
|
|
end
|
|
|
|
def readInt(endianness, bytes)
|
|
if endianness == :little
|
|
# Little endian
|
|
number = (bytes[0] << 0 |
|
|
bytes[1] << 8 |
|
|
bytes[2] << 16 |
|
|
bytes[3] << 24 |
|
|
bytes[4] << 32 |
|
|
bytes[5] << 40 |
|
|
bytes[6] << 48 |
|
|
bytes[7] << 56)
|
|
else
|
|
# Big endian
|
|
number = (bytes[0] << 56 |
|
|
bytes[1] << 48 |
|
|
bytes[2] << 40 |
|
|
bytes[3] << 32 |
|
|
bytes[4] << 24 |
|
|
bytes[5] << 16 |
|
|
bytes[6] << 8 |
|
|
bytes[7] << 0)
|
|
end
|
|
if number > 0x7fffffff_ffffffff
|
|
number -= 1 << 64
|
|
end
|
|
number
|
|
end
|
|
|
|
def prepareMagic(endianness, numbers)
|
|
magicBytes = []
|
|
numbers.each {
|
|
| number |
|
|
currentBytes = []
|
|
8.times {
|
|
currentBytes << (number & 0xff)
|
|
number >>= 8
|
|
}
|
|
if endianness == :big
|
|
currentBytes.reverse!
|
|
end
|
|
magicBytes += currentBytes
|
|
}
|
|
magicBytes
|
|
end
|
|
|
|
def fileBytes(file)
|
|
fileBytes = []
|
|
File.open(file, "rb") {
|
|
| inp |
|
|
loop {
|
|
byte = inp.getbyte
|
|
break unless byte
|
|
fileBytes << byte
|
|
}
|
|
}
|
|
fileBytes
|
|
end
|
|
|
|
def sliceByteArrays(byteArray, pattern)
|
|
result = []
|
|
lastSlicePoint = 0
|
|
(byteArray.length - pattern.length + 1).times {
|
|
| index |
|
|
foundOne = true
|
|
pattern.length.times {
|
|
| subIndex |
|
|
if byteArray[index + subIndex] != pattern[subIndex]
|
|
foundOne = false
|
|
break
|
|
end
|
|
}
|
|
if foundOne
|
|
result << byteArray[lastSlicePoint...index]
|
|
lastSlicePoint = index + pattern.length
|
|
end
|
|
}
|
|
|
|
result << byteArray[lastSlicePoint...(byteArray.length)]
|
|
|
|
result
|
|
end
|
|
|
|
#
|
|
# offsetsAndConfigurationIndex(file) ->
|
|
# [[offsets, index], ...]
|
|
#
|
|
# Parses the offsets from a file and returns a list of offsets and the
|
|
# index of the configuration that is valid in this build target.
|
|
#
|
|
|
|
def offsetsAndConfigurationIndex(file)
|
|
fileBytes = fileBytes(file)
|
|
result = {}
|
|
|
|
[:little, :big].each {
|
|
| endianness |
|
|
headerMagicBytes = prepareMagic(endianness, OFFSET_HEADER_MAGIC_NUMBERS)
|
|
magicBytes = prepareMagic(endianness, OFFSET_MAGIC_NUMBERS)
|
|
|
|
bigArray = sliceByteArrays(fileBytes, headerMagicBytes)
|
|
unless bigArray.size <= 1
|
|
bigArray[1..-1].each {
|
|
| configArray |
|
|
array = sliceByteArrays(configArray, magicBytes)
|
|
index = readInt(endianness, array[1])
|
|
offsets = []
|
|
array[2..-1].each {
|
|
| data |
|
|
offsets << readInt(endianness, data)
|
|
}
|
|
result[index] = offsets
|
|
}
|
|
end
|
|
}
|
|
|
|
raise MissingMagicValuesException unless result.length >= 1
|
|
|
|
# result is {index1=>offsets1, index2=>offsets2} but we want to return
|
|
# [[offsets1, index1], [offsets2, index2]].
|
|
return result.map {
|
|
| pair |
|
|
pair.reverse
|
|
}
|
|
end
|
|
|
|
#
|
|
# offsetsAndConfigurationIndex(file) ->
|
|
# [[offsets, index], ...]
|
|
#
|
|
# Parses the offsets from a file and all its variants and returns a list of
|
|
# offsets and the index of the configuration that is valid in this build target.
|
|
#
|
|
|
|
def offsetsAndConfigurationIndexForVariants(file, variants)
|
|
results = []
|
|
variants.each {
|
|
| current_variant |
|
|
suffix = ""
|
|
unless current_variant == "normal"
|
|
suffix = "_" + current_variant
|
|
end
|
|
results << offsetsAndConfigurationIndex(file + suffix)
|
|
}
|
|
return results.flatten(1)
|
|
end
|
|
|
|
#
|
|
# configurationIndices(file) ->
|
|
# [[offsets, index], ...]
|
|
#
|
|
# Parses the configurations from a file and returns a list of the indices of
|
|
# the configurations that are valid in this build target.
|
|
#
|
|
|
|
def configurationIndices(file)
|
|
fileBytes = fileBytes(file)
|
|
result = []
|
|
|
|
[:little, :big].each {
|
|
| endianness |
|
|
headerMagicBytes = prepareMagic(endianness, OFFSET_HEADER_MAGIC_NUMBERS)
|
|
|
|
bigArray = sliceByteArrays(fileBytes, headerMagicBytes)
|
|
unless bigArray.size <= 1
|
|
bigArray[1..-1].each {
|
|
| configArray |
|
|
result << readInt(endianness, configArray)
|
|
}
|
|
end
|
|
}
|
|
|
|
raise MissingMagicValuesException unless result.length >= 1
|
|
|
|
return result
|
|
end
|
|
|
|
#
|
|
# configurationIndicesForVariants(file, variants) ->
|
|
# [[offsets, index], ...]
|
|
#
|
|
# Parses the configurations from a file and all its variants and returns a list
|
|
# of the indices of the configurations that are valid in this build target.
|
|
#
|
|
|
|
def configurationIndicesForVariants(file, variants)
|
|
results = []
|
|
variants.each {
|
|
| current_variant |
|
|
suffix = ""
|
|
unless current_variant == "normal"
|
|
suffix = "_" + current_variant
|
|
end
|
|
results << configurationIndices(file + suffix)
|
|
}
|
|
return results.flatten(1)
|
|
end
|
|
|
|
#
|
|
# buildOffsetsMap(ast, extractedConstants) -> map
|
|
#
|
|
# Builds a mapping between StructOffset, Sizeof, and ConstExpr nodes and their values.
|
|
#
|
|
|
|
def buildOffsetsMap(ast, extractedConstants)
|
|
map = {}
|
|
astOffsetsList = offsetsList(ast)
|
|
astSizesList = sizesList(ast)
|
|
astConstsList = constsList(ast)
|
|
|
|
raise unless astOffsetsList.size + astSizesList.size + astConstsList.size == extractedConstants.size
|
|
astOffsetsList.each_with_index {
|
|
| structOffset, index |
|
|
map[structOffset] = extractedConstants.shift
|
|
}
|
|
astSizesList.each_with_index {
|
|
| sizeof, index |
|
|
map[sizeof] = extractedConstants.shift
|
|
}
|
|
astConstsList.each_with_index {
|
|
| const, index |
|
|
map[const] = extractedConstants.shift
|
|
}
|
|
map
|
|
end
|
|
|