/* Copyright 2010 Aaron J. Radke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // vim: set ts=3 sw=3 et: package cc.drx /**Get information about ELF binary files*/ case class ELF(val file:File){ private var isValid = !false // private val bb = file.in.toByteBuffer //bb by inputstream private val bb = Input(file.in.byteIt.take(2.k).toArray).toByteBuffer //--search/skip to a PE32, PE32+ header bb.asLittle; //TODO is the little needed? while(bb.getInt != 0x00004550){} //PE00 PE32 or PE32+ magic number header start //--get helpers def getVersion16 = Version(bb.getU8.toInt, bb.getU8.toInt) //get major then minor def getVersion32 = Version(bb.getU16.toInt, bb.getU16.toInt) //get major then minor //---std header val machine = bb.getU16 val sections = bb.getU16 val dateSec = bb.getU32 val date = Date.fromSec(dateSec.toLong) val symbolTable = bb.getU32 //size ??? val symbols = bb.getU32 //size ??? val optSize = bb.getU16 //size ?? val characteristics = bb.getU16 //---opt header val magicNum = bb.getU16 //PE32 => 0x010B //PE32 => 0x010 otherwise switch to PE64 format TODO ??? val isPE32:Boolean = magicNum == U16(0x010B) val isPE64:Boolean = magicNum == U16(0x020B) val isMagicValid = isPE32 || isPE64 isValid &&= isMagicValid //running collection of all validity checks def getPointer:Long = if(isPE32) bb.getU32.toLong else bb.getU64.toLong val linkerVer = getVersion16 val codeSize = bb.getU32 //--- val dataSize = bb.getU32 val dataBSize = bb.getU32 val entryPoint = bb.getU32 val codeBase = bb.getU32 val dataBase = bb.getU32 val imgBase = getPointer val secAlign = bb.getU32 val fileAlign = bb.getU32 val osVer = getVersion32 val imgVer = getVersion32 val subVer = getVersion32 val win32Ver = getVersion32 val imgSize = bb.getU32 val headerSize = bb.getU32 val checksum = bb.getU32 val subsystem = bb.getU16 val dllChars = bb.getU16 //.... //--derived values val machineName = machine.toInt match { case 0x8664 => "AMD64" //x64 case 0x014c => "I386" //x64 case 0x0200 => "IA64" case 0xaa64 => "ARM64" //most common at the top case 0x01c0 => "ARM" case 0x01d3 => "AM33" case 0x01c4 => "ARMV" case 0x0ebc => "EBC" case 0x9041 => "M32R" case 0x0266 => "MIPS16" case 0x0366 => "MIPSFPU" case 0x0466 => "MIPSFPU16" case 0x01f0 => "POWERPC" case 0x01f1 => "POWERPCFP" case 0x01c2 => "THUMB" case 0x0169 => "WCEMIPSV2" case _ => "unknown" } val linkerName:String = { val major:Int = Try{linkerVer.take(1).toString.toInt}.getOrElse(0) // -- https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History val nameOf = Map[Int,String]( 2 -> "gcc", //common for gnu projects like git & ffmpeg 5 -> "Visual Studio 97 (1997)", 6 -> "Visual Studio 6.0 (1998)", 7 -> "Visual Studio .NET (2002)", 8 -> "Visual Studio 2005", 9 -> "Visual Studio 2008", 10 -> "Visual Studio 2010", 11 -> "Visual Studio 2012", 12 -> "Visual Studio 2013", 14 -> "Visual Studio 2015", 15 -> "Visual Studio 2017", 16 -> "Visual Studio 2019", 48 -> "??" //a common value for amd64 ...??? ) val vStr = "v" + linkerVer.toString if(!isValid) f"??? (magic 0x${magicNum.toInt}%04X)" else if(nameOf.contains(major) ) s"${nameOf(major)} ($vStr)" else vStr } // val magicPos = bb.position() - 8 - 1 override def toString = s"ELF date:${date.iso} linker:$linkerName file:$file" def niceRow = f" ${date.isoDay} $machineName%-8s $linkerVer%-8s $linkerName%-35s $file" }