Merge changes I6f7d40b7,I25654032 am: 83a495830b

am: dfcdeec8b2

Change-Id: Ida245504ae6e7074e800ce809fae12e1d6957ee3
This commit is contained in:
Colin Cross 2018-03-03 03:48:25 +00:00 committed by android-build-merger
commit 4335ca3cd6
22 changed files with 3430 additions and 164 deletions

View file

@ -323,6 +323,12 @@ func (binary *binaryDecorator) link(ctx ModuleContext,
flagsToBuilderFlags(flags), afterPrefixSymbols)
}
if Bool(binary.baseLinker.Properties.Use_version_lib) && ctx.Host() {
versionedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unversioned", fileName)
binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
}
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
linkerDeps = append(linkerDeps, objs.tidyFiles...)

View file

@ -0,0 +1,12 @@
cc_library_static {
name: "libbuildversion",
host_supported: true,
srcs: ["libbuildversion.cpp"],
export_include_dirs: ["include"],
cflags: ["-fvisibility=hidden"],
target: {
windows: {
enabled: true,
},
},
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BUILD_VERSION_H
#define BUILD_VERSION_H
#include <string>
namespace android {
namespace build {
std::string GetBuildNumber();
} // namespace build
} // namespace android
#endif // BUILD_VERSION_H

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <build/version.h>
#ifdef __ANDROID__
#include <sys/system_properties.h>
#endif
namespace android {
namespace build {
#ifdef __ANDROID__
std::string GetBuildNumber() {
const prop_info* pi = __system_property_find("ro.build.version.incremental");
if (pi == nullptr) return "";
std::string property_value;
__system_property_read_callback(pi,
[](void* cookie, const char*, const char* value, unsigned) {
auto property_value = reinterpret_cast<std::string*>(cookie);
*property_value = value;
},
&property_value);
return property_value;
}
#else
extern "C" {
char soong_build_number[128] = "SOONG BUILD NUMBER PLACEHOLDER";
}
std::string GetBuildNumber() {
return soong_build_number;
}
#endif
} // namespace build
} // namespace android

View file

@ -0,0 +1,35 @@
cc_defaults {
name: "build_version_test_defaults",
use_version_lib: true,
host_supported: true,
target: {
windows: {
enabled: true,
},
},
}
cc_test {
name: "build_version_test",
defaults: ["build_version_test_defaults"],
srcs: ["build_version_test.cpp"],
target: {
android: {
shared_libs: ["libbuild_version_test"],
},
not_windows: {
shared_libs: ["libbuild_version_test"],
},
},
}
cc_library_shared {
name: "libbuild_version_test",
defaults: ["build_version_test_defaults"],
srcs: ["build_version_test_lib.cpp"],
target: {
windows: {
enabled: false,
},
},
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <gtest/gtest.h>
#include <build/version.h>
#include "build_version_test_lib.h"
TEST(BuildNumber, binary) {
printf("binary version: %s\n", android::build::GetBuildNumber().c_str());
EXPECT_NE(android::build::GetBuildNumber(), "SOONG BUILD NUMBER PLACEHOLDER");
}
// symbol_inject doesn't support dlls
#ifndef __WIN32__
TEST(BuildNumber, library) {
printf("shared library version: %s\n", LibGetBuildNumber().c_str());
EXPECT_NE(LibGetBuildNumber(), "SOONG BUILD NUMBER PLACEHOLDER");
}
#endif

View file

@ -0,0 +1,23 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <build/version.h>
#include "build_version_test_lib.h"
std::string LibGetBuildNumber() {
return android::build::GetBuildNumber();
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BUILD_VERSION_TEST_LIB_H_
#define BUILD_VERSION_TEST_LIB_H_
#include <string>
std::string __attribute__((visibility("default"))) LibGetBuildNumber();
#endif // BUILD_VERSION_TEST_LIB_H_

View file

@ -492,10 +492,16 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext,
library.objects = deps.WholeStaticLibObjs.Copy()
library.objects = library.objects.Append(objs)
outputFile := android.PathForModuleOut(ctx,
ctx.ModuleName()+library.MutatedProperties.VariantName+staticLibraryExtension)
fileName := ctx.ModuleName() + library.MutatedProperties.VariantName + staticLibraryExtension
outputFile := android.PathForModuleOut(ctx, fileName)
builderFlags := flagsToBuilderFlags(flags)
if Bool(library.baseLinker.Properties.Use_version_lib) && ctx.Host() {
versionedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unversioned", fileName)
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
}
TransformObjToStaticLib(ctx, library.objects.objFiles, builderFlags, outputFile, objs.tidyFiles)
library.coverageOutputFile = TransformCoverageFilesToLib(ctx, library.objects, builderFlags,
@ -585,6 +591,12 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
library.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
}
if Bool(library.baseLinker.Properties.Use_version_lib) && ctx.Host() {
versionedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unversioned", fileName)
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
}
sharedLibs := deps.SharedLibs
sharedLibs = append(sharedLibs, deps.LateSharedLibs...)

View file

@ -18,6 +18,7 @@ import (
"android/soong/android"
"fmt"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@ -95,6 +96,9 @@ type BaseLinkerProperties struct {
Exclude_static_libs []string
}
}
// make android::build:GetBuildNumber() available containing the build ID.
Use_version_lib *bool `android:"arch_variant"`
}
func NewBaseLinker() *baseLinker {
@ -136,6 +140,10 @@ func (linker *baseLinker) linkerDeps(ctx BaseModuleContext, deps Deps) Deps {
deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...)
deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...)
if Bool(linker.Properties.Use_version_lib) {
deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion")
}
if ctx.useVndk() {
deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor.Exclude_shared_libs)
deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor.Exclude_shared_libs)
@ -278,3 +286,31 @@ func (linker *baseLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
panic(fmt.Errorf("baseLinker doesn't know how to link"))
}
// Injecting version symbols
// Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step
// after linking that injects a constant placeholder with the current version number.
func init() {
pctx.HostBinToolVariable("symbolInjectCmd", "symbol_inject")
}
var injectVersionSymbol = pctx.AndroidStaticRule("injectVersionSymbol",
blueprint.RuleParams{
Command: "$symbolInjectCmd -i $in -o $out -s soong_build_number " +
"-from 'SOONG BUILD NUMBER PLACEHOLDER' -v $buildNumberFromFile",
CommandDeps: []string{"$symbolInjectCmd"},
},
"buildNumberFromFile")
func (linker *baseLinker) injectVersionSymbol(ctx ModuleContext, in android.Path, out android.WritablePath) {
ctx.Build(pctx, android.BuildParams{
Rule: injectVersionSymbol,
Description: "inject version symbol",
Input: in,
Output: out,
Args: map[string]string{
"buildNumberFromFile": ctx.Config().BuildNumberFromFile(),
},
})
}

View file

@ -20,4 +20,13 @@ blueprint_go_binary {
"macho.go",
"pe.go",
],
testSrcs: [
"elf_symboldata_test.go",
"elf_test.go",
"macho_symboldata_test.go",
"macho_test.go",
"pe_symboldata_test.go",
"pe_test.go",
"symbol_inject_test.go",
],
}

View file

@ -20,57 +20,141 @@ import (
"io"
)
func findElfSymbol(r io.ReaderAt, symbol string) (uint64, uint64, error) {
type mockableElfFile interface {
Symbols() ([]elf.Symbol, error)
Sections() []elf.SectionHeader
Type() elf.Type
}
var _ mockableElfFile = elfFileWrapper{}
type elfFileWrapper struct {
*elf.File
}
func (f elfFileWrapper) Sections() []elf.SectionHeader {
ret := make([]elf.SectionHeader, len(f.File.Sections))
for i, section := range f.File.Sections {
ret[i] = section.SectionHeader
}
return ret
}
func (f elfFileWrapper) Type() elf.Type {
return f.File.Type
}
type mockElfFile struct {
symbols []elf.Symbol
sections []elf.SectionHeader
t elf.Type
}
func (f mockElfFile) Sections() []elf.SectionHeader { return f.sections }
func (f mockElfFile) Symbols() ([]elf.Symbol, error) { return f.symbols, nil }
func (f mockElfFile) Type() elf.Type { return f.t }
func elfSymbolsFromFile(r io.ReaderAt) (*File, error) {
elfFile, err := elf.NewFile(r)
if err != nil {
return maxUint64, maxUint64, cantParseError{err}
return nil, cantParseError{err}
}
return extractElfSymbols(elfFileWrapper{elfFile})
}
func extractElfSymbols(elfFile mockableElfFile) (*File, error) {
symbols, err := elfFile.Symbols()
if err != nil {
return nil, err
}
file := &File{}
for _, section := range elfFile.Sections() {
file.Sections = append(file.Sections, &Section{
Name: section.Name,
Addr: section.Addr,
Offset: section.Offset,
Size: section.Size,
})
}
_ = elf.Section{}
for _, symbol := range symbols {
if elf.ST_TYPE(symbol.Info) != elf.STT_OBJECT {
continue
}
if symbol.Section == elf.SHN_UNDEF || symbol.Section >= elf.SHN_LORESERVE {
continue
}
if int(symbol.Section) >= len(file.Sections) {
return nil, fmt.Errorf("invalid section index %d", symbol.Section)
}
section := file.Sections[symbol.Section]
var addr uint64
switch elfFile.Type() {
case elf.ET_REL:
// "In relocatable files, st_value holds a section offset for a defined symbol.
// That is, st_value is an offset from the beginning of the section that st_shndx identifies."
addr = symbol.Value
case elf.ET_EXEC, elf.ET_DYN:
// "In executable and shared object files, st_value holds a virtual address. To make these
// files symbols more useful for the dynamic linker, the section offset (file interpretation)
// gives way to a virtual address (memory interpretation) for which the section number is
// irrelevant."
if symbol.Value < section.Addr {
return nil, fmt.Errorf("symbol starts before the start of its section")
}
addr = symbol.Value - section.Addr
if addr+symbol.Size > section.Size {
return nil, fmt.Errorf("symbol extends past the end of its section")
}
default:
return nil, fmt.Errorf("unsupported elf file type %d", elfFile.Type())
}
file.Symbols = append(file.Symbols, &Symbol{
Name: symbol.Name,
Addr: addr,
Size: symbol.Size,
Section: section,
})
}
return file, nil
}
func dumpElfSymbols(r io.ReaderAt) error {
elfFile, err := elf.NewFile(r)
if err != nil {
return cantParseError{err}
}
symbols, err := elfFile.Symbols()
if err != nil {
return maxUint64, maxUint64, err
return err
}
for _, s := range symbols {
if elf.ST_TYPE(s.Info) != elf.STT_OBJECT {
continue
}
if s.Name == symbol {
offset, err := calculateElfSymbolOffset(elfFile, s)
if err != nil {
return maxUint64, maxUint64, err
}
return offset, s.Size, nil
}
}
fmt.Println("mockElfFile{")
fmt.Printf("\tt: %#v,\n", elfFile.Type)
return maxUint64, maxUint64, fmt.Errorf("symbol not found")
}
func calculateElfSymbolOffset(file *elf.File, symbol elf.Symbol) (uint64, error) {
if symbol.Section == elf.SHN_UNDEF || int(symbol.Section) >= len(file.Sections) {
return maxUint64, fmt.Errorf("invalid section index %d", symbol.Section)
}
section := file.Sections[symbol.Section]
switch file.Type {
case elf.ET_REL:
// "In relocatable files, st_value holds a section offset for a defined symbol.
// That is, st_value is an offset from the beginning of the section that st_shndx identifies."
return section.Offset + symbol.Value, nil
case elf.ET_EXEC, elf.ET_DYN:
// "In executable and shared object files, st_value holds a virtual address. To make these
// files symbols more useful for the dynamic linker, the section offset (file interpretation)
// gives way to a virtual address (memory interpretation) for which the section number is
// irrelevant."
if symbol.Value < section.Addr {
return maxUint64, fmt.Errorf("symbol starts before the start of its section")
}
section_offset := symbol.Value - section.Addr
if section_offset+symbol.Size > section.Size {
return maxUint64, fmt.Errorf("symbol extends past the end of its section")
}
return section.Offset + section_offset, nil
default:
return maxUint64, fmt.Errorf("unsupported elf file type %d", file.Type)
}
fmt.Println("\tsections: []elf.SectionHeader{")
for _, section := range elfFile.Sections {
fmt.Printf("\t\t%#v,\n", section.SectionHeader)
}
fmt.Println("\t},")
fmt.Println("\tsymbols: []elf.Symbol{")
for _, symbol := range symbols {
fmt.Printf("\t\t%#v,\n", symbol)
}
fmt.Println("\t},")
fmt.Println("}")
return nil
}

View file

@ -0,0 +1,241 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import "debug/elf"
/* Generated from: clang -o a.out test.c
#include <unistd.h>
char soong_build_number[128] = "PLACEHOLDER";
int main() {
write(STDOUT_FILENO, soong_build_number, sizeof(soong_build_number));
}
*/
var elfSymbolTable1 = &mockElfFile{
t: elf.ET_EXEC,
sections: []elf.SectionHeader{
elf.SectionHeader{Name: "", Type: elf.SHT_NULL, Flags: 0x0, Addr: 0x0, Offset: 0x0, Size: 0x0, Link: 0x0, Info: 0x0, Addralign: 0x0, Entsize: 0x0, FileSize: 0x0},
elf.SectionHeader{Name: ".interp", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC, Addr: 0x400238, Offset: 0x238, Size: 0x1c, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x1c},
elf.SectionHeader{Name: ".note.ABI-tag", Type: elf.SHT_NOTE, Flags: elf.SHF_ALLOC, Addr: 0x400254, Offset: 0x254, Size: 0x20, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x20},
elf.SectionHeader{Name: ".hash", Type: elf.SHT_HASH, Flags: elf.SHF_ALLOC, Addr: 0x400278, Offset: 0x278, Size: 0x24, Link: 0x4, Info: 0x0, Addralign: 0x8, Entsize: 0x4, FileSize: 0x24},
elf.SectionHeader{Name: ".dynsym", Type: elf.SHT_DYNSYM, Flags: elf.SHF_ALLOC, Addr: 0x4002a0, Offset: 0x2a0, Size: 0x60, Link: 0x5, Info: 0x1, Addralign: 0x8, Entsize: 0x18, FileSize: 0x60},
elf.SectionHeader{Name: ".dynstr", Type: elf.SHT_STRTAB, Flags: elf.SHF_ALLOC, Addr: 0x400300, Offset: 0x300, Size: 0x3e, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x3e},
elf.SectionHeader{Name: ".gnu.version", Type: elf.SHT_GNU_VERSYM, Flags: elf.SHF_ALLOC, Addr: 0x40033e, Offset: 0x33e, Size: 0x8, Link: 0x4, Info: 0x0, Addralign: 0x2, Entsize: 0x2, FileSize: 0x8},
elf.SectionHeader{Name: ".gnu.version_r", Type: elf.SHT_GNU_VERNEED, Flags: elf.SHF_ALLOC, Addr: 0x400348, Offset: 0x348, Size: 0x20, Link: 0x5, Info: 0x1, Addralign: 0x8, Entsize: 0x0, FileSize: 0x20},
elf.SectionHeader{Name: ".rela.dyn", Type: elf.SHT_RELA, Flags: elf.SHF_ALLOC, Addr: 0x400368, Offset: 0x368, Size: 0x30, Link: 0x4, Info: 0x0, Addralign: 0x8, Entsize: 0x18, FileSize: 0x30},
elf.SectionHeader{Name: ".rela.plt", Type: elf.SHT_RELA, Flags: elf.SHF_ALLOC + elf.SHF_INFO_LINK, Addr: 0x400398, Offset: 0x398, Size: 0x18, Link: 0x4, Info: 0x16, Addralign: 0x8, Entsize: 0x18, FileSize: 0x18},
elf.SectionHeader{Name: ".init", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4003b0, Offset: 0x3b0, Size: 0x17, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x17},
elf.SectionHeader{Name: ".plt", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4003d0, Offset: 0x3d0, Size: 0x20, Link: 0x0, Info: 0x0, Addralign: 0x10, Entsize: 0x10, FileSize: 0x20},
elf.SectionHeader{Name: ".text", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4003f0, Offset: 0x3f0, Size: 0x1b2, Link: 0x0, Info: 0x0, Addralign: 0x10, Entsize: 0x0, FileSize: 0x1b2},
elf.SectionHeader{Name: ".fini", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4005a4, Offset: 0x5a4, Size: 0x9, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x9},
elf.SectionHeader{Name: ".rodata", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_MERGE, Addr: 0x4005b0, Offset: 0x5b0, Size: 0x4, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x4, FileSize: 0x4},
elf.SectionHeader{Name: ".eh_frame_hdr", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC, Addr: 0x4005b4, Offset: 0x5b4, Size: 0x34, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x34},
elf.SectionHeader{Name: ".eh_frame", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC, Addr: 0x4005e8, Offset: 0x5e8, Size: 0xf0, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x0, FileSize: 0xf0},
elf.SectionHeader{Name: ".init_array", Type: elf.SHT_INIT_ARRAY, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e08, Offset: 0xe08, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x8},
elf.SectionHeader{Name: ".fini_array", Type: elf.SHT_FINI_ARRAY, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e10, Offset: 0xe10, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x8},
elf.SectionHeader{Name: ".jcr", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e18, Offset: 0xe18, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x0, FileSize: 0x8},
elf.SectionHeader{Name: ".dynamic", Type: elf.SHT_DYNAMIC, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e20, Offset: 0xe20, Size: 0x1d0, Link: 0x5, Info: 0x0, Addralign: 0x8, Entsize: 0x10, FileSize: 0x1d0},
elf.SectionHeader{Name: ".got", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600ff0, Offset: 0xff0, Size: 0x10, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x10},
elf.SectionHeader{Name: ".got.plt", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x601000, Offset: 0x1000, Size: 0x20, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x20},
elf.SectionHeader{Name: ".data", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x601020, Offset: 0x1020, Size: 0x90, Link: 0x0, Info: 0x0, Addralign: 0x10, Entsize: 0x0, FileSize: 0x90},
elf.SectionHeader{Name: ".bss", Type: elf.SHT_NOBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x6010b0, Offset: 0x10b0, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x8},
elf.SectionHeader{Name: ".comment", Type: elf.SHT_PROGBITS, Flags: elf.SHF_MERGE + elf.SHF_STRINGS, Addr: 0x0, Offset: 0x10b0, Size: 0x56, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x1, FileSize: 0x56},
elf.SectionHeader{Name: ".symtab", Type: elf.SHT_SYMTAB, Flags: 0x0, Addr: 0x0, Offset: 0x1108, Size: 0x5e8, Link: 0x1b, Info: 0x2d, Addralign: 0x8, Entsize: 0x18, FileSize: 0x5e8},
elf.SectionHeader{Name: ".strtab", Type: elf.SHT_STRTAB, Flags: 0x0, Addr: 0x0, Offset: 0x16f0, Size: 0x1dd, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x1dd},
elf.SectionHeader{Name: ".shstrtab", Type: elf.SHT_STRTAB, Flags: 0x0, Addr: 0x0, Offset: 0x18cd, Size: 0xf1, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0xf1},
},
symbols: []elf.Symbol{
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 1, Value: 0x400238, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 2, Value: 0x400254, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 3, Value: 0x400278, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 4, Value: 0x4002a0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 5, Value: 0x400300, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 6, Value: 0x40033e, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 7, Value: 0x400348, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 8, Value: 0x400368, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 9, Value: 0x400398, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 10, Value: 0x4003b0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 11, Value: 0x4003d0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4003f0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 13, Value: 0x4005a4, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 14, Value: 0x4005b0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 15, Value: 0x4005b4, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 16, Value: 0x4005e8, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e08, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 18, Value: 0x600e10, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 19, Value: 0x600e18, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 20, Value: 0x600e20, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 21, Value: 0x600ff0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 22, Value: 0x601000, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601020, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x6010b0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 25, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "crtstuff.c", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__JCR_LIST__", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 19, Value: 0x600e18, Size: 0x0},
elf.Symbol{Name: "deregister_tm_clones", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x400420, Size: 0x0},
elf.Symbol{Name: "register_tm_clones", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x400460, Size: 0x0},
elf.Symbol{Name: "__do_global_dtors_aux", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4004a0, Size: 0x0},
elf.Symbol{Name: "completed.6963", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x6010b0, Size: 0x1},
elf.Symbol{Name: "__do_global_dtors_aux_fini_array_entry", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 18, Value: 0x600e10, Size: 0x0},
elf.Symbol{Name: "frame_dummy", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4004c0, Size: 0x0},
elf.Symbol{Name: "__frame_dummy_init_array_entry", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e08, Size: 0x0},
elf.Symbol{Name: "test.c", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "crtstuff.c", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__FRAME_END__", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 16, Value: 0x4006d4, Size: 0x0},
elf.Symbol{Name: "__JCR_END__", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 19, Value: 0x600e18, Size: 0x0},
elf.Symbol{Name: "", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__init_array_end", Info: 0x0, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e10, Size: 0x0},
elf.Symbol{Name: "_DYNAMIC", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 20, Value: 0x600e20, Size: 0x0},
elf.Symbol{Name: "__init_array_start", Info: 0x0, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e08, Size: 0x0},
elf.Symbol{Name: "__GNU_EH_FRAME_HDR", Info: 0x0, Other: 0x0, Section: elf.SHN_UNDEF + 15, Value: 0x4005b4, Size: 0x0},
elf.Symbol{Name: "_GLOBAL_OFFSET_TABLE_", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 22, Value: 0x601000, Size: 0x0},
elf.Symbol{Name: "__libc_csu_fini", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4005a0, Size: 0x2},
elf.Symbol{Name: "soong_build_number", Info: 0x11, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601030, Size: 0x80},
elf.Symbol{Name: "data_start", Info: 0x20, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601020, Size: 0x0},
elf.Symbol{Name: "write@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "_edata", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x6010b0, Size: 0x0},
elf.Symbol{Name: "_fini", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 13, Value: 0x4005a4, Size: 0x0},
elf.Symbol{Name: "__libc_start_main@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__data_start", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601020, Size: 0x0},
elf.Symbol{Name: "__gmon_start__", Info: 0x20, Other: 0x0, Section: elf.SHN_UNDEF, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__dso_handle", Info: 0x11, Other: 0x2, Section: elf.SHN_UNDEF + 23, Value: 0x601028, Size: 0x0},
elf.Symbol{Name: "_IO_stdin_used", Info: 0x11, Other: 0x0, Section: elf.SHN_UNDEF + 14, Value: 0x4005b0, Size: 0x4},
elf.Symbol{Name: "__libc_csu_init", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x400530, Size: 0x65},
elf.Symbol{Name: "_end", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x6010b8, Size: 0x0},
elf.Symbol{Name: "_start", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4003f0, Size: 0x2b},
elf.Symbol{Name: "__bss_start", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x6010b0, Size: 0x0},
elf.Symbol{Name: "main", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4004f0, Size: 0x31},
elf.Symbol{Name: "__TMC_END__", Info: 0x11, Other: 0x2, Section: elf.SHN_UNDEF + 23, Value: 0x6010b0, Size: 0x0},
elf.Symbol{Name: "_init", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 10, Value: 0x4003b0, Size: 0x0},
},
}
/* Generated from: clang -o a.out test2.c
#include <unistd.h>
char symbol1[128] = "PLACEHOLDER1";
char symbol2[128] = "PLACEHOLDER2";
int main() {
write(STDOUT_FILENO, symbol1, sizeof(symbol1));
write(STDOUT_FILENO, symbol2, sizeof(symbol2));
}
*/
var elfSymbolTable2 = &mockElfFile{
t: elf.ET_EXEC,
sections: []elf.SectionHeader{
elf.SectionHeader{Name: "", Type: elf.SHT_NULL, Flags: 0x0, Addr: 0x0, Offset: 0x0, Size: 0x0, Link: 0x0, Info: 0x0, Addralign: 0x0, Entsize: 0x0, FileSize: 0x0},
elf.SectionHeader{Name: ".interp", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC, Addr: 0x400238, Offset: 0x238, Size: 0x1c, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x1c},
elf.SectionHeader{Name: ".note.ABI-tag", Type: elf.SHT_NOTE, Flags: elf.SHF_ALLOC, Addr: 0x400254, Offset: 0x254, Size: 0x20, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x20},
elf.SectionHeader{Name: ".hash", Type: elf.SHT_HASH, Flags: elf.SHF_ALLOC, Addr: 0x400278, Offset: 0x278, Size: 0x24, Link: 0x4, Info: 0x0, Addralign: 0x8, Entsize: 0x4, FileSize: 0x24},
elf.SectionHeader{Name: ".dynsym", Type: elf.SHT_DYNSYM, Flags: elf.SHF_ALLOC, Addr: 0x4002a0, Offset: 0x2a0, Size: 0x60, Link: 0x5, Info: 0x1, Addralign: 0x8, Entsize: 0x18, FileSize: 0x60},
elf.SectionHeader{Name: ".dynstr", Type: elf.SHT_STRTAB, Flags: elf.SHF_ALLOC, Addr: 0x400300, Offset: 0x300, Size: 0x3e, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x3e},
elf.SectionHeader{Name: ".gnu.version", Type: elf.SHT_GNU_VERSYM, Flags: elf.SHF_ALLOC, Addr: 0x40033e, Offset: 0x33e, Size: 0x8, Link: 0x4, Info: 0x0, Addralign: 0x2, Entsize: 0x2, FileSize: 0x8},
elf.SectionHeader{Name: ".gnu.version_r", Type: elf.SHT_GNU_VERNEED, Flags: elf.SHF_ALLOC, Addr: 0x400348, Offset: 0x348, Size: 0x20, Link: 0x5, Info: 0x1, Addralign: 0x8, Entsize: 0x0, FileSize: 0x20},
elf.SectionHeader{Name: ".rela.dyn", Type: elf.SHT_RELA, Flags: elf.SHF_ALLOC, Addr: 0x400368, Offset: 0x368, Size: 0x30, Link: 0x4, Info: 0x0, Addralign: 0x8, Entsize: 0x18, FileSize: 0x30},
elf.SectionHeader{Name: ".rela.plt", Type: elf.SHT_RELA, Flags: elf.SHF_ALLOC + elf.SHF_INFO_LINK, Addr: 0x400398, Offset: 0x398, Size: 0x18, Link: 0x4, Info: 0x16, Addralign: 0x8, Entsize: 0x18, FileSize: 0x18},
elf.SectionHeader{Name: ".init", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4003b0, Offset: 0x3b0, Size: 0x17, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x17},
elf.SectionHeader{Name: ".plt", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4003d0, Offset: 0x3d0, Size: 0x20, Link: 0x0, Info: 0x0, Addralign: 0x10, Entsize: 0x10, FileSize: 0x20},
elf.SectionHeader{Name: ".text", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4003f0, Offset: 0x3f0, Size: 0x1c2, Link: 0x0, Info: 0x0, Addralign: 0x10, Entsize: 0x0, FileSize: 0x1c2},
elf.SectionHeader{Name: ".fini", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_EXECINSTR, Addr: 0x4005b4, Offset: 0x5b4, Size: 0x9, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x9},
elf.SectionHeader{Name: ".rodata", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC + elf.SHF_MERGE, Addr: 0x4005c0, Offset: 0x5c0, Size: 0x4, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x4, FileSize: 0x4},
elf.SectionHeader{Name: ".eh_frame_hdr", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC, Addr: 0x4005c4, Offset: 0x5c4, Size: 0x34, Link: 0x0, Info: 0x0, Addralign: 0x4, Entsize: 0x0, FileSize: 0x34},
elf.SectionHeader{Name: ".eh_frame", Type: elf.SHT_PROGBITS, Flags: elf.SHF_ALLOC, Addr: 0x4005f8, Offset: 0x5f8, Size: 0xf0, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x0, FileSize: 0xf0},
elf.SectionHeader{Name: ".init_array", Type: elf.SHT_INIT_ARRAY, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e08, Offset: 0xe08, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x8},
elf.SectionHeader{Name: ".fini_array", Type: elf.SHT_FINI_ARRAY, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e10, Offset: 0xe10, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x8},
elf.SectionHeader{Name: ".jcr", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e18, Offset: 0xe18, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x0, FileSize: 0x8},
elf.SectionHeader{Name: ".dynamic", Type: elf.SHT_DYNAMIC, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600e20, Offset: 0xe20, Size: 0x1d0, Link: 0x5, Info: 0x0, Addralign: 0x8, Entsize: 0x10, FileSize: 0x1d0},
elf.SectionHeader{Name: ".got", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x600ff0, Offset: 0xff0, Size: 0x10, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x10},
elf.SectionHeader{Name: ".got.plt", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x601000, Offset: 0x1000, Size: 0x20, Link: 0x0, Info: 0x0, Addralign: 0x8, Entsize: 0x8, FileSize: 0x20},
elf.SectionHeader{Name: ".data", Type: elf.SHT_PROGBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x601020, Offset: 0x1020, Size: 0x110, Link: 0x0, Info: 0x0, Addralign: 0x10, Entsize: 0x0, FileSize: 0x110},
elf.SectionHeader{Name: ".bss", Type: elf.SHT_NOBITS, Flags: elf.SHF_WRITE + elf.SHF_ALLOC, Addr: 0x601130, Offset: 0x1130, Size: 0x8, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x8},
elf.SectionHeader{Name: ".comment", Type: elf.SHT_PROGBITS, Flags: elf.SHF_MERGE + elf.SHF_STRINGS, Addr: 0x0, Offset: 0x1130, Size: 0x56, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x1, FileSize: 0x56},
elf.SectionHeader{Name: ".symtab", Type: elf.SHT_SYMTAB, Flags: 0x0, Addr: 0x0, Offset: 0x1188, Size: 0x600, Link: 0x1b, Info: 0x2d, Addralign: 0x8, Entsize: 0x18, FileSize: 0x600},
elf.SectionHeader{Name: ".strtab", Type: elf.SHT_STRTAB, Flags: 0x0, Addr: 0x0, Offset: 0x1788, Size: 0x1db, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0x1db},
elf.SectionHeader{Name: ".shstrtab", Type: elf.SHT_STRTAB, Flags: 0x0, Addr: 0x0, Offset: 0x1963, Size: 0xf1, Link: 0x0, Info: 0x0, Addralign: 0x1, Entsize: 0x0, FileSize: 0xf1},
},
symbols: []elf.Symbol{
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 1, Value: 0x400238, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 2, Value: 0x400254, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 3, Value: 0x400278, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 4, Value: 0x4002a0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 5, Value: 0x400300, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 6, Value: 0x40033e, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 7, Value: 0x400348, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 8, Value: 0x400368, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 9, Value: 0x400398, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 10, Value: 0x4003b0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 11, Value: 0x4003d0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4003f0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 13, Value: 0x4005b4, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 14, Value: 0x4005c0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 15, Value: 0x4005c4, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 16, Value: 0x4005f8, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e08, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 18, Value: 0x600e10, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 19, Value: 0x600e18, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 20, Value: 0x600e20, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 21, Value: 0x600ff0, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 22, Value: 0x601000, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601020, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x601130, Size: 0x0},
elf.Symbol{Name: "", Info: 0x3, Other: 0x0, Section: elf.SHN_UNDEF + 25, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "crtstuff.c", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__JCR_LIST__", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 19, Value: 0x600e18, Size: 0x0},
elf.Symbol{Name: "deregister_tm_clones", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x400420, Size: 0x0},
elf.Symbol{Name: "register_tm_clones", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x400460, Size: 0x0},
elf.Symbol{Name: "__do_global_dtors_aux", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4004a0, Size: 0x0},
elf.Symbol{Name: "completed.6963", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x601130, Size: 0x1},
elf.Symbol{Name: "__do_global_dtors_aux_fini_array_entry", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 18, Value: 0x600e10, Size: 0x0},
elf.Symbol{Name: "frame_dummy", Info: 0x2, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4004c0, Size: 0x0},
elf.Symbol{Name: "__frame_dummy_init_array_entry", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e08, Size: 0x0},
elf.Symbol{Name: "test2.c", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "crtstuff.c", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__FRAME_END__", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 16, Value: 0x4006e4, Size: 0x0},
elf.Symbol{Name: "__JCR_END__", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 19, Value: 0x600e18, Size: 0x0},
elf.Symbol{Name: "", Info: 0x4, Other: 0x0, Section: elf.SHN_ABS, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__init_array_end", Info: 0x0, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e10, Size: 0x0},
elf.Symbol{Name: "_DYNAMIC", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 20, Value: 0x600e20, Size: 0x0},
elf.Symbol{Name: "__init_array_start", Info: 0x0, Other: 0x0, Section: elf.SHN_UNDEF + 17, Value: 0x600e08, Size: 0x0},
elf.Symbol{Name: "__GNU_EH_FRAME_HDR", Info: 0x0, Other: 0x0, Section: elf.SHN_UNDEF + 15, Value: 0x4005c4, Size: 0x0},
elf.Symbol{Name: "_GLOBAL_OFFSET_TABLE_", Info: 0x1, Other: 0x0, Section: elf.SHN_UNDEF + 22, Value: 0x601000, Size: 0x0},
elf.Symbol{Name: "__libc_csu_fini", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4005b0, Size: 0x2},
elf.Symbol{Name: "symbol1", Info: 0x11, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601030, Size: 0x80},
elf.Symbol{Name: "data_start", Info: 0x20, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601020, Size: 0x0},
elf.Symbol{Name: "write@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "_edata", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601130, Size: 0x0},
elf.Symbol{Name: "_fini", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 13, Value: 0x4005b4, Size: 0x0},
elf.Symbol{Name: "__libc_start_main@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__data_start", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x601020, Size: 0x0},
elf.Symbol{Name: "__gmon_start__", Info: 0x20, Other: 0x0, Section: elf.SHN_UNDEF, Value: 0x0, Size: 0x0},
elf.Symbol{Name: "__dso_handle", Info: 0x11, Other: 0x2, Section: elf.SHN_UNDEF + 23, Value: 0x601028, Size: 0x0},
elf.Symbol{Name: "_IO_stdin_used", Info: 0x11, Other: 0x0, Section: elf.SHN_UNDEF + 14, Value: 0x4005c0, Size: 0x4},
elf.Symbol{Name: "symbol2", Info: 0x11, Other: 0x0, Section: elf.SHN_UNDEF + 23, Value: 0x6010b0, Size: 0x80},
elf.Symbol{Name: "__libc_csu_init", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x400540, Size: 0x65},
elf.Symbol{Name: "_end", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x601138, Size: 0x0},
elf.Symbol{Name: "_start", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4003f0, Size: 0x2b},
elf.Symbol{Name: "__bss_start", Info: 0x10, Other: 0x0, Section: elf.SHN_UNDEF + 24, Value: 0x601130, Size: 0x0},
elf.Symbol{Name: "main", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 12, Value: 0x4004f0, Size: 0x50},
elf.Symbol{Name: "__TMC_END__", Info: 0x11, Other: 0x2, Section: elf.SHN_UNDEF + 23, Value: 0x601130, Size: 0x0},
elf.Symbol{Name: "_init", Info: 0x12, Other: 0x0, Section: elf.SHN_UNDEF + 10, Value: 0x4003b0, Size: 0x0},
},
}

View file

@ -0,0 +1,63 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"strconv"
"testing"
)
func TestElfSymbolTable(t *testing.T) {
testCases := []struct {
file *mockElfFile
symbol string
offset, size uint64
}{
{
file: elfSymbolTable1,
symbol: "soong_build_number",
offset: 0x1030,
size: 128,
},
{
file: elfSymbolTable2,
symbol: "symbol1",
offset: 0x1030,
size: 128,
},
{
file: elfSymbolTable2,
symbol: "symbol2",
offset: 0x10b0,
size: 128,
},
}
for i, testCase := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
file, err := extractElfSymbols(testCase.file)
if err != nil {
t.Error(err.Error())
}
offset, size, err := findSymbol(file, testCase.symbol)
if err != nil {
t.Error(err.Error())
}
if offset != testCase.offset || size != testCase.size {
t.Errorf("expected %x:%x, got %x:%x", testCase.offset, testCase.size, offset, size)
}
})
}
}

View file

@ -19,52 +19,79 @@ import (
"fmt"
"io"
"sort"
"strings"
)
func findMachoSymbol(r io.ReaderAt, symbolName string) (uint64, uint64, error) {
func machoSymbolsFromFile(r io.ReaderAt) (*File, error) {
machoFile, err := macho.NewFile(r)
if err != nil {
return maxUint64, maxUint64, cantParseError{err}
return nil, cantParseError{err}
}
// symbols in macho files seem to be prefixed with an underscore
symbolName = "_" + symbolName
return extractMachoSymbols(machoFile)
}
func extractMachoSymbols(machoFile *macho.File) (*File, error) {
symbols := machoFile.Symtab.Syms
sort.Slice(symbols, func(i, j int) bool {
sort.SliceStable(symbols, func(i, j int) bool {
if symbols[i].Sect != symbols[j].Sect {
return symbols[i].Sect < symbols[j].Sect
}
return symbols[i].Value < symbols[j].Value
})
file := &File{}
for _, section := range machoFile.Sections {
file.Sections = append(file.Sections, &Section{
Name: section.Name,
Addr: section.Addr,
Offset: uint64(section.Offset),
Size: section.Size,
})
}
for _, symbol := range symbols {
if symbol.Name == symbolName && symbol.Sect != 0 {
// Find the next symbol in the same section with a higher address
n := sort.Search(len(symbols), func(i int) bool {
return symbols[i].Sect == symbol.Sect &&
symbols[i].Value > symbol.Value
if symbol.Sect > 0 {
section := file.Sections[symbol.Sect-1]
file.Symbols = append(file.Symbols, &Symbol{
// symbols in macho files seem to be prefixed with an underscore
Name: strings.TrimPrefix(symbol.Name, "_"),
// MachO symbol value is virtual address of the symbol, convert it to offset into the section.
Addr: symbol.Value - section.Addr,
// MachO symbols don't have size information.
Size: 0,
Section: section,
})
section := machoFile.Sections[symbol.Sect-1]
var end uint64
if n < len(symbols) {
end = symbols[n].Value
} else {
end = section.Addr + section.Size
}
if end <= symbol.Value && end > symbol.Value+4096 {
return maxUint64, maxUint64, fmt.Errorf("symbol end address does not seem valid, %x:%x", symbol.Value, end)
}
size := end - symbol.Value - 1
offset := uint64(section.Offset) + (symbol.Value - section.Addr)
return offset, size, nil
}
}
return maxUint64, maxUint64, fmt.Errorf("symbol not found")
return file, nil
}
func dumpMachoSymbols(r io.ReaderAt) error {
machoFile, err := macho.NewFile(r)
if err != nil {
return cantParseError{err}
}
fmt.Println("&macho.File{")
fmt.Println("\tSections: []*macho.Section{")
for _, section := range machoFile.Sections {
fmt.Printf("\t\t&macho.Section{SectionHeader: %#v},\n", section.SectionHeader)
}
fmt.Println("\t},")
fmt.Println("\tSymtab: &macho.Symtab{")
fmt.Println("\t\tSyms: []macho.Symbol{")
for _, symbol := range machoFile.Symtab.Syms {
fmt.Printf("\t\t\t%#v,\n", symbol)
}
fmt.Println("\t\t},")
fmt.Println("\t},")
fmt.Println("}")
return nil
}

View file

@ -0,0 +1,88 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"debug/macho"
)
/* Generated from: clang -o a.out test.c
#include <unistd.h>
char soong_build_number[128] = "PLACEHOLDER";
int main() {
write(STDOUT_FILENO, soong_build_number, sizeof(soong_build_number));
}
*/
var machoSymbolTable1 = &macho.File{
Sections: []*macho.Section{
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__text", Seg: "__TEXT", Addr: 0x100000f50, Size: 0x2e, Offset: 0xf50, Align: 0x4, Reloff: 0x0, Nreloc: 0x0, Flags: 0x80000400}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__stubs", Seg: "__TEXT", Addr: 0x100000f7e, Size: 0x6, Offset: 0xf7e, Align: 0x1, Reloff: 0x0, Nreloc: 0x0, Flags: 0x80000408}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__stub_helper", Seg: "__TEXT", Addr: 0x100000f84, Size: 0x1a, Offset: 0xf84, Align: 0x2, Reloff: 0x0, Nreloc: 0x0, Flags: 0x80000400}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__unwind_info", Seg: "__TEXT", Addr: 0x100000fa0, Size: 0x48, Offset: 0xfa0, Align: 0x2, Reloff: 0x0, Nreloc: 0x0, Flags: 0x0}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__eh_frame", Seg: "__TEXT", Addr: 0x100000fe8, Size: 0x18, Offset: 0xfe8, Align: 0x3, Reloff: 0x0, Nreloc: 0x0, Flags: 0x0}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__nl_symbol_ptr", Seg: "__DATA", Addr: 0x100001000, Size: 0x10, Offset: 0x1000, Align: 0x3, Reloff: 0x0, Nreloc: 0x0, Flags: 0x6}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__la_symbol_ptr", Seg: "__DATA", Addr: 0x100001010, Size: 0x8, Offset: 0x1010, Align: 0x3, Reloff: 0x0, Nreloc: 0x0, Flags: 0x7}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__data", Seg: "__DATA", Addr: 0x100001020, Size: 0x80, Offset: 0x1020, Align: 0x4, Reloff: 0x0, Nreloc: 0x0, Flags: 0x0}},
},
Symtab: &macho.Symtab{
Syms: []macho.Symbol{
macho.Symbol{Name: "__mh_execute_header", Type: 0xf, Sect: 0x1, Desc: 0x10, Value: 0x100000000},
macho.Symbol{Name: "_main", Type: 0xf, Sect: 0x1, Desc: 0x0, Value: 0x100000f50},
macho.Symbol{Name: "_soong_build_number", Type: 0xf, Sect: 0x8, Desc: 0x0, Value: 0x100001020},
macho.Symbol{Name: "_write", Type: 0x1, Sect: 0x0, Desc: 0x100, Value: 0x0},
macho.Symbol{Name: "dyld_stub_binder", Type: 0x1, Sect: 0x0, Desc: 0x100, Value: 0x0},
},
},
}
/* Generated from: clang -o a.out test2.c
#include <unistd.h>
char symbol1[128] = "PLACEHOLDER1";
char symbol2[128] = "PLACEHOLDER2";
int main() {
write(STDOUT_FILENO, symbol1, sizeof(symbol1));
write(STDOUT_FILENO, symbol2, sizeof(symbol2));
}
*/
var machoSymbolTable2 = &macho.File{
Sections: []*macho.Section{
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__text", Seg: "__TEXT", Addr: 0x100000f30, Size: 0x4a, Offset: 0xf30, Align: 0x4, Reloff: 0x0, Nreloc: 0x0, Flags: 0x80000400}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__stubs", Seg: "__TEXT", Addr: 0x100000f7a, Size: 0x6, Offset: 0xf7a, Align: 0x1, Reloff: 0x0, Nreloc: 0x0, Flags: 0x80000408}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__stub_helper", Seg: "__TEXT", Addr: 0x100000f80, Size: 0x1a, Offset: 0xf80, Align: 0x2, Reloff: 0x0, Nreloc: 0x0, Flags: 0x80000400}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__unwind_info", Seg: "__TEXT", Addr: 0x100000f9c, Size: 0x48, Offset: 0xf9c, Align: 0x2, Reloff: 0x0, Nreloc: 0x0, Flags: 0x0}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__eh_frame", Seg: "__TEXT", Addr: 0x100000fe8, Size: 0x18, Offset: 0xfe8, Align: 0x3, Reloff: 0x0, Nreloc: 0x0, Flags: 0x0}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__nl_symbol_ptr", Seg: "__DATA", Addr: 0x100001000, Size: 0x10, Offset: 0x1000, Align: 0x3, Reloff: 0x0, Nreloc: 0x0, Flags: 0x6}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__la_symbol_ptr", Seg: "__DATA", Addr: 0x100001010, Size: 0x8, Offset: 0x1010, Align: 0x3, Reloff: 0x0, Nreloc: 0x0, Flags: 0x7}},
&macho.Section{SectionHeader: macho.SectionHeader{Name: "__data", Seg: "__DATA", Addr: 0x100001020, Size: 0x100, Offset: 0x1020, Align: 0x4, Reloff: 0x0, Nreloc: 0x0, Flags: 0x0}},
},
Symtab: &macho.Symtab{
Syms: []macho.Symbol{
macho.Symbol{Name: "__mh_execute_header", Type: 0xf, Sect: 0x1, Desc: 0x10, Value: 0x100000000},
macho.Symbol{Name: "_main", Type: 0xf, Sect: 0x1, Desc: 0x0, Value: 0x100000f30},
macho.Symbol{Name: "_symbol1", Type: 0xf, Sect: 0x8, Desc: 0x0, Value: 0x100001020},
macho.Symbol{Name: "_symbol2", Type: 0xf, Sect: 0x8, Desc: 0x0, Value: 0x1000010a0},
macho.Symbol{Name: "_write", Type: 0x1, Sect: 0x0, Desc: 0x100, Value: 0x0},
macho.Symbol{Name: "dyld_stub_binder", Type: 0x1, Sect: 0x0, Desc: 0x100, Value: 0x0},
},
},
}

View file

@ -0,0 +1,64 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"debug/macho"
"strconv"
"testing"
)
func TestMachoSymbolTable(t *testing.T) {
testCases := []struct {
file *macho.File
symbol string
offset, size uint64
}{
{
file: machoSymbolTable1,
symbol: "soong_build_number",
offset: 0x1020,
size: 128,
},
{
file: machoSymbolTable2,
symbol: "symbol1",
offset: 0x1020,
size: 128,
},
{
file: machoSymbolTable2,
symbol: "symbol2",
offset: 0x10a0,
size: 128,
},
}
for i, testCase := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
file, err := extractMachoSymbols(testCase.file)
if err != nil {
t.Error(err.Error())
}
offset, size, err := findSymbol(file, testCase.symbol)
if err != nil {
t.Error(err.Error())
}
if offset != testCase.offset || size != testCase.size {
t.Errorf("expected %x:%x, got %x:%x", testCase.offset, testCase.size, offset, size)
}
})
}
}

View file

@ -19,54 +19,84 @@ import (
"fmt"
"io"
"sort"
"strings"
)
func findPESymbol(r io.ReaderAt, symbolName string) (uint64, uint64, error) {
func peSymbolsFromFile(r io.ReaderAt) (*File, error) {
peFile, err := pe.NewFile(r)
if err != nil {
return maxUint64, maxUint64, cantParseError{err}
return nil, cantParseError{err}
}
return extractPESymbols(peFile)
}
func extractPESymbols(peFile *pe.File) (*File, error) {
var prefix string
if peFile.FileHeader.Machine == pe.IMAGE_FILE_MACHINE_I386 {
// symbols in win32 exes seem to be prefixed with an underscore
symbolName = "_" + symbolName
prefix = "_"
}
symbols := peFile.Symbols
sort.Slice(symbols, func(i, j int) bool {
sort.SliceStable(symbols, func(i, j int) bool {
if symbols[i].SectionNumber != symbols[j].SectionNumber {
return symbols[i].SectionNumber < symbols[j].SectionNumber
}
return symbols[i].Value < symbols[j].Value
})
file := &File{}
for _, section := range peFile.Sections {
file.Sections = append(file.Sections, &Section{
Name: section.Name,
Addr: uint64(section.VirtualAddress),
Offset: uint64(section.Offset),
Size: uint64(section.VirtualSize),
})
}
for _, symbol := range symbols {
if symbol.Name == symbolName {
// Find the next symbol (n the same section with a higher address
n := sort.Search(len(symbols), func(i int) bool {
return symbols[i].SectionNumber == symbol.SectionNumber &&
symbols[i].Value > symbol.Value
if symbol.SectionNumber > 0 {
file.Symbols = append(file.Symbols, &Symbol{
Name: strings.TrimPrefix(symbol.Name, prefix),
// PE symbol value is the offset of the symbol into the section
Addr: uint64(symbol.Value),
// PE symbols don't have size information
Size: 0,
Section: file.Sections[symbol.SectionNumber-1],
})
section := peFile.Sections[symbol.SectionNumber-1]
var end uint32
if n < len(symbols) {
end = symbols[n].Value
} else {
end = section.Size
}
if end <= symbol.Value && end > symbol.Value+4096 {
return maxUint64, maxUint64, fmt.Errorf("symbol end address does not seem valid, %x:%x", symbol.Value, end)
}
size := end - symbol.Value - 1
offset := section.Offset + symbol.Value
return uint64(offset), uint64(size), nil
}
}
return maxUint64, maxUint64, fmt.Errorf("symbol not found")
return file, nil
}
func dumpPESymbols(r io.ReaderAt) error {
peFile, err := pe.NewFile(r)
if err != nil {
return cantParseError{err}
}
fmt.Println("&pe.File{")
fmt.Println("\tFileHeader: pe.FileHeader{")
fmt.Printf("\t\tMachine: %#v,\n", peFile.FileHeader.Machine)
fmt.Println("\t},")
fmt.Println("\tSections: []*pe.Section{")
for _, section := range peFile.Sections {
fmt.Printf("\t\t&pe.Section{SectionHeader: %#v},\n", section.SectionHeader)
}
fmt.Println("\t},")
fmt.Println("\tSymbols: []*pe.Symbol{")
for _, symbol := range peFile.Symbols {
fmt.Printf("\t\t%#v,\n", symbol)
}
fmt.Println("\t},")
fmt.Println("}")
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,141 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"debug/pe"
"strconv"
"testing"
)
func TestPESymbolTable(t *testing.T) {
testCases := []struct {
file *pe.File
symbol string
offset, size uint64
}{
{
file: peSymbolTable1,
symbol: "soong_build_number",
offset: 0x2420,
size: 128,
},
{
file: peSymbolTable2,
symbol: "symbol1",
offset: 0x2420,
size: 128,
},
{
file: peSymbolTable2,
symbol: "symbol2",
offset: 0x24a0,
size: 128,
},
{
// Test when symbol has the same value as the target symbol but is located afterwards in the list
file: &pe.File{
FileHeader: pe.FileHeader{
Machine: pe.IMAGE_FILE_MACHINE_I386,
},
Sections: []*pe.Section{
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".text", VirtualSize: 0x15e83c, VirtualAddress: 0x1000, Size: 0x15ea00, Offset: 0x600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060}},
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".data", VirtualSize: 0x6a58, VirtualAddress: 0x160000, Size: 0x6c00, Offset: 0x15f000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0600040}},
},
Symbols: []*pe.Symbol{
&pe.Symbol{Name: "_soong_build_number", Value: 0x20, SectionNumber: 2, Type: 0x0, StorageClass: 0x2},
&pe.Symbol{Name: ".data", Value: 0x20, SectionNumber: 2, Type: 0x0, StorageClass: 0x3},
&pe.Symbol{Name: "_adb_device_banner", Value: 0xa0, SectionNumber: 2, Type: 0x0, StorageClass: 0x2},
},
},
symbol: "soong_build_number",
offset: 0x15f020,
size: 128,
},
{
// Test when symbol has nothing after it
file: &pe.File{
FileHeader: pe.FileHeader{
Machine: pe.IMAGE_FILE_MACHINE_AMD64,
},
Sections: []*pe.Section{
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".text", VirtualSize: 0x1cc0, VirtualAddress: 0x1000, Size: 0x1e00, Offset: 0x600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500020}},
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".data", VirtualSize: 0xa0, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0600040}},
},
Symbols: []*pe.Symbol{
&pe.Symbol{Name: "soong_build_number", Value: 0x20, SectionNumber: 2, Type: 0x0, StorageClass: 0x2},
},
},
symbol: "soong_build_number",
offset: 0x2420,
size: 128,
},
{
// Test when symbol has a symbol in a different section after it
file: &pe.File{
FileHeader: pe.FileHeader{
Machine: pe.IMAGE_FILE_MACHINE_AMD64,
},
Sections: []*pe.Section{
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".text", VirtualSize: 0x1cc0, VirtualAddress: 0x1000, Size: 0x1e00, Offset: 0x600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500020}},
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".data", VirtualSize: 0xa0, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0600040}},
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".rdata", VirtualSize: 0x5e0, VirtualAddress: 0x4000, Size: 0x600, Offset: 0x2600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40500040}},
},
Symbols: []*pe.Symbol{
&pe.Symbol{Name: "soong_build_number", Value: 0x20, SectionNumber: 2, Type: 0x0, StorageClass: 0x2},
&pe.Symbol{Name: "_adb_device_banner", Value: 0x30, SectionNumber: 3, Type: 0x0, StorageClass: 0x2},
},
},
symbol: "soong_build_number",
offset: 0x2420,
size: 128,
},
{
// Test when symbols are out of order
file: &pe.File{
FileHeader: pe.FileHeader{
Machine: pe.IMAGE_FILE_MACHINE_AMD64,
},
Sections: []*pe.Section{
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".text", VirtualSize: 0x1cc0, VirtualAddress: 0x1000, Size: 0x1e00, Offset: 0x600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500020}},
&pe.Section{SectionHeader: pe.SectionHeader{Name: ".data", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0600040}},
},
Symbols: []*pe.Symbol{
&pe.Symbol{Name: "_adb_device_banner", Value: 0xa0, SectionNumber: 2, Type: 0x0, StorageClass: 0x2},
&pe.Symbol{Name: "soong_build_number", Value: 0x20, SectionNumber: 2, Type: 0x0, StorageClass: 0x2},
},
},
symbol: "soong_build_number",
offset: 0x2420,
size: 128,
},
}
for i, testCase := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
file, err := extractPESymbols(testCase.file)
if err != nil {
t.Error(err.Error())
}
offset, size, err := findSymbol(file, testCase.symbol)
if err != nil {
t.Error(err.Error())
}
if offset != testCase.offset || size != testCase.size {
t.Errorf("expected %x:%x, got %x:%x", testCase.offset, testCase.size, offset, size)
}
})
}
}

View file

@ -29,6 +29,8 @@ var (
symbol = flag.String("s", "", "symbol to inject into")
from = flag.String("from", "", "optional existing value of the symbol for verification")
value = flag.String("v", "", "value to inject into symbol")
dump = flag.Bool("dump", false, "dump the symbol table for copying into a test")
)
var maxUint64 uint64 = math.MaxUint64
@ -50,16 +52,18 @@ func main() {
usageError("-i is required")
}
if *output == "" {
usageError("-o is required")
}
if !*dump {
if *output == "" {
usageError("-o is required")
}
if *symbol == "" {
usageError("-s is required")
}
if *symbol == "" {
usageError("-s is required")
}
if *value == "" {
usageError("-v is required")
if *value == "" {
usageError("-v is required")
}
}
r, err := os.Open(*input)
@ -69,6 +73,15 @@ func main() {
}
defer r.Close()
if *dump {
err := dumpSymbols(r)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(6)
}
return
}
w, err := os.OpenFile(*output, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
@ -76,36 +89,45 @@ func main() {
}
defer w.Close()
err = injectSymbol(r, w, *symbol, *value, *from)
file, err := openFile(r)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(4)
}
err = injectSymbol(file, w, *symbol, *value, *from)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Remove(*output)
os.Exit(2)
os.Exit(5)
}
}
type ReadSeekerAt interface {
io.ReaderAt
io.ReadSeeker
}
func injectSymbol(r ReadSeekerAt, w io.Writer, symbol, value, from string) error {
var offset, size uint64
var err error
offset, size, err = findElfSymbol(r, symbol)
func openFile(r io.ReaderAt) (*File, error) {
file, err := elfSymbolsFromFile(r)
if elfError, ok := err.(cantParseError); ok {
// Try as a mach-o file
offset, size, err = findMachoSymbol(r, symbol)
file, err = machoSymbolsFromFile(r)
if _, ok := err.(cantParseError); ok {
// Try as a windows PE file
offset, size, err = findPESymbol(r, symbol)
file, err = peSymbolsFromFile(r)
if _, ok := err.(cantParseError); ok {
// Can't parse as elf, macho, or PE, return the elf error
return elfError
return nil, elfError
}
}
}
if err != nil {
return nil, err
}
file.r = r
return file, err
}
func injectSymbol(file *File, w io.Writer, symbol, value, from string) error {
offset, size, err := findSymbol(file, symbol)
if err != nil {
return err
}
@ -119,7 +141,7 @@ func injectSymbol(r ReadSeekerAt, w io.Writer, symbol, value, from string) error
expected := make([]byte, size)
existing := make([]byte, size)
copy(expected, from)
_, err := r.ReadAt(existing, int64(offset))
_, err := file.r.ReadAt(existing, int64(offset))
if err != nil {
return err
}
@ -129,48 +151,107 @@ func injectSymbol(r ReadSeekerAt, w io.Writer, symbol, value, from string) error
}
}
return copyAndInject(r, w, offset, size, value)
return copyAndInject(file.r, w, offset, size, value)
}
func copyAndInject(r io.ReadSeeker, w io.Writer, offset, size uint64, value string) (err error) {
// helper that asserts a two-value function returning an int64 and an error has err != nil
must := func(n int64, err error) {
if err != nil {
panic(err)
}
}
// helper that asserts a two-value function returning an int and an error has err != nil
must2 := func(n int, err error) {
must(int64(n), err)
}
// convert a panic into returning an error
defer func() {
if r := recover(); r != nil {
err, _ = r.(error)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
if err == nil {
panic(r)
}
}
}()
func copyAndInject(r io.ReaderAt, w io.Writer, offset, size uint64, value string) (err error) {
buf := make([]byte, size)
copy(buf, value)
// Reset the input file
must(r.Seek(0, io.SeekStart))
// Copy the first bytes up to the symbol offset
must(io.CopyN(w, r, int64(offset)))
// Skip the symbol contents in the input file
must(r.Seek(int64(size), io.SeekCurrent))
// Write the injected value in the output file
must2(w.Write(buf))
// Write the remainder of the file
must(io.Copy(w, r))
_, err = io.Copy(w, io.NewSectionReader(r, 0, int64(offset)))
return nil
// Write the injected value in the output file
if err == nil {
_, err = w.Write(buf)
}
// Write the remainder of the file
pos := int64(offset + size)
if err == nil {
_, err = io.Copy(w, io.NewSectionReader(r, pos, 1<<63-1-pos))
}
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
}
func findSymbol(file *File, symbolName string) (uint64, uint64, error) {
for i, symbol := range file.Symbols {
if symbol.Name == symbolName {
// Find the next symbol (n the same section with a higher address
var n int
for n = i; n < len(file.Symbols); n++ {
if file.Symbols[n].Section != symbol.Section {
n = len(file.Symbols)
break
}
if file.Symbols[n].Addr > symbol.Addr {
break
}
}
size := symbol.Size
if size == 0 {
var end uint64
if n < len(file.Symbols) {
end = file.Symbols[n].Addr
} else {
end = symbol.Section.Size
}
if end <= symbol.Addr || end > symbol.Addr+4096 {
return maxUint64, maxUint64, fmt.Errorf("symbol end address does not seem valid, %x:%x", symbol.Addr, end)
}
size = end - symbol.Addr
}
offset := symbol.Section.Offset + symbol.Addr
return uint64(offset), uint64(size), nil
}
}
return maxUint64, maxUint64, fmt.Errorf("symbol not found")
}
type File struct {
r io.ReaderAt
Symbols []*Symbol
Sections []*Section
}
type Symbol struct {
Name string
Addr uint64 // Address of the symbol inside the section.
Size uint64 // Size of the symbol, if known.
Section *Section
}
type Section struct {
Name string
Addr uint64 // Virtual address of the start of the section.
Offset uint64 // Offset into the file of the start of the section.
Size uint64
}
func dumpSymbols(r io.ReaderAt) error {
err := dumpElfSymbols(r)
if elfError, ok := err.(cantParseError); ok {
// Try as a mach-o file
err = dumpMachoSymbols(r)
if _, ok := err.(cantParseError); ok {
// Try as a windows PE file
err = dumpPESymbols(r)
if _, ok := err.(cantParseError); ok {
// Can't parse as elf, macho, or PE, return the elf error
return elfError
}
}
}
return err
}

View file

@ -0,0 +1,67 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bytes"
"strconv"
"testing"
)
func TestCopyAndInject(t *testing.T) {
s := "abcdefghijklmnopqrstuvwxyz"
testCases := []struct {
offset, size uint64
value string
expected string
}{
{
offset: 0,
size: 1,
value: "A",
expected: "Abcdefghijklmnopqrstuvwxyz",
},
{
offset: 1,
size: 1,
value: "B",
expected: "aBcdefghijklmnopqrstuvwxyz",
},
{
offset: 1,
size: 1,
value: "BCD",
expected: "aBcdefghijklmnopqrstuvwxyz",
},
{
offset: 25,
size: 1,
value: "Z",
expected: "abcdefghijklmnopqrstuvwxyZ",
},
}
for i, testCase := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
in := bytes.NewReader([]byte(s))
out := &bytes.Buffer{}
copyAndInject(in, out, testCase.offset, testCase.size, testCase.value)
if out.String() != testCase.expected {
t.Errorf("expected %s, got %s", testCase.expected, out.String())
}
})
}
}