aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2023-11-27 17:46:34 +0100
committerAleksandr Nogikh <nogikh@google.com>2024-01-17 09:28:44 +0000
commitc9a1c95bf02421042abda563e4ec488384157409 (patch)
tree3cfbeacc8843daa4db9e6d711d2aa9bbfeeeada7 /pkg
parentedd756a5fa6390fb08e2b515e507253a59b22d70 (diff)
pkg/cover/backend: adjust module base address by .text offset
Modules' .text sections are not necessarily loaded at the address shown in /proc/modules. If there are other non-init code sections preceding them in the ELF binary, .text is loaded at non-zero address. For example, for a module with the following sections: Idx Name Size VMA LMA File off Algn ... 5 .plt 00000001 0000000000000000 0000000000000000 00000500 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 6 .init.ddplt 00000001 0000000000000000 0000000000000000 00000501 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 7 .text.ftrace_trampoline 00000001 0000000000000000 0000000000000000 00000502 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 8 .hyp.text 00002000 0000000000000000 0000000000000000 00001000 2**12 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE ... 13 .text 00001aac 0000000000000000 0000000000000000 00005048 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE the base address displayed in /proc/modules points to the beginning of .plt, and other sections have the following offsets: .init.plt - ignored .text.ftrace_trampoline - 0x1 .hyp.text - 0x1000 .text - 0x3000 This patch calculates the offset of the .text section and uses it to adjust the address obtained from /proc/modules.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/cover/backend/dwarf.go3
-rw-r--r--pkg/cover/backend/elf.go42
-rw-r--r--pkg/cover/backend/modules.go12
3 files changed, 52 insertions, 5 deletions
diff --git a/pkg/cover/backend/dwarf.go b/pkg/cover/backend/dwarf.go
index 4db2f2ad4..75063f9e0 100644
--- a/pkg/cover/backend/dwarf.go
+++ b/pkg/cover/backend/dwarf.go
@@ -34,6 +34,7 @@ type dwarfParams struct {
readTextData func(*Module) ([]byte, error)
readModuleCoverPoints func(*targets.Target, *Module, *symbolInfo) ([2][]uint64, error)
readTextRanges func(*Module) ([]pcRange, []*CompileUnit, error)
+ getModuleOffset func(string) uint64
}
type Arch struct {
@@ -91,7 +92,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) {
objDir := params.objDir
srcDir := params.srcDir
buildDir := params.buildDir
- modules, err := discoverModules(target, objDir, params.moduleObj, params.hostModules)
+ modules, err := discoverModules(target, objDir, params.moduleObj, params.hostModules, params.getModuleOffset)
if err != nil {
return nil, err
}
diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go
index 57975a9d5..5398d64bb 100644
--- a/pkg/cover/backend/elf.go
+++ b/pkg/cover/backend/elf.go
@@ -28,6 +28,7 @@ func makeELF(target *targets.Target, objDir, srcDir, buildDir string,
readTextData: elfReadTextData,
readModuleCoverPoints: elfReadModuleCoverPoints,
readTextRanges: elfReadTextRanges,
+ getModuleOffset: elfGetModuleOffset,
})
}
@@ -175,3 +176,44 @@ func elfReadModuleCoverPoints(target *targets.Target, module *Module, info *symb
}
return pcs, nil
}
+
+// Calculate the offset of the module .text section in the kernel memory.
+// /proc/modules only contains the base address, which corresponds to the
+// beginning of the first code section, but that section does not have to
+// be .text (e.g. on Android it may be .plt).
+// The offset is calculated by summing up the aligned sizes of sections
+// that:
+// - precede .text;
+// - are not .init/.exit sections;
+// - have the SHF_ALLOC and SHF_EXECINSTR flags.
+func elfGetModuleOffset(path string) uint64 {
+ file, err := elf.Open(path)
+ if err != nil {
+ return 0
+ }
+ defer file.Close()
+ ts := file.Section(".text")
+ if ts == nil {
+ return 0
+ }
+ off := uint64(0)
+ const textFlagsMask = elf.SHF_ALLOC | elf.SHF_EXECINSTR
+ for _, s := range file.Sections {
+ if (s.Flags&textFlagsMask == textFlagsMask) && !strings.HasPrefix(s.SectionHeader.Name, ".init") &&
+ !strings.HasPrefix(s.SectionHeader.Name, ".exit") {
+ off = alignUp(off, s.SectionHeader.Addralign)
+ if s == ts {
+ return off
+ }
+ off += s.SectionHeader.Size
+ }
+ }
+ return 0
+}
+
+func alignUp(addr, align uint64) uint64 {
+ if align == 0 {
+ return addr
+ }
+ return (addr + align - 1) & ^(align - 1)
+}
diff --git a/pkg/cover/backend/modules.go b/pkg/cover/backend/modules.go
index 4da73d3ad..ac3326236 100644
--- a/pkg/cover/backend/modules.go
+++ b/pkg/cover/backend/modules.go
@@ -16,14 +16,16 @@ import (
"github.com/google/syzkaller/sys/targets"
)
-func discoverModules(target *targets.Target, objDir string, moduleObj []string, hostModules []host.KernelModule) (
+func discoverModules(target *targets.Target, objDir string, moduleObj []string,
+ hostModules []host.KernelModule, getModuleOffset func(string) uint64) (
[]*Module, error) {
modules := []*Module{
// A dummy module representing the kernel itself.
{Path: filepath.Join(objDir, target.KernelObject)},
}
if target.OS == targets.Linux {
- modules1, err := discoverModulesLinux(append([]string{objDir}, moduleObj...), hostModules)
+ modules1, err := discoverModulesLinux(append([]string{objDir}, moduleObj...),
+ hostModules, getModuleOffset)
if err != nil {
return nil, err
}
@@ -34,7 +36,8 @@ func discoverModules(target *targets.Target, objDir string, moduleObj []string,
return modules, nil
}
-func discoverModulesLinux(dirs []string, hostModules []host.KernelModule) ([]*Module, error) {
+func discoverModulesLinux(dirs []string, hostModules []host.KernelModule,
+ getModuleOffset func(string) uint64) ([]*Module, error) {
paths, err := locateModules(dirs)
if err != nil {
return nil, err
@@ -47,9 +50,10 @@ func discoverModulesLinux(dirs []string, hostModules []host.KernelModule) ([]*Mo
continue
}
log.Logf(0, "module %v -> %v", mod.Name, path)
+ offset := getModuleOffset(path)
modules = append(modules, &Module{
Name: mod.Name,
- Addr: mod.Addr,
+ Addr: mod.Addr + offset,
Path: path,
})
}