Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fails with shared libraries because mapping is ignored on OSX #311

Closed
Timmmm opened this issue Feb 5, 2018 · 2 comments
Closed

Fails with shared libraries because mapping is ignored on OSX #311

Timmmm opened this issue Feb 5, 2018 · 2 comments

Comments

@Timmmm
Copy link
Contributor

Timmmm commented Feb 5, 2018

See this issue for background and test case.

Basically on OSX pprof does not subtract the mapped base address of shared libraries from code addresses before feeding them to llvm-symbolizer.

I don't know exactly how it is supposed to work, but replacing this line with this seems to make it work:

		addr := l.Address
		if l.Mapping != nil {
			addr -= l.Mapping.Start
		}

		stack, err := segment.SourceLine(addr)

Also, for some very strange reason, with this patch, -web, -top and -list '.*' work but -weblist '.*' does not. However -weblist 'factorial' does work. It seems like the web interface trips up on the first ?? output:

$ pprof -list ".*" out.prof
Local symbolization failed for libdyld.dylib: unrecognized binary: /usr/lib/system/libdyld.dylib
Some binary filenames not available. Symbolization may be incomplete.
Try setting PPROF_BINARY_PATH to the search path for local binaries.
Total: 690ms
ROUTINE ========================  in ??
         0      690ms (flat, cum)   100% of Total
 Error: Could not find file ?? on path /Users/me/test
ROUTINE ======================== factorial in /Users/me/test/lib.cpp
     690ms      690ms (flat, cum)   100% of Total
         .          .      3:    long long int result=m_nValue;
         .          .      4:    long long int result_next;
         .          .      5:    long long int pc = m_nValue;
         .          .      6:    do
         .          .      7:    {
     310ms      310ms      8:        result_next = result*(pc-1);
     250ms      250ms      9:        result = result_next;
      60ms       60ms     10:        pc--;
      70ms       70ms     11:    } while(pc>2);
         .          .     12:    m_nValue = result;
         .          .     13:    return m_nValue;
         .          .     14:}
         .          .     15:
         .          .     16:int foo() {
@Timmmm
Copy link
Contributor Author

Timmmm commented Feb 6, 2018

Actually this fix is not correct - there is already a mechanism for subtracting base addresses but it isn't used on OSX! On OSX all the symbols in a library start at 0, but all the symbols in an executable start at 0x100000000. This number comes from the vmaddr of the __TEXT segment load command, as shown by objdump -private-headers <file>. It should read by openMachO() and assigned to base, but weirdly openMachO() just opens the file and closes it again. I guess the code was never finished.

Here is the fixed code (instead of the above Mapping change):

// Base address of the __TEXT section. Usually 0 for shared libraries
// of 0x100000000 for executables.
func getTextAddress(of *macho.File) uint64 {
	for _, ld := range of.Loads {
		switch s := ld.(type) {
		case *macho.Segment:
			if s.Name == "__TEXT" {
				return s.Addr
			}
		}
	}
	return 0
}

func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
	of, err := macho.Open(name)
	if err != nil {
		return nil, fmt.Errorf("Parsing %s: %v", name, err)
	}
	defer of.Close()

	base := start - getTextAddress(of)

	if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
		return &fileNM{file: file{b: b, name: name, base: base}}, nil
	}
	return &fileAddr2Line{file: file{b: b, name: name, base: base}}, nil
}

With both of these fixes it works for shared libraries and in the executable, with PIE and ASLR enabled.

Timmmm added a commit to Timmmm/pprof that referenced this issue Feb 6, 2018
This fixes issue google#311. The mapped address of libraries was never considered, nor was the load address of the segments.
@aalexand
Copy link
Collaborator

aalexand commented Feb 6, 2018

Huh, thanks a lot for tracking this down, this makes a lot of sense. I think your fix will also help a number of cases people had in #130 - some of symbolization issues mentioned there are with dynamic libraries and some could have been because of executable's ASLR.

aalexand pushed a commit that referenced this issue Feb 9, 2018
Set base address on OSX.

This fixes issue #311. The mapped address of libraries was never considered, nor was the load address of the segments. It also fixes a couple of issues in binutils.go, such as when the tail of the data wasn't handled right when grouping symbols at the same address.
lannadorai pushed a commit to lannadorai/pprof that referenced this issue Feb 13, 2018
Set base address on OSX.

This fixes issue google#311. The mapped address of libraries was never considered, nor was the load address of the segments. It also fixes a couple of issues in binutils.go, such as when the tail of the data wasn't handled right when grouping symbols at the same address.
gmarin13 pushed a commit to gmarin13/pprof that referenced this issue Dec 17, 2020
Set base address on OSX.

This fixes issue google#311. The mapped address of libraries was never considered, nor was the load address of the segments. It also fixes a couple of issues in binutils.go, such as when the tail of the data wasn't handled right when grouping symbols at the same address.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants