This commit is contained in:
Ian A. Mason 2021-02-18 09:56:39 -08:00
commit 70a9d23b20
6 changed files with 164 additions and 22 deletions

View File

@ -30,4 +30,4 @@ lint:
golint ./shared/ ./tests/ ./cmd/...
clean:
rm -f data/hello data/hello.bc [td]*/.helloworld.c.o [td]*/.helloworld.c.o.bc
rm -f data/*hello data/*.bc [td]*/.*.c.o [td]*/*.o [td]*/.*.c.o.bc data/*.notanextensionthatwerecognize

View File

@ -250,7 +250,12 @@ such as *link time optimization* (indicated by the presence of compiler flag `-f
your build is unlikely to produce anything that `get-bc` will work on. This is to be
expected.
## Developer tools
Debugging usually boils down to looking in the logs, maybe adding a print statement or two.
There is an additional executable, not mentioned above, called `gparse` that gets installed
along with `gclang`, `gclang++`, `get-bc` and `gsanity-check`. `gparse` takes the command line
arguments to the compiler, and outputs how it parsed them. This can sometimes be helpful.
## License

View File

@ -153,6 +153,7 @@ func attachBitcodePathToObject(bcFile, objFile string) (success bool) {
default:
//OK we have to work harder here
ok, err := injectableViaFileType(objFile)
LogDebug("attachBitcodePathToObject: injectableViaFileType returned ok=%v err=%v", ok, err)
if ok {
success = injectPath(extension, bcFile, objFile)
return
@ -161,6 +162,7 @@ func attachBitcodePathToObject(bcFile, objFile string) (success bool) {
// OK we have to work EVEN harder here (the file utility is not installed - probably)
// N.B. this will probably fail if we are cross compiling.
ok, err = injectableViaDebug(objFile)
LogDebug("attachBitcodePathToObject: injectableViaDebug returned ok=%v err=%v", ok, err)
if ok {
success = injectPath(extension, bcFile, objFile)
return
@ -269,6 +271,7 @@ func compileTimeLinkFiles(compilerExecName string, pr ParserResult, objFiles []s
func buildObjectFile(compilerExecName string, pr ParserResult, srcFile string, objFile string) (success bool) {
args := pr.CompileArgs[:]
args = append(args, srcFile, "-c", "-o", objFile)
LogDebug("buildObjectFile: %v", args)
success, err := execCmd(compilerExecName, args, "")
if !success {
LogError("Failed to build object file for %s because: %v\n", srcFile, err)

View File

@ -42,7 +42,7 @@ import (
"strings"
)
//BinaryType is the 'intersection' of elf.Type and macho.Type and partitions
// BinaryType is the 'intersection' of elf.Type and macho.Type and partitions
// the binary world into categories we are most interested in. Missing is
// ARCHIVE but that is because it is not an elf format, so we cannot entirely
// eliminate the use of the 'file' utility (cf getFileType below).
@ -59,6 +59,49 @@ const (
BinaryShared BinaryType = 3
)
func (bt BinaryType) String() string {
switch bt {
case BinaryUnknown:
return "Unknown"
case BinaryObject:
return "Object"
case BinaryExecutable:
return "Executable"
case BinaryShared:
return "Library"
default:
return "Error"
}
}
// GetBinaryType gets the binary type of the given path
func GetBinaryType(path string) (bt BinaryType) {
bt = BinaryUnknown
plain := IsPlainFile(path)
if !plain {
return
}
// try the format that suits the platform first
operatingSys := runtime.GOOS
switch operatingSys {
case "linux", "freebsd":
bt, _ = ElfFileType(path)
case "darwin":
bt, _ = MachoFileType(path)
}
if bt != BinaryUnknown {
return
}
// try the other format instead
switch operatingSys {
case "linux", "freebsd":
bt, _ = MachoFileType(path)
case "darwin":
bt, _ = ElfFileType(path)
}
return
}
func elfType2BinaryType(et elf.Type) (bt BinaryType) {
bt = BinaryUnknown
switch et {
@ -95,21 +138,24 @@ func machoType2BinaryType(mt macho.Type) (bt BinaryType) {
return
}
// isPlainFile returns true if the file is stat-able (i.e. exists etc), and is not a directory, else it returns false.
func isPlainFile(objectFile string) (ok bool) {
// IsPlainFile returns true if the file is stat-able (i.e. exists etc), and is not a directory, else it returns false.
func IsPlainFile(objectFile string) (ok bool) {
info, err := os.Stat(objectFile)
if os.IsNotExist(err) || info.IsDir() {
if os.IsNotExist(err) {
return
}
if err != nil {
return
}
if info.IsDir() {
return
}
ok = true
return
}
func injectableViaFileType(objectFile string) (ok bool, err error) {
plain := isPlainFile(objectFile)
plain := IsPlainFile(objectFile)
if !plain {
return
}
@ -117,7 +163,7 @@ func injectableViaFileType(objectFile string) (ok bool, err error) {
if err != nil {
return
}
ok = (fileType == fileTypeELFOBJECT) || (fileType == fileTypeELFOBJECT)
ok = (fileType == fileTypeELFOBJECT) || (fileType == fileTypeMACHOBJECT)
return
}
@ -151,7 +197,7 @@ func MachoFileType(objectFile string) (code BinaryType, err error) {
//IsObjectFileForOS returns true if the given file is an object file for the given OS, using the debug/elf and debug/macho packages.
func IsObjectFileForOS(objectFile string, operatingSys string) (ok bool, err error) {
plain := isPlainFile(objectFile)
plain := IsPlainFile(objectFile)
if !plain {
return
}

View File

@ -177,8 +177,8 @@ func Parse(argList []string) ParserResult {
"--version": {0, pr.compileOnlyCallback},
"-v": {0, pr.compileOnlyCallback},
"-w": {0, pr.compileOnlyCallback},
"-W": {0, pr.compileOnlyCallback},
"-w": {0, pr.compileUnaryCallback},
"-W": {0, pr.compileUnaryCallback},
"-emit-llvm": {0, pr.emitLLVMCallback},
"-flto": {0, pr.linkTimeOptimizationCallback},

View File

@ -7,19 +7,23 @@ import (
"testing"
)
const (
DEBUG bool = false
)
func Test_basic_functionality(t *testing.T) {
args := []string{"../data/helloworld.c", "-o", "../data/hello"}
exitCode := shared.Compile(args, "clang")
if exitCode != 0 {
t.Errorf("Compile of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Compiled OK")
}
args = []string{"get-bc", "-v", "../data/hello"}
exitCode = shared.Extract(args)
if exitCode != 0 {
t.Errorf("Extraction of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Extraction OK")
}
}
@ -30,27 +34,27 @@ func Test_more_functionality(t *testing.T) {
exitCode := shared.Compile(args, "clang")
if exitCode != 0 {
t.Errorf("Compile of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Compiled OK")
}
ok, err := shared.IsObjectFileForOS(objectFile, runtime.GOOS)
if !ok {
t.Errorf("isObjectFileForOS(%v, %v) = %v (err = %v)\n", objectFile, runtime.GOOS, ok, err)
} else {
} else if DEBUG {
fmt.Printf("isObjectFileForOS(%v, %v) = %v\n", objectFile, runtime.GOOS, ok)
}
args = []string{objectFile, "-o", "../data/bhello"}
exitCode = shared.Compile(args, "clang")
if exitCode != 0 {
t.Errorf("Compile of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Compiled OK")
}
args = []string{"get-bc", "-v", "../data/bhello"}
exitCode = shared.Extract(args)
if exitCode != 0 {
t.Errorf("Extraction of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Extraction OK")
}
}
@ -64,39 +68,123 @@ func Test_obscure_functionality(t *testing.T) {
exitCode := shared.Compile(args, "clang")
if exitCode != 0 {
t.Errorf("Compile of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Compiled OK")
}
ok, err := shared.IsObjectFileForOS(sourceFile, opSys)
if ok {
t.Errorf("isObjectFileForOS(%v, %v) = %v\n", sourceFile, opSys, ok)
} else {
} else if DEBUG {
fmt.Printf("isObjectFileForOS(%v, %v) = %v (err = %v)\n", sourceFile, opSys, ok, err)
}
ok, err = shared.IsObjectFileForOS(objectFile, opSys)
if !ok {
t.Errorf("isObjectFileForOS(%v, %v) = %v (err = %v)\n", objectFile, opSys, ok, err)
} else {
} else if DEBUG {
fmt.Printf("isObjectFileForOS(%v, %v) = %v\n", objectFile, opSys, ok)
}
args = []string{objectFile, "-o", exeFile}
exitCode = shared.Compile(args, "clang")
if exitCode != 0 {
t.Errorf("Compile of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Compiled OK")
}
ok, err = shared.IsObjectFileForOS(exeFile, opSys)
if ok {
t.Errorf("isObjectFileForOS(%v, %v) = %v\n", exeFile, opSys, ok)
} else {
} else if DEBUG {
fmt.Printf("isObjectFileForOS(%v, %v) = %v (err = %v)\n", exeFile, opSys, ok, err)
}
args = []string{"get-bc", "-v", exeFile}
exitCode = shared.Extract(args)
if exitCode != 0 {
t.Errorf("Extraction of %v returned %v\n", args, exitCode)
} else {
} else if DEBUG {
fmt.Println("Extraction OK")
}
}
func Test_file_type(t *testing.T) {
fictionalFile := "HopefullyThereIsNotAFileCalledThisNearBy.txt"
dataDir := "../data"
sourceFile := "../data/helloworld.c"
objectFile := "../data/bhello.notanextensionthatwerecognize"
exeFile := "../data/bhello"
var binaryFileType shared.BinaryType
binaryFileType = shared.GetBinaryType(fictionalFile)
if binaryFileType != shared.BinaryUnknown {
t.Errorf("GetBinaryType(%v) = %v\n", fictionalFile, binaryFileType)
} else if DEBUG {
fmt.Printf("GetBinaryType(%v) = %v\n", fictionalFile, binaryFileType)
}
binaryFileType = shared.GetBinaryType(dataDir)
if binaryFileType != shared.BinaryUnknown {
t.Errorf("GetBinaryType(%v) = %v\n", dataDir, binaryFileType)
} else if DEBUG {
fmt.Printf("GetBinaryType(%v) = %v\n", dataDir, binaryFileType)
}
binaryFileType = shared.GetBinaryType(sourceFile)
if binaryFileType != shared.BinaryUnknown {
t.Errorf("GetBinaryType(%v) = %v\n", sourceFile, binaryFileType)
} else if DEBUG {
fmt.Printf("GetBinaryType(%v) = %v\n", sourceFile, binaryFileType)
}
binaryFileType = shared.GetBinaryType(objectFile)
if binaryFileType != shared.BinaryObject {
t.Errorf("GetBinaryType(%v) = %v\n", objectFile, binaryFileType)
} else if DEBUG {
fmt.Printf("GetBinaryType(%v) = %v\n", objectFile, binaryFileType)
}
binaryFileType = shared.GetBinaryType(exeFile)
if binaryFileType != shared.BinaryExecutable {
t.Errorf("GetBinaryType(%v) = %v\n", exeFile, binaryFileType)
} else if DEBUG {
fmt.Printf("GetBinaryType(%v) = %v\n", exeFile, binaryFileType)
}
var plain bool
plain = shared.IsPlainFile(fictionalFile)
if plain {
t.Errorf("shared.IsPlainFile(%v) returned %v\n", fictionalFile, plain)
} else if DEBUG {
fmt.Printf("shared.IsPlainFile(%v) returned %v\n", fictionalFile, plain)
}
plain = shared.IsPlainFile(dataDir)
if plain {
t.Errorf("shared.IsPlainFile(%v) returned %v\n", dataDir, plain)
} else if DEBUG {
fmt.Printf("shared.IsPlainFile(%v) returned %v\n", dataDir, plain)
}
plain = shared.IsPlainFile(sourceFile)
if !plain {
t.Errorf("shared.IsPlainFile(%v) returned %v\n", sourceFile, plain)
} else if DEBUG {
fmt.Printf("shared.IsPlainFile(%v) returned %v\n", sourceFile, plain)
}
plain = shared.IsPlainFile(objectFile)
if !plain {
t.Errorf("shared.IsPlainFile(%v) returned %v\n", objectFile, plain)
} else if DEBUG {
fmt.Printf("shared.IsPlainFile(%v) returned %v\n", objectFile, plain)
}
plain = shared.IsPlainFile(exeFile)
if !plain {
t.Errorf("shared.IsPlainFile(%v) returned %v\n", exeFile, plain)
} else if DEBUG {
fmt.Printf("shared.IsPlainFile(%v) returned %v\n", exeFile, plain)
}
}