Merge changes I6f7d40b7,I25654032 am: 83a495830b
am: dfcdeec8b2
Change-Id: Ida245504ae6e7074e800ce809fae12e1d6957ee3
This commit is contained in:
commit
4335ca3cd6
22 changed files with 3430 additions and 164 deletions
|
@ -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...)
|
||||
|
|
12
cc/libbuildversion/Android.bp
Normal file
12
cc/libbuildversion/Android.bp
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
30
cc/libbuildversion/include/build/version.h
Normal file
30
cc/libbuildversion/include/build/version.h
Normal 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
|
55
cc/libbuildversion/libbuildversion.cpp
Normal file
55
cc/libbuildversion/libbuildversion.cpp
Normal 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
|
35
cc/libbuildversion/tests/Android.bp
Normal file
35
cc/libbuildversion/tests/Android.bp
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
36
cc/libbuildversion/tests/build_version_test.cpp
Normal file
36
cc/libbuildversion/tests/build_version_test.cpp
Normal 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
|
23
cc/libbuildversion/tests/build_version_test_lib.cpp
Normal file
23
cc/libbuildversion/tests/build_version_test_lib.cpp
Normal 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();
|
||||
}
|
24
cc/libbuildversion/tests/build_version_test_lib.h
Normal file
24
cc/libbuildversion/tests/build_version_test_lib.h
Normal 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_
|
|
@ -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...)
|
||||
|
||||
|
|
36
cc/linker.go
36
cc/linker.go
|
@ -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(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
241
cmd/symbol_inject/elf_symboldata_test.go
Normal file
241
cmd/symbol_inject/elf_symboldata_test.go
Normal 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},
|
||||
},
|
||||
}
|
63
cmd/symbol_inject/elf_test.go
Normal file
63
cmd/symbol_inject/elf_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
88
cmd/symbol_inject/macho_symboldata_test.go
Normal file
88
cmd/symbol_inject/macho_symboldata_test.go
Normal 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},
|
||||
},
|
||||
},
|
||||
}
|
64
cmd/symbol_inject/macho_test.go
Normal file
64
cmd/symbol_inject/macho_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
2102
cmd/symbol_inject/pe_symboldata_test.go
Normal file
2102
cmd/symbol_inject/pe_symboldata_test.go
Normal file
File diff suppressed because it is too large
Load diff
141
cmd/symbol_inject/pe_test.go
Normal file
141
cmd/symbol_inject/pe_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
67
cmd/symbol_inject/symbol_inject_test.go
Normal file
67
cmd/symbol_inject/symbol_inject_test.go
Normal 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())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue