github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/cover/backend/mach-o.go (about)

     1  // Copyright 2020 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package backend
     5  
     6  import (
     7  	"debug/macho"
     8  	"fmt"
     9  	"path/filepath"
    10  	"sort"
    11  	"strings"
    12  
    13  	"github.com/google/syzkaller/sys/targets"
    14  )
    15  
    16  func makeMachO(target *targets.Target, objDir, srcDir, buildDir string,
    17  	moduleObj []string, hostModules []KernelModule) (*Impl, error) {
    18  	return makeDWARF(&dwarfParams{
    19  		target:                target,
    20  		objDir:                objDir,
    21  		srcDir:                srcDir,
    22  		buildDir:              buildDir,
    23  		moduleObj:             moduleObj,
    24  		hostModules:           hostModules,
    25  		readSymbols:           machoReadSymbols,
    26  		readTextData:          machoReadTextData,
    27  		readModuleCoverPoints: machoReadModuleCoverPoints,
    28  		readTextRanges:        machoReadTextRanges,
    29  	})
    30  }
    31  
    32  func machoReadSymbols(module *Module, info *symbolInfo) ([]*Symbol, error) {
    33  	file, err := macho.Open(module.Path)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	text := file.Section("__text")
    38  	if text == nil {
    39  		return nil, fmt.Errorf("no __text section in the object file")
    40  	}
    41  	if file.Symtab == nil {
    42  		return nil, fmt.Errorf("failed to read Mach-O symbols")
    43  	}
    44  	info.textAddr = text.Addr
    45  
    46  	// We don't get symbol lengths or symbol ends in Mach-O symbols. So we
    47  	// guesstimate them by taking the next symbols beginning -1. That only
    48  	// works after we have sorted them.
    49  	sort.Slice(file.Symtab.Syms, func(i, j int) bool {
    50  		return file.Symtab.Syms[i].Value < file.Symtab.Syms[j].Value
    51  	})
    52  
    53  	var symbols []*Symbol
    54  	for i, symb := range file.Symtab.Syms {
    55  		// Mach-Os doesn't contain the Symbol size like in ELF
    56  		symbEnd := text.Addr + text.Size
    57  		if i < len(file.Symtab.Syms)-1 {
    58  			symbEnd = file.Symtab.Syms[i+1].Value
    59  		}
    60  
    61  		text := symb.Value >= text.Addr && symbEnd <= text.Addr+text.Size
    62  		if text {
    63  			symbStart := symb.Value + module.Addr
    64  			symbols = append(symbols, &Symbol{
    65  				Module: module,
    66  				ObjectUnit: ObjectUnit{
    67  					Name: symb.Name,
    68  				},
    69  				Start: symbStart,
    70  				End:   symbEnd,
    71  			})
    72  		}
    73  		if strings.HasPrefix(symb.Name, "___sanitizer_cov_trace_") {
    74  			if symb.Name == "___sanitizer_cov_trace_pc_guard" {
    75  				info.tracePCIdx[i] = true
    76  				if text {
    77  					info.tracePC[symb.Value] = true
    78  				}
    79  			} else {
    80  				info.traceCmpIdx[i] = true
    81  				if text {
    82  					info.traceCmp[symb.Value] = true
    83  				}
    84  			}
    85  		}
    86  	}
    87  	return symbols, nil
    88  }
    89  
    90  func machoReadTextRanges(module *Module) ([]pcRange, []*CompileUnit, error) {
    91  	dir, kernel := filepath.Split(module.Path)
    92  	dSYMPath := filepath.Join(dir, fmt.Sprintf(
    93  		"%[1]s.dSYM/Contents/Resources/DWARF/%[1]s", kernel))
    94  	dSYM, err := macho.Open(dSYMPath)
    95  	if err != nil {
    96  		return nil, nil, err
    97  	}
    98  	debugInfo, err := dSYM.DWARF()
    99  	if err != nil {
   100  		return nil, nil, fmt.Errorf("failed to parse DWARF: %w", err)
   101  	}
   102  	return readTextRanges(debugInfo, module, nil)
   103  }
   104  
   105  func machoReadTextData(module *Module) ([]byte, error) {
   106  	file, err := macho.Open(module.Path)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	text := file.Section("__text")
   111  	if text == nil {
   112  		return nil, fmt.Errorf("no __text section in the object file")
   113  	}
   114  	return text.Data()
   115  }
   116  
   117  func machoReadModuleCoverPoints(target *targets.Target, module *Module, info *symbolInfo) ([2][]uint64, error) {
   118  	// TODO: Linux/ELF supports module symbols. We should probably also do that
   119  	// for XNU/Mach-O. To maximize code re-use we already have a lot of the
   120  	// plumbing for module support. I think we mainly miss an equivalent to
   121  	// discoverModules and this function at the moment.
   122  	return [2][]uint64{}, fmt.Errorf("machoReadModuleCoverPoints not implemented")
   123  }