gaulthiergain-tools/srcs/binarytool/elf64core/elf_symbols.go
Gaulthier Gain f25637cdb7 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>
2021-01-30 12:37:27 +01:00

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
}