Skip to content

Commit

Permalink
all: fix arm64 runtime pc not align with elf
Browse files Browse the repository at this point in the history
  • Loading branch information
joeyjiaojg authored and dvyukov committed Jun 25, 2021
1 parent 0edbbe3 commit ae6bf8d
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 102 deletions.
24 changes: 15 additions & 9 deletions pkg/cover/backend/dwarf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bufio"
"bytes"
"debug/dwarf"
"debug/elf"
"encoding/binary"
"fmt"
"io/ioutil"
Expand All @@ -30,25 +31,30 @@ type containerFns struct {
}

type Arch struct {
callLen int
opcodeOffset int
opcodes [2]byte
target func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64
callLen int
relaOffset uint64
opcodeOffset int
opcodes [2]byte
callRelocType uint64
target func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64
}

var arches = map[string]Arch{
targets.AMD64: {
callLen: 5,
opcodes: [2]byte{0xe8, 0xe8},
callLen: 5,
relaOffset: 1,
opcodes: [2]byte{0xe8, 0xe8},
callRelocType: uint64(elf.R_X86_64_PLT32),
target: func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64 {
off := uint64(int64(int32(binary.LittleEndian.Uint32(insn[1:]))))
return pc + off + uint64(arch.callLen)
},
},
targets.ARM64: {
callLen: 4,
opcodeOffset: 3,
opcodes: [2]byte{0x94, 0x97},
callLen: 4,
opcodeOffset: 3,
opcodes: [2]byte{0x94, 0x97},
callRelocType: uint64(elf.R_AARCH64_CALL26),
target: func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64 {
off := uint64(binary.LittleEndian.Uint32(insn)) & ((1 << 24) - 1)
if opcode == arch.opcodes[1] {
Expand Down
14 changes: 9 additions & 5 deletions pkg/cover/backend/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ func elfReadSymbols(module *Module, info *symbolInfo) ([]*Symbol, error) {
if err != nil {
return nil, fmt.Errorf("failed to read ELF symbols: %v", err)
}
info.textAddr = text.Addr
if module.Name == "" {
info.textAddr = text.Addr
}
var symbols []*Symbol
for i, symb := range allSymbols {
text := symb.Value >= text.Addr && symb.Value+symb.Size <= text.Addr+text.Size
Expand Down Expand Up @@ -133,7 +135,8 @@ func elfReadModuleCoverPoints(target *targets.Target, module *Module, info *symb
if err != nil {
return pcs, err
}
offset := uint64(arches[target.Arch].opcodeOffset)
callRelocType := arches[target.Arch].callRelocType
relaOffset := arches[target.Arch].relaOffset
for _, s := range file.Sections {
if s.Type != elf.SHT_RELA { // nolint: misspell
continue
Expand All @@ -146,10 +149,11 @@ func elfReadModuleCoverPoints(target *targets.Target, module *Module, info *symb
}
return pcs, err
}
// Note: this assumes that call instruction is 1 byte.
pc := module.Addr + rel.Off - 1
if (rel.Info & 0xffffffff) != callRelocType {
continue
}
pc := module.Addr + rel.Off - relaOffset
index := int(elf.R_SYM64(rel.Info)) - 1
pc -= offset
if info.tracePCIdx[index] {
pcs[0] = append(pcs[0], pc)
} else if info.traceCmpIdx[index] {
Expand Down
100 changes: 95 additions & 5 deletions pkg/cover/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,43 @@ import (

"github.com/google/syzkaller/pkg/cover/backend"
"github.com/google/syzkaller/pkg/mgrconfig"
"github.com/google/syzkaller/sys/targets"
)

func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog) error {
func fixUpPCs(target string, progs []Prog, coverFilter map[uint32]uint32) []Prog {
if coverFilter != nil {
for _, prog := range progs {
var nPCs []uint64
for _, pc := range prog.PCs {
if coverFilter[uint32(pc)] != 0 {
nPCs = append(nPCs, pc)
}
}
prog.PCs = nPCs
}
}

// On arm64 as PLT is enabled by default, .text section is loaded after .plt section,
// so there is 0x18 bytes offset from module load address for .text section
// we need to remove the 0x18 bytes offset in order to correct module symbol address
if target == targets.ARM64 {
for _, prog := range progs {
var nPCs []uint64
for _, pc := range prog.PCs {
// TODO: avoid to hardcode the address
if pc < 0xffffffd010000000 {
pc -= 0x18
}
nPCs = append(nPCs, pc)
}
prog.PCs = nPCs
}
}
return progs
}

func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
files, err := rg.prepareFileMap(progs)
if err != nil {
return err
Expand Down Expand Up @@ -106,7 +140,8 @@ func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog) error {
return coverTemplate.Execute(w, d)
}

func (rg *ReportGenerator) DoRawCoverFiles(w http.ResponseWriter, progs []Prog) error {
func (rg *ReportGenerator) DoRawCoverFiles(w http.ResponseWriter, progs []Prog, coverFilter map[uint32]uint32) error {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
if err := rg.lazySymbolize(progs); err != nil {
return err
}
Expand All @@ -125,6 +160,58 @@ func (rg *ReportGenerator) DoRawCoverFiles(w http.ResponseWriter, progs []Prog)
return nil
}

func (rg *ReportGenerator) DoRawCover(w http.ResponseWriter, progs []Prog, coverFilter map[uint32]uint32) {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
var pcs []uint64
uniquePCs := make(map[uint64]bool)
for _, prog := range progs {
for _, pc := range prog.PCs {
if uniquePCs[pc] {
continue
}
uniquePCs[pc] = true
pcs = append(pcs, pc)
}
}
sort.Slice(pcs, func(i, j int) bool {
return pcs[i] < pcs[j]
})

w.Header().Set("Content-Type", "text/plain; charset=utf-8")
buf := bufio.NewWriter(w)
for _, pc := range pcs {
fmt.Fprintf(buf, "0x%x\n", pc)
}
buf.Flush()
}

func (rg *ReportGenerator) DoFilterPCs(w http.ResponseWriter, progs []Prog, coverFilter map[uint32]uint32) {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
var pcs []uint64
uniquePCs := make(map[uint64]bool)
for _, prog := range progs {
for _, pc := range prog.PCs {
if uniquePCs[pc] {
continue
}
uniquePCs[pc] = true
if coverFilter[uint32(pc)] != 0 {
pcs = append(pcs, pc)
}
}
}
sort.Slice(pcs, func(i, j int) bool {
return pcs[i] < pcs[j]
})

w.Header().Set("Content-Type", "text/plain; charset=utf-8")
buf := bufio.NewWriter(w)
for _, pc := range pcs {
fmt.Fprintf(buf, "0x%x\n", pc)
}
buf.Flush()
}

type fileStats struct {
Name string
CoveredLines int
Expand Down Expand Up @@ -200,7 +287,8 @@ func (rg *ReportGenerator) convertToStats(progs []Prog) ([]fileStats, error) {
return data, nil
}

func (rg *ReportGenerator) DoCSVFiles(w io.Writer, progs []Prog) error {
func (rg *ReportGenerator) DoCSVFiles(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
data, err := rg.convertToStats(progs)
if err != nil {
return err
Expand Down Expand Up @@ -298,7 +386,8 @@ func groupCoverByFilePrefixes(datas []fileStats, subsystems []mgrconfig.Subsyste
return d
}

func (rg *ReportGenerator) DoHTMLTable(w io.Writer, progs []Prog) error {
func (rg *ReportGenerator) DoHTMLTable(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
data, err := rg.convertToStats(progs)
if err != nil {
return err
Expand All @@ -316,7 +405,8 @@ var csvHeader = []string{
"Total PCs",
}

func (rg *ReportGenerator) DoCSV(w io.Writer, progs []Prog) error {
func (rg *ReportGenerator) DoCSV(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
files, err := rg.prepareFileMap(progs)
if err != nil {
return err
Expand Down
8 changes: 4 additions & 4 deletions pkg/cover/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,20 +224,20 @@ func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, []
test.Progs = append(test.Progs, Prog{Data: "main", PCs: pcs})
}
html := new(bytes.Buffer)
if err := rg.DoHTML(html, test.Progs); err != nil {
if err := rg.DoHTML(html, test.Progs, nil); err != nil {
return nil, nil, err
}
htmlTable := new(bytes.Buffer)
if err := rg.DoHTMLTable(htmlTable, test.Progs); err != nil {
if err := rg.DoHTMLTable(htmlTable, test.Progs, nil); err != nil {
return nil, nil, err
}
_ = htmlTable
csv := new(bytes.Buffer)
if err := rg.DoCSV(csv, test.Progs); err != nil {
if err := rg.DoCSV(csv, test.Progs, nil); err != nil {
return nil, nil, err
}
csvFiles := new(bytes.Buffer)
if err := rg.DoCSVFiles(csvFiles, test.Progs); err != nil {
if err := rg.DoCSVFiles(csvFiles, test.Progs, nil); err != nil {
return nil, nil, err
}
_ = csvFiles
Expand Down
Loading

0 comments on commit ae6bf8d

Please sign in to comment.