gaulthiergain-tools/srcs/dependtool/static_analyser.go
Gaulthier Gain 1ea8dfbc9a remove user input from stdin
Signed-off-by: Gaulthier Gain <gaulthier.gain@uliege.be>
2021-03-02 12:26:50 +01:00

232 lines
6.3 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 dependtool
import (
"bufio"
"fmt"
"os"
"runtime"
"strings"
u "tools/srcs/common"
)
// ---------------------------------Gather Data---------------------------------
// gatherStaticSymbols gathers symbols of a given application.
//
// It returns an error if any, otherwise it returns nil.
func gatherStaticSymbols(programPath string, data *u.StaticData) error {
// Use 'readelf' to get symbols
if output, err := u.ExecuteCommand("readelf", []string{"-s",
programPath}); err != nil {
return err
} else {
parseReadELF(output, data)
}
return nil
}
// gatherStaticSymbols gathers system calls of a given application.
//
// It returns an error if any, otherwise it returns nil.
func gatherStaticSystemCalls(programPath, argument string, data *u.StaticData) error {
var args []string
if len(argument) > 0 {
args = []string{argument, programPath}
} else {
args = []string{programPath}
}
// Use 'nm' to get symbols and system calls
if output, err := u.ExecuteCommand("nm", args); err != nil {
return err
} else {
if strings.ToLower(runtime.GOOS) == "linux" {
parseNMLinux(output, data)
} else {
parseNMMac(output, data)
}
}
return nil
}
// gatherStaticSymbols gathers shared libs of a given application.
//
// It returns an error if any, otherwise it returns nil.
func gatherStaticSharedLibsLinux(programPath string, data *u.StaticData,
v bool) error {
// Use 'ldd' to get shared libraries
if output, err := u.ExecutePipeCommand("ldd " + programPath +
" | awk '/ => / { print $1,$3 }'"); err != nil {
return err
} else {
// Init SharedLibs
lddGlMap := make(map[string][]string)
_ = parseLDD(output, data.SharedLibs, lddGlMap, v)
}
return nil
}
func gatherStaticSharedLibsMac(programPath string, data *u.StaticData,
v bool) error {
// Use 'ldd' to get shared libraries
if output, err := u.ExecutePipeCommand("otool -L " + programPath +
" | awk '{ print $1 }'"); err != nil {
return err
} else {
// Init SharedLibs
lddGlMap := make(map[string][]string)
_ = parseLDDMac(output, data.SharedLibs, lddGlMap, v)
}
return nil
}
// gatherDependencies gathers dependencies of a given application.
//
// It returns an error if any, otherwise it returns nil.
func gatherDependencies(programName string, data *u.StaticData, v bool) error {
// Use 'apt-cache pkgnames' to get the name of the package
output, err := u.ExecuteCommand("apt-cache",
[]string{"pkgnames", programName})
if err != nil {
return err
}
// If the name of the package is know, execute apt-cache depends
if len(output) > 0 {
// Parse package name
packageName := parsePackagesName(output)
if len(packageName) > 0 {
return executeDependAptCache(packageName, data, v)
}
} else {
// Enter manually the name of the package
u.PrintWarning(programName + " not found in apt-cache")
var output string
for len(output) == 0 {
fmt.Print("Please enter manually the name of the package " +
"(empty string to exit): ")
scanner := bufio.NewScanner(os.Stdin)
if err := scanner.Err(); err != nil {
return err
}
if scanner.Scan() {
// Get the new package name
input := scanner.Text()
if input == "" {
break
}
output, err = u.ExecuteCommand("apt-cache",
[]string{"pkgnames", input})
if err != nil {
return err
}
}
}
if len(output) == 0 {
u.PrintWarning("Skip dependencies analysis from apt-cache depends")
} else {
packageName := parsePackagesName(output)
return executeDependAptCache(packageName, data, v)
}
}
return nil
}
// executeDependAptCache gathers dependencies by executing 'apt-cache depends'.
//
// It returns an error if any, otherwise it returns nil.
func executeDependAptCache(programName string, data *u.StaticData,
fullDeps bool) error {
// Use 'apt-cache depends' to get dependencies
if output, err := u.ExecutePipeCommand("apt-cache depends " +
programName + " | awk '/Depends/ { print $2 }'"); err != nil {
return err
} else {
// Init Dependencies (from apt cache depends)
data.Dependencies = make(map[string][]string)
dependenciesMap := make(map[string][]string)
printDep := make(map[string][]string)
_ = parseDependencies(output, data.Dependencies, dependenciesMap,
printDep, fullDeps, 0)
}
fmt.Println("----------------------------------------------")
return nil
}
// -------------------------------------Run-------------------------------------
// staticAnalyser runs the static analysis to get shared libraries,
// system calls and library calls of a given application.
//
func staticAnalyser(args u.Arguments, data *u.Data, programPath string) {
//programName := *args.StringArg[programArg]
fullDeps := *args.BoolArg[fullDepsArg]
staticData := &data.StaticData
// If the program is a binary, runs static analysis tools
if len(programPath) > 0 {
// Gather Data from binary file
// Init symbols members
staticData.Symbols = make(map[string]string)
staticData.SystemCalls = make(map[string]string)
staticData.SharedLibs = make(map[string][]string)
if strings.ToLower(runtime.GOOS) == "linux" {
u.PrintHeader2("(*) Gathering symbols from binary file")
if err := gatherStaticSymbols(programPath, staticData); err != nil {
u.PrintWarning(err)
}
}
u.PrintHeader2("(*) Gathering symbols & system calls from binary file")
if err := gatherStaticSystemCalls(programPath, "-D", staticData); err != nil {
// Check without the dynamic argument
if err := gatherStaticSystemCalls(programPath, "", staticData); err != nil {
u.PrintWarning(err)
}
}
u.PrintHeader2("(*) Gathering shared libraries from binary file")
if strings.ToLower(runtime.GOOS) == "linux" {
if err := gatherStaticSharedLibsLinux(programPath, staticData,
fullDeps); err != nil {
u.PrintWarning(err)
}
} else {
if err := gatherStaticSharedLibsMac(programPath, staticData,
fullDeps); err != nil {
u.PrintWarning(err)
}
}
}
/*if strings.ToLower(runtime.GOOS) == "linux" {
// Gather Data from apt-cache
u.PrintHeader2("(*) Gathering dependencies from apt-cache depends")
if err := gatherDependencies(programName, staticData, fullDeps); err != nil {
u.PrintWarning(err)
}
}*/
}