Add binary analyser code to the toolchain
This commit adds the binary analyser code to the toolchain. This binary analyser adds various features such as gathering ELF information (e.g., functions, symbols, ...), micro-libs inspection, ELF comparison, ELF pages division, ... Note that it was developped with Unikraft structure in mind. The binary analyser can be used as an external tool with the '--binary' argument. A specific json file should be provided which contains specific fields (see 'bin_analysis_example.json'). Please, see the wiki for further information. Signed-off-by: Gaulthier Gain <gaulthier.gain@uliege.be>
This commit is contained in:
parent
81e5677e1a
commit
f25637cdb7
21 changed files with 2331 additions and 1 deletions
40
bin_analysis_example.json
Normal file
40
bin_analysis_example.json
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"unikernels": [
|
||||
{
|
||||
"buildPath": "/Users/unicore/buildCompare/lib-sqlite",
|
||||
"ignoredPlats": [
|
||||
"linuxu",
|
||||
"xen"
|
||||
],
|
||||
"kernel": "lib-sqlite3_kvm-x86_64.dbg",
|
||||
"splitSection": ".text",
|
||||
"displayMapping": true,
|
||||
"displayStatSize": false,
|
||||
"displayElfFile": [
|
||||
"sections"
|
||||
],
|
||||
"displaySectionInfo": [],
|
||||
"findSectionByAddress": [
|
||||
"0x43a74e"
|
||||
],
|
||||
"compareGroup": 1
|
||||
},
|
||||
{
|
||||
"buildPath": "/Users/unicore/buildCompare/app-helloworld",
|
||||
"ignoredPlats": [
|
||||
"linuxu",
|
||||
"xen"
|
||||
],
|
||||
"kernel": "lib-redis_kvm-x86_64.dbg",
|
||||
"splitSection": ".text",
|
||||
"displayElfFile": [],
|
||||
"displayMapping": true,
|
||||
"displayStatSize": true,
|
||||
"displaySectionInfo": [],
|
||||
"findSectionByAddress": [
|
||||
"0x427836"
|
||||
],
|
||||
"compareGroup": 1
|
||||
}
|
||||
]
|
||||
}
|
38
srcs/binarytool/args.go
Normal file
38
srcs/binarytool/args.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package binarytool
|
||||
|
||||
import (
|
||||
"github.com/akamensky/argparse"
|
||||
"os"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
const (
|
||||
filesArg = "file"
|
||||
mappingArg = "mapping"
|
||||
listArg = "list"
|
||||
)
|
||||
|
||||
// ParseArguments parses arguments of the application.
|
||||
//
|
||||
// It returns an error if any, otherwise it returns nil.
|
||||
func parseLocalArguments(p *argparse.Parser, args *u.Arguments) error {
|
||||
|
||||
args.InitArgParse(p, args, u.BOOL, "m", mappingArg,
|
||||
&argparse.Options{Required: false, Default: false,
|
||||
Help: "Display libraries mapping (required -l argument)"})
|
||||
|
||||
args.InitArgParse(p, args, u.STRING, "l", listArg,
|
||||
&argparse.Options{Required: false, Help: "A list of build directories " +
|
||||
"to analyse (sep: ,)"})
|
||||
args.InitArgParse(p, args, u.STRING, "f", filesArg,
|
||||
&argparse.Options{Required: false, Help: "Json file that contains " +
|
||||
"the information for the binary analyser"})
|
||||
|
||||
return u.ParserWrapper(p, os.Args)
|
||||
}
|
251
srcs/binarytool/elf64analyser/elf_analyser.go
Normal file
251
srcs/binarytool/elf64analyser/elf_analyser.go
Normal file
|
@ -0,0 +1,251 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64analyser
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"tools/srcs/binarytool/elf64core"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type ElfAnalyser struct {
|
||||
ElfLibs []ElfLibs
|
||||
ElfPage []*ElfPage
|
||||
}
|
||||
|
||||
type ElfLibs struct {
|
||||
Name string
|
||||
StartAddr uint64
|
||||
EndAddr uint64
|
||||
Size uint64
|
||||
NbSymbols int
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) DisplayMapping() {
|
||||
|
||||
if len(analyser.ElfLibs) == 0 {
|
||||
fmt.Println("Mapping is empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
_, _ = fmt.Fprintln(w, "Name \tStart \tEnd \tSize \tNbSymbols\tnbDiv")
|
||||
for _, lib := range analyser.ElfLibs {
|
||||
|
||||
var name = lib.Name
|
||||
if strings.Contains(lib.Name, string(os.PathSeparator)) {
|
||||
split := strings.Split(lib.Name, string(os.PathSeparator))
|
||||
name = split[len(split)-1]
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(w, "%s \t0x%x \t0x%x \t0x%x\t%d\t%f\n",
|
||||
name, lib.StartAddr, lib.EndAddr, lib.Size,
|
||||
lib.NbSymbols, float32(lib.StartAddr)/float32(pageSize))
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
||||
func filterFunctions(objFuncsAll []elf64core.ELF64Function, elfFuncsAll []elf64core.ELF64Function) []*elf64core.ELF64Function {
|
||||
|
||||
i := 0
|
||||
filteredFuncs := make([]*elf64core.ELF64Function, len(objFuncsAll))
|
||||
for j, _ := range elfFuncsAll {
|
||||
|
||||
if strings.Compare(objFuncsAll[i].Name, elfFuncsAll[j].Name) == 0 {
|
||||
filteredFuncs[i] = &elfFuncsAll[j]
|
||||
i++
|
||||
} else {
|
||||
// Reset the counter if we do not have consecutive functions
|
||||
i = 0
|
||||
// Special case where we can skip a function if we do not check again
|
||||
if strings.Compare(objFuncsAll[i].Name, elfFuncsAll[j].Name) == 0 {
|
||||
filteredFuncs[i] = &elfFuncsAll[j]
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
if i == len(objFuncsAll) {
|
||||
return filteredFuncs
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func compareFunctions(elf *elf64core.ELF64File, obj *elf64core.ELF64File) (uint64, uint64, int) {
|
||||
|
||||
// Obj: Merge all functions table(s) in one slice for simplicity
|
||||
objFuncs := make([]elf64core.ELF64Function, 0)
|
||||
for i := len(obj.FunctionsTables) - 1; i >= 0; i-- {
|
||||
if strings.Compare(obj.FunctionsTables[i].Name, elf64core.BootTextSection) != 0 {
|
||||
// Ignore the '.text.boot' section since it can be split through
|
||||
// different places
|
||||
objFuncs = append(objFuncs, obj.FunctionsTables[i].Functions...)
|
||||
}
|
||||
}
|
||||
// Elf: Merge all functions table(s) in one slice for simplicity
|
||||
elfFuncs := make([]elf64core.ELF64Function, 0)
|
||||
for i := len(elf.FunctionsTables) - 1; i >= 0; i-- {
|
||||
if strings.Compare(elf.FunctionsTables[i].Name, elf64core.BootTextSection) != 0 {
|
||||
// Ignore the '.text.boot' section since it can be split through
|
||||
// different places
|
||||
elfFuncs = append(elfFuncs, elf.FunctionsTables[i].Functions...)
|
||||
}
|
||||
}
|
||||
|
||||
// Add functions into a map for better search
|
||||
mapObjFuncs := make(map[string]*elf64core.ELF64Function)
|
||||
for i := 0; i < len(objFuncs); i++ {
|
||||
mapObjFuncs[objFuncs[i].Name] = &objFuncs[i]
|
||||
}
|
||||
|
||||
elfFuncsAll := make([]elf64core.ELF64Function, 0)
|
||||
mapArrayFuncs := make(map[string]uint64, 0)
|
||||
for _, elfFunc := range elfFuncs {
|
||||
if _, ok := mapObjFuncs[elfFunc.Name]; ok {
|
||||
// Check if the function is already in mapArrayFuncs
|
||||
val, ok := mapArrayFuncs[elfFunc.Name]
|
||||
// Do not add duplicate functions (check on addresses)
|
||||
if !ok {
|
||||
mapArrayFuncs[elfFunc.Name] = elfFunc.Addr
|
||||
elfFuncsAll = append(elfFuncsAll, elfFunc)
|
||||
} else if val != elfFunc.Addr {
|
||||
elfFuncsAll = append(elfFuncsAll, elfFunc)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if len(elfFuncsAll) == 0 {
|
||||
u.PrintWarning(fmt.Sprintf("Cannot extract mapping of lib %s: No function", obj.Name))
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
||||
if len(elfFuncsAll) != len(objFuncs) {
|
||||
// We do not have the same set of functions, need to filter it.
|
||||
filteredFuncs := filterFunctions(objFuncs, elfFuncsAll)
|
||||
if filteredFuncs == nil {
|
||||
u.PrintWarning(fmt.Sprintf("Cannot extract mapping of lib %s: Different size", obj.Name))
|
||||
return 0, 0, 0
|
||||
}
|
||||
return filteredFuncs[0].Addr, filteredFuncs[len(filteredFuncs)-1].Size +
|
||||
filteredFuncs[len(filteredFuncs)-1].Addr, len(filteredFuncs)
|
||||
}
|
||||
|
||||
return elfFuncsAll[0].Addr, elfFuncsAll[len(elfFuncsAll)-1].Size +
|
||||
elfFuncsAll[len(elfFuncsAll)-1].Addr, len(elfFuncsAll)
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) InspectMapping(elf *elf64core.ELF64File, objs ...interface{}) {
|
||||
|
||||
if len(objs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
analyser.ElfLibs = make([]ElfLibs, 0)
|
||||
for _, iobj := range objs {
|
||||
obj := iobj.(*elf64core.ELF64File)
|
||||
start, end, nbSymbols := compareFunctions(elf, obj)
|
||||
analyser.ElfLibs = append(analyser.ElfLibs, ElfLibs{
|
||||
Name: obj.Name,
|
||||
StartAddr: start,
|
||||
EndAddr: end,
|
||||
Size: end - start,
|
||||
NbSymbols: nbSymbols,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// sort functions
|
||||
sort.Slice(analyser.ElfLibs, func(i, j int) bool {
|
||||
return analyser.ElfLibs[i].StartAddr < analyser.ElfLibs[j].StartAddr
|
||||
})
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File,
|
||||
objs []*elf64core.ELF64File) {
|
||||
|
||||
if len(objs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
analyser.ElfLibs = make([]ElfLibs, 0)
|
||||
for _, obj := range objs {
|
||||
start, end, nbSymbols := compareFunctions(elf, obj)
|
||||
analyser.ElfLibs = append(analyser.ElfLibs, ElfLibs{
|
||||
Name: obj.Name,
|
||||
StartAddr: start,
|
||||
EndAddr: end,
|
||||
Size: end - start,
|
||||
NbSymbols: nbSymbols,
|
||||
})
|
||||
}
|
||||
|
||||
// sort functions by start address.
|
||||
sort.Slice(analyser.ElfLibs, func(i, j int) bool {
|
||||
return analyser.ElfLibs[i].StartAddr < analyser.ElfLibs[j].StartAddr
|
||||
})
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) SplitIntoPagesBySection(elfFile *elf64core.ELF64File, sectionName string) {
|
||||
|
||||
if len(analyser.ElfPage) == 0 {
|
||||
analyser.ElfPage = make([]*ElfPage, 0)
|
||||
}
|
||||
|
||||
if strings.Contains(sectionName, elf64core.TextSection) {
|
||||
// An ELF might have several text sections
|
||||
for _, indexSection := range elfFile.TextSectionIndex {
|
||||
sectionName := elfFile.SectionsTable.DataSect[indexSection].Name
|
||||
analyser.computePage(elfFile, sectionName, indexSection)
|
||||
}
|
||||
} else if indexSection, ok := elfFile.IndexSections[sectionName]; ok {
|
||||
analyser.computePage(elfFile, sectionName, indexSection)
|
||||
} else {
|
||||
u.PrintWarning(fmt.Sprintf("Cannot split section %s into pages", sectionName))
|
||||
}
|
||||
}
|
||||
|
||||
func CreateNewPage(startAddress uint64, k int, raw []byte) *ElfPage {
|
||||
byteArray := make([]byte, pageSize)
|
||||
b := raw
|
||||
if cpd := copy(byteArray, b); cpd == 0 {
|
||||
u.PrintWarning("0 bytes were copied")
|
||||
}
|
||||
page := &ElfPage{
|
||||
number: k,
|
||||
startAddress: startAddress,
|
||||
contentByteArray: byteArray,
|
||||
}
|
||||
h := sha256.New()
|
||||
h.Write(page.contentByteArray)
|
||||
page.hash = hex.EncodeToString(h.Sum(nil))
|
||||
return page
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) computePage(elfFile *elf64core.ELF64File, section string, indexSection int) {
|
||||
offsetTextSection := elfFile.SectionsTable.DataSect[indexSection].Elf64section.FileOffset
|
||||
k := 0
|
||||
for i := offsetTextSection; i < offsetTextSection+elfFile.SectionsTable.DataSect[indexSection].Elf64section.Size; i += pageSize {
|
||||
|
||||
end := i + pageSize
|
||||
if end >= uint64(len(elfFile.Raw)) {
|
||||
end = uint64(len(elfFile.Raw) - 1)
|
||||
}
|
||||
page := CreateNewPage(i, k, elfFile.Raw[i:end])
|
||||
page.sectionName = section
|
||||
analyser.ElfPage = append(analyser.ElfPage, page)
|
||||
k++
|
||||
}
|
||||
}
|
124
srcs/binarytool/elf64analyser/elf_pages.go
Normal file
124
srcs/binarytool/elf64analyser/elf_pages.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64analyser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const pageSize = 0x1000
|
||||
|
||||
type ElfFileSegment struct {
|
||||
Filename string
|
||||
NbPages int
|
||||
Pages []*ElfPage
|
||||
}
|
||||
|
||||
type ElfPage struct {
|
||||
number int
|
||||
startAddress uint64
|
||||
contentByteArray []byte
|
||||
hash string
|
||||
libName string
|
||||
sectionName string
|
||||
noNullValues int
|
||||
cap int
|
||||
}
|
||||
|
||||
func (p *ElfPage) pageContentToString() string {
|
||||
|
||||
var builder strings.Builder
|
||||
for i, entry := range p.contentByteArray {
|
||||
|
||||
if i > 0 && i%4 == 0 {
|
||||
builder.WriteString(" ")
|
||||
}
|
||||
|
||||
if i > 0 && i%16 == 0 {
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
|
||||
_, _ = builder.WriteString(fmt.Sprintf("%02x", entry))
|
||||
|
||||
}
|
||||
_, _ = builder.WriteString("")
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (p *ElfPage) displayPageContent(mw io.Writer) {
|
||||
|
||||
/*
|
||||
hexStartAddr, err := strconv.ParseInt(p.startAddress, 16, 64);
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
for i, entry := range p.contentByteArray {
|
||||
|
||||
if i > 0 && i%4 == 0 {
|
||||
_, _ = fmt.Fprintf(mw, " ")
|
||||
}
|
||||
|
||||
if i > 0 && i%16 == 0 {
|
||||
_, _ = fmt.Fprintf(mw, "\n")
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(mw, "%02x", entry)
|
||||
|
||||
}
|
||||
_, _ = fmt.Fprintln(mw, "")
|
||||
}
|
||||
|
||||
func (p *ElfPage) displayPageContentShort(mw io.Writer) {
|
||||
|
||||
entryLine := 0
|
||||
for i, entry := range p.contentByteArray {
|
||||
|
||||
if entry > 0 {
|
||||
_, _ = fmt.Fprintf(mw, "[%d] %02x ", i, entry)
|
||||
if entryLine > 0 && entryLine%16 == 0 {
|
||||
_, _ = fmt.Fprintf(mw, "\n")
|
||||
}
|
||||
entryLine++
|
||||
}
|
||||
}
|
||||
_, _ = fmt.Fprintln(mw, "")
|
||||
}
|
||||
|
||||
func SavePagesToFile(pageTables []*ElfPage, filename string, shortView bool) error {
|
||||
|
||||
mw := io.MultiWriter(os.Stdout)
|
||||
if len(filename) > 0 {
|
||||
file, err := os.Create(filename)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mw = io.MultiWriter(file)
|
||||
}
|
||||
|
||||
for i, p := range pageTables {
|
||||
_, _ = fmt.Fprintln(mw, "----------------------------------------------------")
|
||||
_, _ = fmt.Fprintf(mw, "Page: %d\n", i+1)
|
||||
_, _ = fmt.Fprintf(mw, "LibName: %s\n", p.libName)
|
||||
_, _ = fmt.Fprintf(mw, "Section: %s\n", p.sectionName)
|
||||
_, _ = fmt.Fprintf(mw, "StartAddr: %x (%d)\n", p.startAddress, p.startAddress)
|
||||
_, _ = fmt.Fprintf(mw, "Non-Null value: %d\n", p.noNullValues)
|
||||
_, _ = fmt.Fprintf(mw, "Hash: %s\n", p.hash)
|
||||
|
||||
if shortView {
|
||||
p.displayPageContentShort(mw)
|
||||
} else {
|
||||
p.displayPageContent(mw)
|
||||
}
|
||||
_, _ = fmt.Fprintln(mw, "----------------------------------------------------")
|
||||
}
|
||||
return nil
|
||||
}
|
227
srcs/binarytool/elf64analyser/elf_stats.go
Normal file
227
srcs/binarytool/elf64analyser/elf_stats.go
Normal file
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64analyser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"tools/srcs/binarytool/elf64core"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type ComparisonElf struct {
|
||||
GroupFileSegment []*ElfFileSegment
|
||||
dictSamePage map[string]int
|
||||
dictFile map[string]map[string]int
|
||||
}
|
||||
|
||||
func (comparison *ComparisonElf) processDictName(filename, hash string) {
|
||||
m := comparison.dictFile[hash]
|
||||
if _, ok := m[filename]; !ok {
|
||||
m[filename] = 1
|
||||
} else {
|
||||
t := m[filename]
|
||||
t += 1
|
||||
m[filename] = t
|
||||
}
|
||||
comparison.dictFile[hash] = m
|
||||
}
|
||||
|
||||
func (comparison *ComparisonElf) ComparePageTables() {
|
||||
|
||||
comparison.dictSamePage = make(map[string]int)
|
||||
comparison.dictFile = make(map[string]map[string]int)
|
||||
|
||||
for _, file := range comparison.GroupFileSegment {
|
||||
|
||||
for _, p := range file.Pages {
|
||||
if _, ok := comparison.dictSamePage[p.hash]; !ok {
|
||||
comparison.dictSamePage[p.hash] = 1
|
||||
comparison.dictFile[p.hash] = make(map[string]int)
|
||||
} else {
|
||||
comparison.dictSamePage[p.hash] += 1
|
||||
}
|
||||
comparison.processDictName(file.Filename, p.hash)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (comparison *ComparisonElf) DisplayComparison() {
|
||||
|
||||
fmt.Println("\n\nHash comparison:")
|
||||
for key, value := range comparison.dictFile {
|
||||
fmt.Println(key, ";", value)
|
||||
}
|
||||
|
||||
fmt.Println("---------------------------")
|
||||
fmt.Println("\n\nStats:")
|
||||
countSamePage := 0
|
||||
singlePage := 0
|
||||
for _, value := range comparison.dictSamePage {
|
||||
if value > 1 {
|
||||
countSamePage += value
|
||||
} else {
|
||||
singlePage++
|
||||
}
|
||||
}
|
||||
|
||||
totalNbPages := 0
|
||||
for i, _ := range comparison.GroupFileSegment {
|
||||
totalNbPages += comparison.GroupFileSegment[i].NbPages
|
||||
}
|
||||
ratio := (float64(countSamePage) / float64(totalNbPages)) * 100
|
||||
|
||||
fmt.Printf("- Total Nb of pages: %d\n", totalNbPages)
|
||||
fmt.Printf("- Nb page(s) sharing: %d\n", countSamePage)
|
||||
fmt.Printf("- Page alone: %d\n", singlePage)
|
||||
fmt.Printf("- Ratio: %f\n", ratio)
|
||||
}
|
||||
|
||||
func filterOutput(text1, text2 []string) string {
|
||||
header := "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>Diff Pages</title></head><body style=\"font-family:Menlo\">"
|
||||
footer := "</body></html>"
|
||||
|
||||
maxArray := text1
|
||||
minArray := text2
|
||||
if len(text1) < len(text2) {
|
||||
maxArray = text2
|
||||
minArray = text1
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
for i := 0; i < len(maxArray); i++ {
|
||||
builder.WriteString("<span>" + maxArray[i] + "</span><br>")
|
||||
if i < len(minArray)-1 && maxArray[i] != minArray[i] {
|
||||
builder.WriteString("<p><del style=\"background:#ffe6e6;\">" + minArray[i] + "</del><br>")
|
||||
builder.WriteString("<ins style=\"background:#e6ffe6;\">" + maxArray[i] + "</ins></p>")
|
||||
}
|
||||
}
|
||||
|
||||
return header + builder.String() + footer
|
||||
}
|
||||
|
||||
func (comparison *ComparisonElf) DiffComparison(path string) error {
|
||||
|
||||
if len(comparison.GroupFileSegment) != 2 {
|
||||
return errors.New("multi-comparison (more than 2) is still not supported")
|
||||
}
|
||||
|
||||
minPage := comparison.GroupFileSegment[0].Pages
|
||||
for _, file := range comparison.GroupFileSegment {
|
||||
if len(minPage) > len(file.Pages) {
|
||||
minPage = file.Pages
|
||||
}
|
||||
}
|
||||
|
||||
println(len(comparison.GroupFileSegment[0].Pages))
|
||||
println(len(comparison.GroupFileSegment[1].Pages))
|
||||
|
||||
for i := 0; i < len(minPage); i++ {
|
||||
|
||||
page1 := comparison.GroupFileSegment[0].Pages[i]
|
||||
page2 := comparison.GroupFileSegment[1].Pages[i]
|
||||
if page1.hash != page2.hash {
|
||||
|
||||
text1String := comparison.GroupFileSegment[0].Pages[i].pageContentToString()
|
||||
text2String := comparison.GroupFileSegment[1].Pages[i].pageContentToString()
|
||||
text1 := strings.Split(text1String, "\n")
|
||||
text2 := strings.Split(text2String, "\n")
|
||||
str := filterOutput(text1, text2)
|
||||
|
||||
file, err := os.Create(path + "page_" + strconv.Itoa(page1.number) + "_diff.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := file.WriteString(str); err != nil {
|
||||
return err
|
||||
}
|
||||
file.Close()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) DisplaySectionInfo(elfFile *elf64core.ELF64File, info []string) {
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 10, 8, 0, '\t', 0)
|
||||
_, _ = fmt.Fprintln(w, "Name\tAddress\tOffset\tSize")
|
||||
for _, sectionName := range info {
|
||||
if indexSection, ok := elfFile.IndexSections[sectionName]; ok {
|
||||
section := elfFile.SectionsTable.DataSect[indexSection].Elf64section
|
||||
|
||||
_, _ = fmt.Fprintf(w, "- %s\t0x%.6x\t0x%.6x\t%d\n",
|
||||
sectionName, section.VirtualAddress, section.FileOffset,
|
||||
section.Size)
|
||||
|
||||
} else {
|
||||
u.PrintWarning("Wrong section name " + sectionName)
|
||||
}
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) FindSectionByAddress(elfFile *elf64core.ELF64File, addresses []string) {
|
||||
if len(elfFile.SectionsTable.DataSect) == 0 {
|
||||
u.PrintWarning("Sections table is empty")
|
||||
return
|
||||
}
|
||||
for _, addr := range addresses {
|
||||
hexStr := strings.Replace(addr, "0x", "", -1)
|
||||
intAddr, err := strconv.ParseUint(hexStr, 16, 64)
|
||||
if err != nil {
|
||||
u.PrintWarning(fmt.Sprintf("Error %s: Cannot convert %s to integer. Skip.", err, addr))
|
||||
} else {
|
||||
found := false
|
||||
for _, s := range elfFile.SectionsTable.DataSect {
|
||||
if s.Elf64section.VirtualAddress <= intAddr && intAddr < s.Elf64section.VirtualAddress+s.Elf64section.Size {
|
||||
fmt.Printf("Address %s is in section %s\n", addr, s.Name)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
u.PrintWarning(fmt.Sprintf("Cannot find a section for address: %s", addr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (analyser *ElfAnalyser) DisplayStatSize(elfFile *elf64core.ELF64File) {
|
||||
if len(elfFile.SectionsTable.DataSect) == 0 {
|
||||
u.PrintWarning("Sections table is empty")
|
||||
return
|
||||
}
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
|
||||
var totalSizeText uint64
|
||||
var totalSizeElf uint64
|
||||
_, _ = fmt.Fprintf(w, "Name\tFile size (Bytes/Hex)\n")
|
||||
for _, s := range elfFile.SectionsTable.DataSect {
|
||||
if len(s.Name) > 0 {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%d (0x%x)\n", s.Name, s.Elf64section.Size, s.Elf64section.Size)
|
||||
}
|
||||
if strings.Contains(s.Name, elf64core.TextSection) {
|
||||
totalSizeText += s.Elf64section.Size
|
||||
}
|
||||
totalSizeElf += s.Elf64section.Size
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "----------------------\t----------------------\n")
|
||||
_, _ = fmt.Fprintf(w, "Total Size:\n")
|
||||
_, _ = fmt.Fprintf(w, "Section .text:\t%d (0x%x)\n", totalSizeText, totalSizeText)
|
||||
_, _ = fmt.Fprintf(w, "All sections:\t%d (0x%x)\n", totalSizeElf, totalSizeElf)
|
||||
_, _ = fmt.Fprintf(w, "#Pages (.text):\t%d\n", totalSizeText/pageSize)
|
||||
_, _ = fmt.Fprintf(w, "#Pages (all sections):\t%d\n", totalSizeElf/pageSize)
|
||||
_ = w.Flush()
|
||||
}
|
171
srcs/binarytool/elf64core/elf_constant.go
Normal file
171
srcs/binarytool/elf64core/elf_constant.go
Normal file
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
const (
|
||||
TextSection = ".text"
|
||||
BssSection = ".bss"
|
||||
DataSection = ".data"
|
||||
RodataSection = ".rodata"
|
||||
|
||||
BootTextSection = ".text.boot"
|
||||
BootDataSection = ".data.boot"
|
||||
UkCtorTabSection = ".uk_ctortab"
|
||||
UkInitTabSection = ".uk_inittab"
|
||||
)
|
||||
|
||||
var rx86_64Strings = map[uint32]string{
|
||||
0: "R_X86_64_NONE",
|
||||
1: "R_X86_64_64",
|
||||
2: "R_X86_64_PC32",
|
||||
3: "R_X86_64_GOT32",
|
||||
4: "R_X86_64_PLT32",
|
||||
5: "R_X86_64_COPY",
|
||||
6: "R_X86_64_GLOB_DAT",
|
||||
7: "R_X86_64_JMP_SLOT",
|
||||
8: "R_X86_64_RELATIVE",
|
||||
9: "R_X86_64_GOTPCREL",
|
||||
10: "R_X86_64_32",
|
||||
11: "R_X86_64_32S",
|
||||
12: "R_X86_64_16",
|
||||
13: "R_X86_64_PC16",
|
||||
14: "R_X86_64_8",
|
||||
15: "R_X86_64_PC8",
|
||||
16: "R_X86_64_DTPMOD64",
|
||||
17: "R_X86_64_DTPOFF64",
|
||||
18: "R_X86_64_TPOFF64",
|
||||
19: "R_X86_64_TLSGD",
|
||||
20: "R_X86_64_TLSLD",
|
||||
21: "R_X86_64_DTPOFF32",
|
||||
22: "R_X86_64_GOTTPOFF",
|
||||
23: "R_X86_64_TPOFF32",
|
||||
24: "R_X86_64_PC64",
|
||||
25: "R_X86_64_GOTOFF64",
|
||||
26: "R_X86_64_GOTPC32",
|
||||
27: "R_X86_64_GOT64",
|
||||
28: "R_X86_64_GOTPCREL64",
|
||||
29: "R_X86_64_GOTPC64",
|
||||
30: "R_X86_64_GOTPLT64",
|
||||
31: "R_X86_64_PLTOFF64",
|
||||
32: "R_X86_64_SIZE32",
|
||||
33: "R_X86_64_SIZE64",
|
||||
34: "R_X86_64_GOTPC32_TLSDESC",
|
||||
35: "R_X86_64_TLSDESC_CALL",
|
||||
36: "R_X86_64_TLSDESC",
|
||||
37: "R_X86_64_IRELATIVE",
|
||||
38: "R_X86_64_RELATIVE64",
|
||||
39: "R_X86_64_PC32_BND",
|
||||
40: "R_X86_64_PLT32_BND",
|
||||
41: "R_X86_64_GOTPCRELX",
|
||||
42: "R_X86_64_REX_GOTPCRELX",
|
||||
}
|
||||
|
||||
var shtStrings = map[uint32]string{
|
||||
0: "SHT_NULL",
|
||||
1: "SHT_PROGBITS",
|
||||
2: "SHT_SYMTAB",
|
||||
3: "SHT_STRTAB",
|
||||
4: "SHT_RELA",
|
||||
5: "SHT_HASH",
|
||||
6: "SHT_DYNAMIC",
|
||||
7: "SHT_NOTE",
|
||||
8: "SHT_NOBITS",
|
||||
9: "SHT_REL",
|
||||
10: "SHT_SHLIB",
|
||||
11: "SHT_DYNSYM",
|
||||
14: "SHT_INIT_ARRAY",
|
||||
15: "SHT_FINI_ARRAY",
|
||||
16: "SHT_PREINIT_ARRAY",
|
||||
17: "SHT_GROUP",
|
||||
18: "SHT_SYMTAB_SHNDX",
|
||||
0x60000000: "SHT_LOOS",
|
||||
0x6ffffff5: "SHT_GNU_ATTRIBUTES",
|
||||
0x6ffffff6: "SHT_GNU_HASH",
|
||||
0x6ffffff7: "SHT_GNU_LIBLIST",
|
||||
0x6ffffffd: "SHT_GNU_VERDEF",
|
||||
0x6ffffffe: "SHT_GNU_VERNEED",
|
||||
0x6fffffff: "SHT_GNU_VERSYM",
|
||||
0x70000000: "SHT_LOPROC",
|
||||
0x7fffffff: "SHT_HIPROC",
|
||||
0x80000000: "SHT_LOUSER",
|
||||
0xffffffff: "SHT_HIUSER",
|
||||
}
|
||||
|
||||
var sttStrings = map[byte]string{
|
||||
0: "NOTYPE",
|
||||
1: "OBJECT",
|
||||
2: "FUNC",
|
||||
3: "SECTION",
|
||||
4: "FILE",
|
||||
5: "COMMON",
|
||||
6: "TLS",
|
||||
10: "LOOS",
|
||||
12: "HIOS",
|
||||
13: "LOPROC",
|
||||
15: "HIPROC",
|
||||
}
|
||||
|
||||
var ptStrings = map[uint32]string{
|
||||
0: "PT_NULL",
|
||||
1: "PT_LOAD",
|
||||
2: "PT_DYNAMIC",
|
||||
3: "PT_INTERP",
|
||||
4: "PT_NOTE",
|
||||
5: "PT_SHLIB",
|
||||
6: "PT_PHDR",
|
||||
7: "PT_TLS",
|
||||
0x60000000: "PT_LOOS",
|
||||
0x6fffffff: "PT_HIOS",
|
||||
0x70000000: "PT_LOPROC",
|
||||
0x7fffffff: "PT_HIPROC",
|
||||
0x6474e550: "GNU_EH_FRAME",
|
||||
0x6474e551: "GNU_STACK",
|
||||
0x6474e552: "GNU_RELRO",
|
||||
}
|
||||
|
||||
var dtStrings = map[uint64]string{
|
||||
0: "DT_NULL",
|
||||
1: "DT_NEEDED",
|
||||
2: "DT_PLTRELSZ",
|
||||
3: "DT_PLTGOT",
|
||||
4: "DT_HASH",
|
||||
5: "DT_STRTAB",
|
||||
6: "DT_SYMTAB",
|
||||
7: "DT_RELA",
|
||||
8: "DT_RELASZ",
|
||||
9: "DT_RELAENT",
|
||||
10: "DT_STRSZ",
|
||||
11: "DT_SYMENT",
|
||||
12: "DT_INIT",
|
||||
13: "DT_FINI",
|
||||
14: "DT_SONAME",
|
||||
15: "DT_RPATH",
|
||||
16: "DT_SYMBOLIC",
|
||||
17: "DT_REL",
|
||||
18: "DT_RELSZ",
|
||||
19: "DT_RELENT",
|
||||
20: "DT_PLTREL",
|
||||
21: "DT_DEBUG",
|
||||
22: "DT_TEXTREL",
|
||||
23: "DT_JMPREL",
|
||||
24: "DT_BIND_NOW",
|
||||
25: "DT_INIT_ARRAY",
|
||||
26: "DT_FINI_ARRAY",
|
||||
27: "DT_INIT_ARRAYSZ",
|
||||
28: "DT_FINI_ARRAYSZ",
|
||||
29: "DT_RUNPATH",
|
||||
30: "DT_FLAGS",
|
||||
32: "DT_PREINIT_ARRAY",
|
||||
33: "DT_PREINIT_ARRAYSZ",
|
||||
0x6000000d: "DT_LOOS",
|
||||
0x6ffff000: "DT_HIOS",
|
||||
0x6ffffff0: "DT_VERSYM",
|
||||
0x6ffffffe: "DT_VERNEED",
|
||||
0x6fffffff: "DT_VERNEEDNUM",
|
||||
0x70000000: "DT_LOPROC",
|
||||
0x7fffffff: "DT_HIPROC",
|
||||
}
|
85
srcs/binarytool/elf64core/elf_dynamic.go
Normal file
85
srcs/binarytool/elf64core/elf_dynamic.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type DynamicTable struct {
|
||||
nbEntries int
|
||||
name string
|
||||
elf64dyn []Elf64Dynamic
|
||||
}
|
||||
|
||||
type Elf64Dynamic struct {
|
||||
Tag uint64
|
||||
Value uint64
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) addDynamicEntry(index int, dynEntries []Elf64Dynamic) error {
|
||||
|
||||
elfFile.DynamicTable = DynamicTable{}
|
||||
elfFile.DynamicTable.nbEntries = len(dynEntries)
|
||||
elfFile.DynamicTable.name = elfFile.SectionsTable.DataSect[index].Name
|
||||
elfFile.DynamicTable.elf64dyn = make([]Elf64Dynamic, 0)
|
||||
|
||||
for _, s := range dynEntries {
|
||||
elfFile.DynamicTable.elf64dyn = append(elfFile.DynamicTable.elf64dyn, s)
|
||||
if s.Tag == uint64(elf.DT_NULL) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) parseDynamic(index int) error {
|
||||
|
||||
content, err := elfFile.GetSectionContent(uint16(index))
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading relocation table: %s", err)
|
||||
}
|
||||
|
||||
dynEntries := make([]Elf64Dynamic, len(content)/binary.Size(Elf64Dynamic{}))
|
||||
if err := binary.Read(bytes.NewReader(content),
|
||||
elfFile.Endianness, dynEntries); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.addDynamicEntry(index, dynEntries); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table *DynamicTable) DisplayDynamicEntries() {
|
||||
|
||||
if len(table.elf64dyn) == 0 {
|
||||
u.PrintWarning("Dynamic table is empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
|
||||
fmt.Printf("%s table contains %d entries:\n\n", table.name, table.nbEntries)
|
||||
_, _ = fmt.Fprintln(w, "Nr\tTag\tType\tValue")
|
||||
for i, s := range table.elf64dyn {
|
||||
_, _ = fmt.Fprintf(w, "%d:\t%.8x\t%s\t%x\n", i, s.Tag,
|
||||
dtStrings[s.Tag], s.Value)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
82
srcs/binarytool/elf64core/elf_file.go
Normal file
82
srcs/binarytool/elf64core/elf_file.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ELF64File struct {
|
||||
Header *ELF64Header
|
||||
SectionsTable SectionsTable
|
||||
SegmentsTable ProgramTable
|
||||
DynamicTable DynamicTable
|
||||
SymbolsTables []SymbolsTables
|
||||
RelaTables []RelaTables
|
||||
NotesTables []NotesTables
|
||||
FunctionsTables []FunctionTables
|
||||
Raw []byte
|
||||
IndexSections map[string]int
|
||||
Name string
|
||||
Endianness binary.ByteOrder
|
||||
TextSectionIndex []int // slice since we can have several
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) ReadElfBinaryFile(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
stats, statsErr := file.Stat()
|
||||
if statsErr != nil {
|
||||
return statsErr
|
||||
}
|
||||
|
||||
var size = stats.Size()
|
||||
elfFile.Raw = make([]byte, size)
|
||||
|
||||
buf := bufio.NewReader(file)
|
||||
_, err = buf.Read(elfFile.Raw)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) ParseAll(path, name string) error {
|
||||
|
||||
elfFile.Name = name
|
||||
|
||||
if err := elfFile.ReadElfBinaryFile(path + name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.ParseElfHeader(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.ParseSectionHeaders(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.ParseSections(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.ParseProgramHeaders(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.parseFunctions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
151
srcs/binarytool/elf64core/elf_function.go
Normal file
151
srcs/binarytool/elf64core/elf_function.go
Normal file
|
@ -0,0 +1,151 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type FunctionTables struct {
|
||||
Name string
|
||||
NbEntries int
|
||||
Functions []ELF64Function
|
||||
}
|
||||
|
||||
type ELF64Function struct {
|
||||
Name string
|
||||
Addr uint64
|
||||
Size uint64
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) getIndexFctTable(ndx uint16) int {
|
||||
|
||||
if int(ndx) > len(elfFile.SectionsTable.DataSect) {
|
||||
return -1
|
||||
}
|
||||
|
||||
sectionName := elfFile.SectionsTable.DataSect[ndx].Name
|
||||
for i, t := range elfFile.FunctionsTables {
|
||||
if strings.Compare(t.Name, sectionName) == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) detectSizeSymbol(symbolsTable []ELF64Function, index int) uint64 {
|
||||
|
||||
if index+1 == len(symbolsTable) {
|
||||
textIndex := elfFile.IndexSections[TextSection]
|
||||
textSection := elfFile.SectionsTable.DataSect[textIndex]
|
||||
size := textSection.Elf64section.FileOffset + textSection.Elf64section.Size
|
||||
return size - symbolsTable[index].Addr
|
||||
}
|
||||
return symbolsTable[index+1].Addr - symbolsTable[index].Addr
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) inspectFunctions() error {
|
||||
|
||||
for _, table := range elfFile.SymbolsTables {
|
||||
for _, s := range table.dataSymbols {
|
||||
k := elfFile.getIndexFctTable(s.elf64sym.Shndx)
|
||||
if k != -1 && s.elf64sym.Value > 0 {
|
||||
if !isInSlice(elfFile.Name, s.name) {
|
||||
function := ELF64Function{Name: s.name, Addr: s.elf64sym.Value,
|
||||
Size: s.elf64sym.Size}
|
||||
elfFile.FunctionsTables[k].Functions =
|
||||
append(elfFile.FunctionsTables[k].Functions, function)
|
||||
}
|
||||
} else if s.TypeSymbol == byte(elf.STT_FUNC) {
|
||||
// If it is a func where the start address starts at 0
|
||||
function := ELF64Function{Name: s.name, Addr: s.elf64sym.Value,
|
||||
Size: s.elf64sym.Size}
|
||||
elfFile.FunctionsTables[k].Functions =
|
||||
append(elfFile.FunctionsTables[k].Functions, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) parseFunctions() error {
|
||||
|
||||
if _, ok := elfFile.IndexSections[TextSection]; ok {
|
||||
|
||||
if err := elfFile.inspectFunctions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
return errors.New("no text section detected")
|
||||
}
|
||||
|
||||
for _, table := range elfFile.FunctionsTables {
|
||||
// sort Functions
|
||||
|
||||
sort.Slice(table.Functions, func(i, j int) bool {
|
||||
return table.Functions[i].Addr < table.Functions[j].Addr
|
||||
})
|
||||
|
||||
for i, f := range table.Functions {
|
||||
if f.Size == 0 {
|
||||
f.Size = elfFile.detectSizeSymbol(table.Functions, i)
|
||||
}
|
||||
|
||||
// Special case where symbol of same address can be in different order
|
||||
// between the ELF and the object file
|
||||
if i < len(table.Functions)-1 && table.Functions[i].Addr == table.Functions[i+1].Addr {
|
||||
if strings.Compare(table.Functions[i].Name, table.Functions[i+1].Name) > 0 {
|
||||
swap(i, table.Functions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func swap(index int, x []ELF64Function) {
|
||||
x[index], x[index+1] = x[index+1], x[index]
|
||||
}
|
||||
|
||||
func (table *FunctionTables) displayFunctions(w *tabwriter.Writer, fullDisplay bool) {
|
||||
|
||||
_, _ = fmt.Fprintf(w, "\nTable section '%s' contains %d entries:\n",
|
||||
table.Name, table.NbEntries)
|
||||
_, _ = fmt.Fprintf(w, "Name:\tAddr:\tSize\tRaw:\n")
|
||||
for _, f := range table.Functions {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%6.x\t%6.x\t%s\n", f.Name, f.Addr, f.Size)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) DisplayFunctionsTables(fullDisplay bool) {
|
||||
|
||||
if len(elfFile.FunctionsTables) == 0 {
|
||||
u.PrintWarning("Functions table(s) is/are empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
|
||||
for _, table := range elfFile.FunctionsTables {
|
||||
table.displayFunctions(w, fullDisplay)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
100
srcs/binarytool/elf64core/elf_header.go
Normal file
100
srcs/binarytool/elf64core/elf_header.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
const (
|
||||
identLength = 16
|
||||
littleEndian = 1
|
||||
)
|
||||
|
||||
type ELF64Header struct {
|
||||
Ident [identLength]byte
|
||||
Type uint16
|
||||
Machine uint16
|
||||
Version uint32
|
||||
EntryPoint uint64
|
||||
ProgramHeaderOffset uint64
|
||||
SectionHeaderOffset uint64
|
||||
Flags uint32
|
||||
HeaderSize uint16
|
||||
ProgramHeaderEntrySize uint16
|
||||
ProgramHeaderEntries uint16
|
||||
SectionHeaderEntrySize uint16
|
||||
SectionHeaderEntries uint16
|
||||
SectionNamesTable uint16
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) ParseElfHeader() error {
|
||||
|
||||
elfFile.Header = new(ELF64Header)
|
||||
|
||||
// Check the size
|
||||
if len(elfFile.Raw) < identLength {
|
||||
return errors.New("invalid size")
|
||||
}
|
||||
|
||||
// Check the magic number
|
||||
if elfFile.Raw[0] != 0x7f && elfFile.Raw[1] != 0x45 &&
|
||||
elfFile.Raw[2] != 0x4c && elfFile.Raw[3] != 0x46 {
|
||||
return errors.New("invalid ELF file")
|
||||
}
|
||||
|
||||
// Check the type
|
||||
if elfFile.Raw[4] != 0x02 {
|
||||
return errors.New("elf32 is not supported")
|
||||
}
|
||||
|
||||
if elfFile.Raw[5] == littleEndian {
|
||||
elfFile.Endianness = binary.LittleEndian
|
||||
} else {
|
||||
elfFile.Endianness = binary.BigEndian
|
||||
}
|
||||
|
||||
data := bytes.NewReader(elfFile.Raw)
|
||||
err := binary.Read(data, elfFile.Endianness, elfFile.Header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfHeader ELF64Header) DisplayHeader() {
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
_, _ = fmt.Fprintf(w, "Magic Header:\t")
|
||||
for _, hex := range elfHeader.Ident {
|
||||
_, _ = fmt.Fprintf(w, "%.2x ", hex)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(w, "\nType:\t%x\n", elfHeader.Type)
|
||||
_, _ = fmt.Fprintf(w, "Machine:\t%d\n", elfHeader.Machine)
|
||||
_, _ = fmt.Fprintf(w, "Version:\t0x%x\n", elfHeader.Version)
|
||||
_, _ = fmt.Fprintf(w, "EntryPoint:\t0x%x\n", elfHeader.EntryPoint)
|
||||
_, _ = fmt.Fprintf(w, "ProgramHeaderOffset:\t%d\n", elfHeader.ProgramHeaderOffset)
|
||||
_, _ = fmt.Fprintf(w, "SectionHeaderOffset:\t%d\n", elfHeader.SectionHeaderOffset)
|
||||
_, _ = fmt.Fprintf(w, "Flags:\t0x%x\n", elfHeader.Flags)
|
||||
_, _ = fmt.Fprintf(w, "HeaderSize:\t%d\n", elfHeader.HeaderSize)
|
||||
_, _ = fmt.Fprintf(w, "ProgramHeaderEntrySize:\t%d\n", elfHeader.ProgramHeaderEntrySize)
|
||||
_, _ = fmt.Fprintf(w, "ProgramHeaderEntries:\t%d\n", elfHeader.ProgramHeaderEntries)
|
||||
_, _ = fmt.Fprintf(w, "SectionHeaderEntrySize:\t%d\n", elfHeader.SectionHeaderEntrySize)
|
||||
_, _ = fmt.Fprintf(w, "SectionHeaderEntries:\t%d\n", elfHeader.SectionHeaderEntries)
|
||||
_, _ = fmt.Fprintf(w, "SectionNamesTable:\t%d\n", elfHeader.SectionNamesTable)
|
||||
|
||||
_ = w.Flush()
|
||||
}
|
73
srcs/binarytool/elf64core/elf_note.go
Normal file
73
srcs/binarytool/elf64core/elf_note.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type NotesTables struct {
|
||||
name string
|
||||
dataNote dataNote
|
||||
}
|
||||
|
||||
type dataNote struct {
|
||||
name string
|
||||
description string
|
||||
elf64note ELF64Note
|
||||
}
|
||||
|
||||
type ELF64Note struct {
|
||||
Namesz uint32
|
||||
Descsz uint32
|
||||
TypeNote uint32
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) parseNote(index int) error {
|
||||
|
||||
var notesTable NotesTables
|
||||
notesTable.name = elfFile.SectionsTable.DataSect[index].Name
|
||||
|
||||
content, err := elfFile.GetSectionContent(uint16(index))
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading note section: %s", err)
|
||||
}
|
||||
|
||||
data := bytes.NewReader(content)
|
||||
err = binary.Read(data, elfFile.Endianness, ¬esTable.dataNote.elf64note)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading elf64note: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) DisplayNotes() {
|
||||
|
||||
if len(elfFile.NotesTables) == 0 {
|
||||
u.PrintWarning("Notes are empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
for _, t := range elfFile.NotesTables {
|
||||
_, _ = fmt.Fprintf(w, "\nDisplaying notes found in: %s\n", t.name)
|
||||
_, _ = fmt.Fprintln(w, " Owner\tData size\tDescription")
|
||||
_, _ = fmt.Fprintf(w, " %s\t0x%.6x\t%x\n", t.dataNote.name,
|
||||
t.dataNote.elf64note.Descsz, t.dataNote.description)
|
||||
}
|
||||
|
||||
_ = w.Flush()
|
||||
}
|
126
srcs/binarytool/elf64core/elf_relocation.go
Normal file
126
srcs/binarytool/elf64core/elf_relocation.go
Normal file
|
@ -0,0 +1,126 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type RelaTables struct {
|
||||
nbEntries int
|
||||
name string
|
||||
dataRela []*dataRela
|
||||
}
|
||||
|
||||
type dataRela struct {
|
||||
name *string
|
||||
elf64Rela Elf64Rela
|
||||
}
|
||||
|
||||
type Elf64Rela struct {
|
||||
Offset uint64
|
||||
Type uint32
|
||||
SymbolIndex uint32
|
||||
Addend int64
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) addRela(index int, relas []Elf64Rela) error {
|
||||
|
||||
var relocationTables RelaTables
|
||||
relocationTables.nbEntries = len(relas)
|
||||
relocationTables.name = elfFile.SectionsTable.DataSect[index].Name
|
||||
relocationTables.dataRela = make([]*dataRela, relocationTables.nbEntries)
|
||||
|
||||
for i := range relas {
|
||||
|
||||
relocationTables.dataRela[i] = &dataRela{
|
||||
elf64Rela: relas[i],
|
||||
name: nil,
|
||||
}
|
||||
}
|
||||
|
||||
elfFile.RelaTables = append(elfFile.RelaTables, relocationTables)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) parseRelocations(index int) error {
|
||||
|
||||
content, err := elfFile.GetSectionContent(uint16(index))
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading relocation table: %s", err)
|
||||
}
|
||||
|
||||
rela := make([]Elf64Rela, len(content)/binary.Size(Elf64Rela{}))
|
||||
if err := binary.Read(bytes.NewReader(content),
|
||||
elfFile.Endianness, rela); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.addRela(index, rela); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) resolveRelocSymbolsName() error {
|
||||
for _, table := range elfFile.RelaTables {
|
||||
for _, s := range table.dataRela {
|
||||
t := 0
|
||||
if s.elf64Rela.Type == uint32(elf.R_X86_64_JMP_SLOT) ||
|
||||
s.elf64Rela.Type == uint32(elf.R_X86_64_GLOB_DAT) ||
|
||||
s.elf64Rela.Type == uint32(elf.R_X86_64_COPY) &&
|
||||
len(elfFile.SymbolsTables) > 1 {
|
||||
t++
|
||||
}
|
||||
|
||||
symName, err := elfFile.SymbolsTables[t].getSymbolName(s.elf64Rela.SymbolIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.name = &symName
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table *RelaTables) displayRelocations(w *tabwriter.Writer) {
|
||||
_, _ = fmt.Fprintf(w, "\nRelocation section '%s' contains %d entries:\n",
|
||||
table.name, table.nbEntries)
|
||||
_, _ = fmt.Fprintln(w, "Offset\tInfo\tType\tValue")
|
||||
for _, r := range table.dataRela {
|
||||
_, _ = fmt.Fprintf(w, "%.6x\t%.6d\t%s\t%s %x\n",
|
||||
r.elf64Rela.Offset, r.elf64Rela.SymbolIndex,
|
||||
rx86_64Strings[r.elf64Rela.Type], *r.name,
|
||||
r.elf64Rela.Addend)
|
||||
}
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) DisplayRelocationTables() {
|
||||
|
||||
if len(elfFile.RelaTables) == 0 {
|
||||
u.PrintWarning("Relocation table(s) are empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
|
||||
for _, table := range elfFile.RelaTables {
|
||||
table.displayRelocations(w)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
187
srcs/binarytool/elf64core/elf_section.go
Normal file
187
srcs/binarytool/elf64core/elf_section.go
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type SectionsTable struct {
|
||||
NbEntries int
|
||||
Name string
|
||||
DataSect []*DataSections
|
||||
}
|
||||
|
||||
type DataSections struct {
|
||||
Name string
|
||||
Elf64section ELF64SectionHeader
|
||||
}
|
||||
|
||||
type ELF64SectionHeader struct {
|
||||
Name uint32
|
||||
Type uint32
|
||||
Flags uint64
|
||||
VirtualAddress uint64
|
||||
FileOffset uint64
|
||||
Size uint64
|
||||
LinkedIndex uint32
|
||||
Info uint32
|
||||
Align uint64
|
||||
EntrySize uint64
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) addSection(sections []ELF64SectionHeader) error {
|
||||
|
||||
elfFile.SectionsTable = SectionsTable{}
|
||||
elfFile.SectionsTable.NbEntries = len(sections)
|
||||
elfFile.SectionsTable.DataSect = make([]*DataSections,
|
||||
elfFile.SectionsTable.NbEntries)
|
||||
|
||||
for i := len(sections) - 1; i >= 0; i-- {
|
||||
elfFile.SectionsTable.DataSect[i] = &DataSections{
|
||||
Elf64section: sections[i],
|
||||
}
|
||||
nameString, err := elfFile.GetSectionName(elfFile.SectionsTable.DataSect[i].Elf64section.Name, elfFile.Header.SectionNamesTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
elfFile.SectionsTable.DataSect[i].Name = nameString
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) ParseSectionHeaders() error {
|
||||
|
||||
offset := elfFile.Header.SectionHeaderOffset
|
||||
if offset >= uint64(len(elfFile.Raw)) {
|
||||
return fmt.Errorf("invalid elf64section header offset: 0x%x", offset)
|
||||
}
|
||||
|
||||
data := bytes.NewReader(elfFile.Raw[offset:])
|
||||
|
||||
sections := make([]ELF64SectionHeader, elfFile.Header.SectionHeaderEntries)
|
||||
err := binary.Read(data, elfFile.Endianness, sections)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading elf64section header table: %s", err)
|
||||
}
|
||||
|
||||
if err := elfFile.addSection(sections); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) GetSectionContent(sectionIndex uint16) ([]byte, error) {
|
||||
|
||||
sectionTable := elfFile.SectionsTable.DataSect
|
||||
if int(sectionIndex) > len(sectionTable) {
|
||||
return nil, fmt.Errorf("invalid elf64section index: %d", sectionIndex)
|
||||
}
|
||||
|
||||
start := sectionTable[sectionIndex].Elf64section.FileOffset
|
||||
if start > uint64(len(elfFile.Raw)) {
|
||||
return nil, fmt.Errorf("bad file offset for elf64section %d", sectionIndex)
|
||||
}
|
||||
|
||||
end := start + sectionTable[sectionIndex].Elf64section.Size
|
||||
if (end > uint64(len(elfFile.Raw))) || (end < start) {
|
||||
return nil, fmt.Errorf("bad size for elf64section %d", sectionIndex)
|
||||
}
|
||||
|
||||
return elfFile.Raw[start:end], nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) GetSectionName(indexString uint32, indexStringTable uint16) (string, error) {
|
||||
|
||||
rawDataStringTable, err := elfFile.GetSectionContent(indexStringTable)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rawDataStart := rawDataStringTable[indexString:]
|
||||
|
||||
return string(rawDataStart[:bytes.IndexByte(rawDataStart, 0)]), nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) ParseSections() error {
|
||||
|
||||
elfFile.IndexSections = make(map[string]int, 0)
|
||||
elfFile.FunctionsTables = make([]FunctionTables, 0)
|
||||
elfFile.TextSectionIndex = make([]int, 0)
|
||||
|
||||
for i := 0; i < len(elfFile.SectionsTable.DataSect)-1; i++ {
|
||||
sectionName := elfFile.SectionsTable.DataSect[i].Name
|
||||
elfFile.IndexSections[sectionName] = i
|
||||
typeSection := elfFile.SectionsTable.DataSect[i].Elf64section.Type
|
||||
switch typeSection {
|
||||
case uint32(elf.SHT_SYMTAB):
|
||||
if err := elfFile.parseSymbolsTable(i); err != nil {
|
||||
return err
|
||||
}
|
||||
case uint32(elf.SHT_RELA):
|
||||
if err := elfFile.parseRelocations(i); err != nil {
|
||||
return err
|
||||
}
|
||||
case uint32(elf.SHT_DYNAMIC):
|
||||
if err := elfFile.parseDynamic(i); err != nil {
|
||||
return err
|
||||
}
|
||||
case uint32(elf.SHT_DYNSYM):
|
||||
if err := elfFile.parseSymbolsTable(i); err != nil {
|
||||
return err
|
||||
}
|
||||
case uint32(elf.SHT_NOTE):
|
||||
if err := elfFile.parseNote(i); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
if strings.Contains(sectionName, TextSection) {
|
||||
elfFile.FunctionsTables = append(elfFile.FunctionsTables, FunctionTables{
|
||||
Name: sectionName,
|
||||
NbEntries: 0,
|
||||
Functions: nil,
|
||||
})
|
||||
|
||||
if typeSection != uint32(elf.SHT_RELA) {
|
||||
elfFile.TextSectionIndex = append(elfFile.TextSectionIndex, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elfFile.resolveRelocSymbolsName()
|
||||
}
|
||||
|
||||
func (table *SectionsTable) DisplaySections() {
|
||||
|
||||
if table.DataSect == nil || len(table.DataSect) == 0 {
|
||||
u.PrintWarning("Section table(s) are empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
_, _ = fmt.Fprintln(w, "Nr\tName\tType\tAddress\tOffset\tSize")
|
||||
for i, s := range table.DataSect {
|
||||
_, _ = fmt.Fprintf(w, "[%d]\t%s\t%s\t%.6x\t%.6x\t%.6x\n", i,
|
||||
s.Name, shtStrings[s.Elf64section.Type],
|
||||
s.Elf64section.VirtualAddress, s.Elf64section.FileOffset,
|
||||
s.Elf64section.Size)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
134
srcs/binarytool/elf64core/elf_segment.go
Normal file
134
srcs/binarytool/elf64core/elf_segment.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type ProgramTable struct {
|
||||
nbEntries int
|
||||
name string
|
||||
dataProgram []*dataProgram
|
||||
}
|
||||
|
||||
type dataProgram struct {
|
||||
sectionsPtr []*DataSections
|
||||
elf64program ELF64ProgramHeader
|
||||
}
|
||||
|
||||
type ELF64ProgramHeader struct {
|
||||
Type uint32
|
||||
Flags uint32
|
||||
FileOffset uint64
|
||||
VirtualAddress uint64
|
||||
PhysicalAddress uint64
|
||||
FileSize uint64
|
||||
MemorySize uint64
|
||||
Align uint64
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) addProgram(programs []ELF64ProgramHeader) error {
|
||||
|
||||
elfFile.SegmentsTable = ProgramTable{}
|
||||
elfFile.SegmentsTable.nbEntries = len(programs)
|
||||
elfFile.SegmentsTable.dataProgram = make([]*dataProgram,
|
||||
elfFile.SegmentsTable.nbEntries)
|
||||
|
||||
for i := range programs {
|
||||
elfFile.SegmentsTable.dataProgram[i] = &dataProgram{
|
||||
elf64program: programs[i],
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) mapSectionSegments() {
|
||||
for _, p := range elfFile.SegmentsTable.dataProgram {
|
||||
for _, s := range elfFile.SectionsTable.DataSect {
|
||||
if s.Elf64section.FileOffset >= p.elf64program.FileOffset &&
|
||||
s.Elf64section.FileOffset+s.Elf64section.Size <= p.elf64program.FileOffset+p.elf64program.FileSize {
|
||||
p.sectionsPtr = append(p.sectionsPtr, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) ParseProgramHeaders() error {
|
||||
|
||||
if elfFile.Header.ProgramHeaderEntries == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
offset := elfFile.Header.ProgramHeaderOffset
|
||||
if offset >= uint64(len(elfFile.Raw)) {
|
||||
return fmt.Errorf("invalid elf64section header offset: 0x%x", offset)
|
||||
}
|
||||
|
||||
data := bytes.NewReader(elfFile.Raw[offset:])
|
||||
|
||||
programs := make([]ELF64ProgramHeader, elfFile.Header.ProgramHeaderEntries)
|
||||
err := binary.Read(data, elfFile.Endianness, programs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading elf64section header table: %s", err)
|
||||
}
|
||||
|
||||
if err := elfFile.addProgram(programs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
elfFile.mapSectionSegments()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table *ProgramTable) DisplayProgramHeader() {
|
||||
|
||||
if len(table.dataProgram) == 0 {
|
||||
fmt.Println("Program header is empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
_, _ = fmt.Fprintln(w, "Nr\tType\tOffset\tVirtAddr\tPhysAddr\tFileSiz\tMemSiz\tFlg\tAlign")
|
||||
for i, p := range table.dataProgram {
|
||||
_, _ = fmt.Fprintf(w, "[%.2d]\t%s\t%.6x\t%.6x\t%.6x\t%.6x\t%.6x\t%.6x\t0x%x\n", i,
|
||||
ptStrings[p.elf64program.Type],
|
||||
p.elf64program.FileOffset, p.elf64program.VirtualAddress,
|
||||
p.elf64program.PhysicalAddress, p.elf64program.FileSize,
|
||||
p.elf64program.MemorySize, p.elf64program.Flags, p.elf64program.Align)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
||||
func (table *ProgramTable) DisplaySegmentSectionMapping() {
|
||||
|
||||
if len(table.dataProgram) == 0 {
|
||||
u.PrintWarning("Mapping between segments and sections is empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
for i, p := range table.dataProgram {
|
||||
_, _ = fmt.Fprintf(w, "[%.2d] ", i)
|
||||
for _, s := range p.sectionsPtr {
|
||||
_, _ = fmt.Fprintf(w, "%s ", s.Name)
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "\n")
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
138
srcs/binarytool/elf64core/elf_symbols.go
Normal file
138
srcs/binarytool/elf64core/elf_symbols.go
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
type SymbolsTables struct {
|
||||
nbEntries int
|
||||
name string
|
||||
dataSymbols []*dataSymbols
|
||||
}
|
||||
|
||||
type dataSymbols struct {
|
||||
elf64sym ELF64Symbols
|
||||
name string
|
||||
TypeSymbol byte
|
||||
}
|
||||
|
||||
type ELF64Symbols struct {
|
||||
Name uint32
|
||||
Info byte
|
||||
Other byte
|
||||
Shndx uint16
|
||||
Value uint64
|
||||
Size uint64
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) addSymbols(index int, symbols []ELF64Symbols) error {
|
||||
|
||||
var symbolsTables SymbolsTables
|
||||
symbolsTables.nbEntries = len(symbols)
|
||||
symbolsTables.name = elfFile.SectionsTable.DataSect[index].Name
|
||||
symbolsTables.dataSymbols = make([]*dataSymbols, symbolsTables.nbEntries)
|
||||
|
||||
var nameString string
|
||||
var err error
|
||||
for j, s := range symbols {
|
||||
|
||||
if s.Info == byte(elf.STT_SECTION) {
|
||||
// This is a section, save its name
|
||||
nameString = elfFile.SectionsTable.DataSect[s.Shndx].Name
|
||||
} else {
|
||||
nameString, err = elfFile.GetSectionName(s.Name, uint16(index+1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
symbolsTables.dataSymbols[j] = &dataSymbols{
|
||||
elf64sym: s,
|
||||
name: nameString,
|
||||
TypeSymbol: (s.Info) & 0xf,
|
||||
}
|
||||
}
|
||||
|
||||
elfFile.SymbolsTables = append(elfFile.SymbolsTables, symbolsTables)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) parseSymbolsTable(index int) error {
|
||||
|
||||
content, err := elfFile.GetSectionContent(uint16(index))
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading string table: %s", err)
|
||||
}
|
||||
|
||||
if content[len(content)-1] != 0 {
|
||||
return fmt.Errorf("the string table isn't null-terminated")
|
||||
}
|
||||
|
||||
symbols := make([]ELF64Symbols, len(content)/binary.Size(ELF64Symbols{}))
|
||||
if err := binary.Read(bytes.NewReader(content),
|
||||
elfFile.Endianness, symbols); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := elfFile.addSymbols(index, symbols); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table *SymbolsTables) displaySymbols(w *tabwriter.Writer) {
|
||||
_, _ = fmt.Fprintf(w, "\nSymbol table %s contains %d entries:\n\n",
|
||||
table.name, table.nbEntries)
|
||||
|
||||
_, _ = fmt.Fprintf(w, "\nNum:\tValue\tSize\tName\tType\n")
|
||||
|
||||
for i, s := range table.dataSymbols {
|
||||
_, _ = fmt.Fprintf(w, "%d:\t%.6x\t%d\t%s\t%s (%d)\n", i,
|
||||
s.elf64sym.Value, s.elf64sym.Size, s.name,
|
||||
sttStrings[s.TypeSymbol], s.TypeSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
func (elfFile *ELF64File) DisplaySymbolsTables() {
|
||||
|
||||
if len(elfFile.SymbolsTables) == 0 {
|
||||
u.PrintWarning("Symbols table(s) are empty")
|
||||
return
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
|
||||
for _, table := range elfFile.SymbolsTables {
|
||||
table.displaySymbols(w)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
||||
func (table *SymbolsTables) getSymbolName(index uint32) (string, error) {
|
||||
if table.dataSymbols == nil {
|
||||
return "", fmt.Errorf("symbol table is empty")
|
||||
}
|
||||
|
||||
if uint32(table.nbEntries) <= index {
|
||||
return "", fmt.Errorf("invalid index %d", index)
|
||||
}
|
||||
|
||||
return table.dataSymbols[index].name, nil
|
||||
}
|
32
srcs/binarytool/elf64core/elf_utils.go
Normal file
32
srcs/binarytool/elf64core/elf_utils.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package elf64core
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var mapList = map[string][]string{"libkvmplat.o": {"haltme"}}
|
||||
|
||||
func isInSlice(libName, symbol string) bool {
|
||||
|
||||
if strings.Contains(libName, string(os.PathSeparator)) {
|
||||
|
||||
libNameSplit := strings.Split(libName, string(os.PathSeparator))
|
||||
|
||||
if list, ok := mapList[libNameSplit[len(libNameSplit)-1]]; ok {
|
||||
for _, b := range list {
|
||||
if b == symbol {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
38
srcs/binarytool/helpers.go
Normal file
38
srcs/binarytool/helpers.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package binarytool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ReadJsonFile(path string) (*Unikernels, error) {
|
||||
jsonFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer jsonFile.Close()
|
||||
byteValue, _ := ioutil.ReadAll(jsonFile)
|
||||
unikernels := new(Unikernels)
|
||||
if err := json.Unmarshal(byteValue, unikernels); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unikernels, nil
|
||||
}
|
||||
|
||||
func stringInSlice(name string, plats []string) bool {
|
||||
for _, plat := range plats {
|
||||
if strings.Contains(name, plat) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
170
srcs/binarytool/run_binarytool.go
Normal file
170
srcs/binarytool/run_binarytool.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package binarytool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"tools/srcs/binarytool/elf64analyser"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
const diffPath = "diff" + u.SEP
|
||||
const pagesPath = "pages" + u.SEP
|
||||
|
||||
// RunBinaryAnalyser allows to run the binary analyser tool (which is out of the
|
||||
// UNICORE toolchain).
|
||||
func RunBinaryAnalyser(homeDir string) {
|
||||
|
||||
// Init and parse local arguments
|
||||
args := new(u.Arguments)
|
||||
p, err := args.InitArguments()
|
||||
if err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
if err := parseLocalArguments(p, args); err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
|
||||
// Check if a json file is used or if it is via command line
|
||||
var unikernels *Unikernels
|
||||
if len(*args.StringArg[listArg]) > 0 {
|
||||
unikernels = new(Unikernels)
|
||||
unikernels.Unikernel = make([]Unikernel, len(*args.StringArg[listArg]))
|
||||
mapping := false
|
||||
if *args.BoolArg[mappingArg] {
|
||||
mapping = true
|
||||
}
|
||||
list := strings.Split(*args.StringArg[listArg], ",")
|
||||
for i, arg := range list {
|
||||
unikernels.Unikernel[i] = Unikernel{
|
||||
BuildPath: arg,
|
||||
DisplayMapping: mapping,
|
||||
}
|
||||
}
|
||||
} else if len(*args.StringArg[filesArg]) > 0 {
|
||||
var err error
|
||||
unikernels, err = ReadJsonFile(*args.StringArg[filesArg])
|
||||
if err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
} else {
|
||||
u.PrintErr(errors.New("argument(s) must be provided"))
|
||||
}
|
||||
|
||||
var comparison elf64analyser.ComparisonElf
|
||||
comparison.GroupFileSegment = make([]*elf64analyser.ElfFileSegment, 0)
|
||||
|
||||
for i, uk := range unikernels.Unikernel {
|
||||
|
||||
uk.Analyser = new(elf64analyser.ElfAnalyser)
|
||||
if len(uk.BuildPath) > 0 {
|
||||
if uk.BuildPath[len(uk.BuildPath)-1] != os.PathSeparator {
|
||||
uk.BuildPath += u.SEP
|
||||
}
|
||||
if err := uk.GetFiles(); err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
|
||||
// Perform the inspection of micro-libs since we have the buildPath
|
||||
uk.Analyser.InspectMappingList(uk.ElfFile, uk.ListObjs)
|
||||
} else {
|
||||
if err := uk.GetKernel(); err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(uk.DisplayElfFile) > 0 {
|
||||
uk.DisplayElfInfo()
|
||||
}
|
||||
|
||||
if uk.DisplayMapping && len(uk.BuildPath) > 0 {
|
||||
fmt.Printf("==========[(%d): %s]==========\n", i, uk.BuildPath)
|
||||
uk.Analyser.DisplayMapping()
|
||||
fmt.Println("=====================================================")
|
||||
}
|
||||
|
||||
if uk.DisplayStatSize {
|
||||
uk.Analyser.DisplayStatSize(uk.ElfFile)
|
||||
}
|
||||
|
||||
if len(uk.DisplaySectionInfo) > 0 {
|
||||
uk.Analyser.DisplaySectionInfo(uk.ElfFile, uk.DisplaySectionInfo)
|
||||
}
|
||||
|
||||
if len(uk.FindSectionByAddress) > 0 {
|
||||
uk.Analyser.FindSectionByAddress(uk.ElfFile, uk.FindSectionByAddress)
|
||||
}
|
||||
|
||||
if uk.CompareGroup > 0 {
|
||||
|
||||
foundSection := false
|
||||
section := uk.SectionSplit
|
||||
for _, s := range uk.ElfFile.SectionsTable.DataSect {
|
||||
if s.Name == section {
|
||||
foundSection = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if foundSection {
|
||||
|
||||
path := homeDir + u.SEP + pagesPath
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
err := os.Mkdir(path, os.ModePerm)
|
||||
if err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
u.PrintInfo(fmt.Sprintf("Splitting %s section of %s into pages...", section, uk.ElfFile.Name))
|
||||
uk.Analyser.SplitIntoPagesBySection(uk.ElfFile, section)
|
||||
|
||||
out := path + section[1:] + u.SEP
|
||||
|
||||
if _, err := os.Stat(out); os.IsNotExist(err) {
|
||||
err := os.Mkdir(out, os.ModePerm)
|
||||
if err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := elf64analyser.SavePagesToFile(uk.Analyser.ElfPage, out+uk.ElfFile.Name+".txt", false); err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
u.PrintOk(fmt.Sprintf("Pages of section %s (%s) are saved into %s", section, uk.ElfFile.Name, out))
|
||||
|
||||
comparison.GroupFileSegment = append(comparison.GroupFileSegment,
|
||||
&elf64analyser.ElfFileSegment{Filename: uk.ElfFile.Name,
|
||||
NbPages: len(uk.Analyser.ElfPage), Pages: uk.Analyser.ElfPage})
|
||||
} else {
|
||||
u.PrintWarning("Section '" + section + "' is not found in the ELF file")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if len(comparison.GroupFileSegment) > 1 {
|
||||
|
||||
// Perform the comparison
|
||||
path := homeDir + u.SEP + diffPath
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
err := os.Mkdir(path, os.ModePerm)
|
||||
if err != nil {
|
||||
u.PrintErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
comparison.ComparePageTables()
|
||||
if err := comparison.DiffComparison(path); err != nil {
|
||||
u.PrintWarning(err)
|
||||
}
|
||||
comparison.DisplayComparison()
|
||||
}
|
||||
}
|
152
srcs/binarytool/unikernels.go
Normal file
152
srcs/binarytool/unikernels.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2019 The UNICORE Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file
|
||||
//
|
||||
// Author: Gaulthier Gain <gaulthier.gain@uliege.be>
|
||||
|
||||
package binarytool
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"tools/srcs/binarytool/elf64analyser"
|
||||
"tools/srcs/binarytool/elf64core"
|
||||
u "tools/srcs/common"
|
||||
)
|
||||
|
||||
const (
|
||||
makefile = "Makefile"
|
||||
config = "config"
|
||||
objExt = ".o"
|
||||
ldExt = ".ld.o"
|
||||
dbgExt = ".dbg"
|
||||
)
|
||||
|
||||
type Unikernels struct {
|
||||
Unikernel []Unikernel `json:"unikernels"`
|
||||
}
|
||||
|
||||
type Unikernel struct {
|
||||
BuildPath string `json:"buildPath"`
|
||||
Kernel string `json:"kernel"`
|
||||
SectionSplit string `json:"splitSection"`
|
||||
DisplayMapping bool `json:"displayMapping"`
|
||||
DisplayStatSize bool `json:"displayStatSize"`
|
||||
IgnoredPlats []string `json:"ignoredPlats"`
|
||||
DisplayElfFile []string `json:"displayElfFile"`
|
||||
DisplaySectionInfo []string `json:"displaySectionInfo"`
|
||||
FindSectionByAddress []string `json:"findSectionByAddress"`
|
||||
CompareGroup int `json:"compareGroup"`
|
||||
|
||||
ElfFile *elf64core.ELF64File
|
||||
ListObjs []*elf64core.ELF64File
|
||||
Analyser *elf64analyser.ElfAnalyser
|
||||
}
|
||||
|
||||
func parseFile(path, name string) (*elf64core.ELF64File, error) {
|
||||
var elfFile *elf64core.ELF64File
|
||||
elfFile = new(elf64core.ELF64File)
|
||||
if err := elfFile.ParseAll(path, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return elfFile, nil
|
||||
}
|
||||
|
||||
func (uk *Unikernel) GetKernel() error {
|
||||
var err error
|
||||
uk.ElfFile, err = parseFile("", uk.Kernel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uk *Unikernel) GetFiles() error {
|
||||
files, err := ioutil.ReadDir(uk.BuildPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uk.ListObjs = make([]*elf64core.ELF64File, 0)
|
||||
foundExec := false
|
||||
for _, f := range files {
|
||||
|
||||
if f.IsDir() || strings.Contains(f.Name(), makefile) ||
|
||||
strings.Contains(f.Name(), config) ||
|
||||
strings.Contains(f.Name(), ldExt) {
|
||||
continue
|
||||
}
|
||||
if filepath.Ext(strings.TrimSpace(f.Name())) == objExt &&
|
||||
!stringInSlice(f.Name(), uk.IgnoredPlats) {
|
||||
objFile, err := parseFile(uk.BuildPath, f.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uk.ListObjs = append(uk.ListObjs, objFile)
|
||||
} else if filepath.Ext(strings.TrimSpace(f.Name())) == dbgExt &&
|
||||
!stringInSlice(f.Name(), uk.IgnoredPlats) && !foundExec {
|
||||
|
||||
execName := f.Name()
|
||||
if len(uk.Kernel) > 0 {
|
||||
execName = uk.Kernel
|
||||
}
|
||||
uk.ElfFile, err = parseFile(uk.BuildPath, execName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
foundExec = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(uk.Kernel) > 0 {
|
||||
u.PrintInfo("Use specified ELF file: " + uk.ElfFile.Name)
|
||||
} else {
|
||||
u.PrintInfo("Use ELF file found in build folder: " + uk.ElfFile.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uk *Unikernel) displayAllElfInfo() {
|
||||
uk.ElfFile.Header.DisplayHeader()
|
||||
uk.ElfFile.SectionsTable.DisplaySections()
|
||||
uk.ElfFile.DisplayRelocationTables()
|
||||
uk.ElfFile.DisplaySymbolsTables()
|
||||
uk.ElfFile.DynamicTable.DisplayDynamicEntries()
|
||||
uk.ElfFile.SegmentsTable.DisplayProgramHeader()
|
||||
uk.ElfFile.SegmentsTable.DisplaySegmentSectionMapping()
|
||||
uk.ElfFile.DisplayNotes()
|
||||
uk.ElfFile.DisplayFunctionsTables(false)
|
||||
}
|
||||
|
||||
func (uk *Unikernel) DisplayElfInfo() {
|
||||
|
||||
if len(uk.DisplayElfFile) == 1 && uk.DisplayElfFile[0] == "all" {
|
||||
uk.displayAllElfInfo()
|
||||
} else {
|
||||
for _, d := range uk.DisplayElfFile {
|
||||
if d == "header" {
|
||||
uk.ElfFile.Header.DisplayHeader()
|
||||
} else if d == "sections" {
|
||||
uk.ElfFile.SectionsTable.DisplaySections()
|
||||
} else if d == "relocations" {
|
||||
uk.ElfFile.DisplayRelocationTables()
|
||||
} else if d == "symbols" {
|
||||
uk.ElfFile.DisplaySymbolsTables()
|
||||
} else if d == "dynamics" {
|
||||
uk.ElfFile.DynamicTable.DisplayDynamicEntries()
|
||||
} else if d == "segments" {
|
||||
uk.ElfFile.SegmentsTable.DisplayProgramHeader()
|
||||
} else if d == "mapping" {
|
||||
uk.ElfFile.SegmentsTable.DisplaySegmentSectionMapping()
|
||||
} else if d == "notes" {
|
||||
uk.ElfFile.DisplayNotes()
|
||||
} else if d == "functions" {
|
||||
uk.ElfFile.DisplayFunctionsTables(false)
|
||||
} else {
|
||||
u.PrintWarning("No display configuration found for argument: " + d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ const (
|
|||
BUILD = "build"
|
||||
VERIF = "verif"
|
||||
PERF = "perf"
|
||||
BINARY = "binary"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -82,6 +83,9 @@ func (*Arguments) ParseMainArguments(p *argparse.Parser, args *Arguments) error
|
|||
args.InitArgParse(p, args, BOOL, "", CRAWLER,
|
||||
&argparse.Options{Required: false, Default: false,
|
||||
Help: "Execute the crawler unikraft tool"})
|
||||
args.InitArgParse(p, args, BOOL, "", BINARY,
|
||||
&argparse.Options{Required: false, Default: false,
|
||||
Help: "Execute the binary analyser tool"})
|
||||
args.InitArgParse(p, args, BOOL, "", DEP,
|
||||
&argparse.Options{Required: false, Default: false,
|
||||
Help: "Execute only the dependency analysis tool"})
|
||||
|
@ -98,7 +102,7 @@ func (*Arguments) ParseMainArguments(p *argparse.Parser, args *Arguments) error
|
|||
// Parse only the two first arguments <program name, [tools]>
|
||||
if len(os.Args) > 2 {
|
||||
return ParserWrapper(p, os.Args[:2])
|
||||
}else{
|
||||
} else {
|
||||
p.Parse(os.Args)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ package main
|
|||
|
||||
import (
|
||||
"os/user"
|
||||
"tools/srcs/binarytool"
|
||||
"tools/srcs/buildtool"
|
||||
u "tools/srcs/common"
|
||||
"tools/srcs/crawlertool"
|
||||
|
@ -50,6 +51,12 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
if *args.BoolArg[u.BINARY] {
|
||||
u.PrintHeader1("(*) RUN BINARY UNIKRAFT ANALYSER")
|
||||
binarytool.RunBinaryAnalyser(usr.HomeDir)
|
||||
return
|
||||
}
|
||||
|
||||
if all || *args.BoolArg[u.DEP] {
|
||||
|
||||
// Initialize data
|
||||
|
|
Loading…
Add table
Reference in a new issue