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>
138 lines
3.1 KiB
Go
138 lines
3.1 KiB
Go
// 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
|
|
}
|