]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - offlineasm/offsets.rb
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / offlineasm / offsets.rb
diff --git a/offlineasm/offsets.rb b/offlineasm/offsets.rb
new file mode 100644 (file)
index 0000000..63af014
--- /dev/null
@@ -0,0 +1,183 @@
+# 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 "ast"
+
+OFFSET_HEADER_MAGIC_NUMBERS = [ 0x9e43fd66, 0x4379bfba ]
+OFFSET_MAGIC_NUMBERS = [ 0xec577ac7, 0x0ff5e755 ]
+
+#
+# MissingMagicValuesException
+#
+# Thrown when magic values are missing from the binary.
+# This is usually an indication that the classic interpreter is enabled.
+#
+
+class MissingMagicValuesException < Exception
+end
+
+#
+# offsetsList(ast)
+# sizesList(ast)
+#
+# Returns a list of offsets and sizes used by the AST.
+#
+
+def offsetsList(ast)
+    ast.filter(StructOffset).uniq.sort
+end
+
+def sizesList(ast)
+    ast.filter(Sizeof).uniq.sort
+end
+
+#
+# offsetsAndConfigurationIndex(ast, 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)
+    endiannessMarkerBytes = nil
+    result = []
+    
+    def readInt(endianness, bytes)
+        if endianness == :little
+            # Little endian
+            (bytes[0] << 0 |
+             bytes[1] << 8 |
+             bytes[2] << 16 |
+             bytes[3] << 24)
+        else
+            # Big endian
+            (bytes[0] << 24 |
+             bytes[1] << 16 |
+             bytes[2] << 8 |
+             bytes[3] << 0)
+        end
+    end
+    
+    def prepareMagic(endianness, numbers)
+        magicBytes = []
+        numbers.each {
+            | number |
+            currentBytes = []
+            4.times {
+                currentBytes << (number & 0xff)
+                number >>= 8
+            }
+            if endianness == :big
+                currentBytes.reverse!
+            end
+            magicBytes += currentBytes
+        }
+        magicBytes
+    end
+    
+    fileBytes = []
+    
+    File.open(file, "r") {
+        | inp |
+        loop {
+            byte = inp.getbyte
+            break unless byte
+            fileBytes << byte
+        }
+    }
+    
+    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
+    
+    [: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 << [offsets, index]
+            }
+        end
+    }
+    
+    raise MissingMagicValuesException unless result.length >= 1
+    raise if result.map{|v| v[1]}.uniq.size < result.map{|v| v[1]}.size
+    
+    result
+end
+
+#
+# buildOffsetsMap(ast, offsetsList) -> [offsets, sizes]
+#
+# Builds a mapping between StructOffset nodes and their values.
+#
+
+def buildOffsetsMap(ast, offsetsList)
+    offsetsMap = {}
+    sizesMap = {}
+    astOffsetsList = offsetsList(ast)
+    astSizesList = sizesList(ast)
+    raise unless astOffsetsList.size + astSizesList.size == offsetsList.size
+    offsetsList(ast).each_with_index {
+        | structOffset, index |
+        offsetsMap[structOffset] = offsetsList.shift
+    }
+    sizesList(ast).each_with_index {
+        | sizeof, index |
+        sizesMap[sizeof] = offsetsList.shift
+    }
+    [offsetsMap, sizesMap]
+end
+