github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/binary_info/binary_info_darwin.go (about)

     1  // The MIT License (MIT)
     2  
     3  // Copyright (c) 2014 Derek Parker
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy of
     6  // this software and associated documentation files (the "Software"), to deal in
     7  // the Software without restriction, including without limitation the rights to
     8  // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     9  // the Software, and to permit persons to whom the Software is furnished to do so,
    10  // subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    17  // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    18  // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    19  // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  //go:build darwin
    23  // +build darwin
    24  
    25  package binary_info
    26  
    27  import (
    28  	"debug/macho"
    29  	"errors"
    30  	"sync"
    31  
    32  	"github.com/Rookout/GoSDK/pkg/logger"
    33  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/frame"
    34  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/godwarf"
    35  	"github.com/Rookout/GoSDK/pkg/utils"
    36  )
    37  
    38  type archID = macho.Cpu
    39  type File = macho.File
    40  
    41  var supportedArchs = map[macho.Cpu]interface{}{
    42  	macho.CpuAmd64: nil,
    43  	macho.CpuArm64: nil,
    44  }
    45  
    46  const crosscall2SPOffset = 0x58
    47  
    48  
    49  
    50  func loadBinaryInfo(bi *BinaryInfo, image *Image, path string, entryPoint uint64) error {
    51  	exe, err := macho.Open(path)
    52  	if err != nil {
    53  		return err
    54  	}
    55  	if entryPoint != 0 {
    56  		
    57  		
    58  		
    59  		
    60  		image.StaticBase = entryPoint - 0x100000000
    61  	}
    62  	image.closer = exe
    63  	if !isSupportedArch(exe.Cpu) {
    64  		return errors.New("unsupported darwin arch")
    65  	}
    66  	image.Dwarf, err = exe.DWARF()
    67  	if err != nil {
    68  		return err
    69  	}
    70  	debugInfoBytes, err := GetDebugSection(exe, "info")
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	debugLineBytes, err := GetDebugSection(exe, "line")
    76  	if err != nil {
    77  		return err
    78  	}
    79  	bi.debugLocBytes, _ = GetDebugSection(exe, "loc")
    80  	bi.debugLoclistBytes, _ = GetDebugSection(exe, "loclists")
    81  	debugAddrBytes, _ := GetDebugSection(exe, "addr")
    82  	image.debugAddr = godwarf.ParseAddr(debugAddrBytes)
    83  	debugLineStrBytes, _ := GetDebugSection(exe, "line_str")
    84  	image.debugLineStr = debugLineStrBytes
    85  
    86  	wg := &sync.WaitGroup{}
    87  	wg.Add(2)
    88  	utils.CreateGoroutine(func() {
    89  		defer wg.Done()
    90  		err = bi.parseDebugFrame(image, exe, debugInfoBytes)
    91  		if err != nil {
    92  			logger.Logger().WithError(err).Error("Failed to parse debug frame")
    93  		}
    94  	})
    95  	utils.CreateGoroutine(func() {
    96  		defer wg.Done()
    97  		err = bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes)
    98  		if err != nil {
    99  			logger.Logger().WithError(err).Error("Failed to load debug info maps")
   100  		}
   101  	})
   102  	wg.Wait()
   103  	bi.macOSDebugFrameBugWorkaround()
   104  	return nil
   105  }
   106  
   107  func getSectionName(section string) string {
   108  	return "__debug_" + section
   109  }
   110  
   111  func getCompressedSectionName(section string) string {
   112  	return "__zdebug_" + section
   113  }
   114  
   115  func getEhFrameSection(f *macho.File) *macho.Section {
   116  	return f.Section("__eh_frame")
   117  }
   118  
   119  
   120  
   121  
   122  
   123  
   124  
   125  
   126  
   127  
   128  
   129  
   130  
   131  
   132  
   133  
   134  
   135  
   136  
   137  
   138  
   139  func (bi *BinaryInfo) macOSDebugFrameBugWorkaround() {
   140  	if len(bi.Images) > 1 {
   141  		
   142  		
   143  		
   144  		return
   145  	}
   146  
   147  	
   148  	var fn *Function
   149  	for i := range bi.Functions {
   150  		if bi.Functions[i].cu.IsGo && bi.Functions[i].Entry > 0 {
   151  			fn = &bi.Functions[i]
   152  			break
   153  		}
   154  	}
   155  	if fn == nil {
   156  		
   157  		return
   158  	}
   159  
   160  	if fde, _ := bi.FrameEntries.FDEForPC(fn.Entry); fde != nil {
   161  		
   162  		
   163  		return
   164  	}
   165  
   166  	
   167  	var fde *frame.FrameDescriptionEntry
   168  	for i := range bi.FrameEntries {
   169  		if bi.FrameEntries[i].CIE.CIE_id == ^uint32(0) {
   170  			fde = bi.FrameEntries[i]
   171  			break
   172  		}
   173  	}
   174  
   175  	if fde == nil {
   176  		
   177  		return
   178  	}
   179  
   180  	fnsize := fn.End - fn.Entry
   181  
   182  	if fde.End()-fde.Begin() != fnsize || fde.Begin() > fn.Entry {
   183  		
   184  		return
   185  	}
   186  
   187  	delta := fn.Entry - fde.Begin()
   188  
   189  	
   190  
   191  	for i := range bi.FrameEntries {
   192  		if bi.FrameEntries[i].CIE.CIE_id == ^uint32(0) {
   193  			bi.FrameEntries[i].Translate(delta)
   194  		}
   195  	}
   196  }