MCPcopy Create free account
hub / github.com/google/pprof / GetBase

Function GetBase

internal/elfexec/elfexec.go:216–283  ·  view source on GitHub ↗

GetBase determines the base address to subtract from virtual address to get symbol table address. For an executable, the base is 0. Otherwise, it's a shared library, and the base is the address where the mapping starts. The kernel needs special handling.

(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint64, start, limit, offset uint64)

Source from the content-addressed store, hash-verified

214// is 0. Otherwise, it's a shared library, and the base is the
215// address where the mapping starts. The kernel needs special handling.
216func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint64, start, limit, offset uint64) (uint64, error) {
217
218 if start == 0 && offset == 0 && (limit == ^uint64(0) || limit == 0) {
219 // Some tools may introduce a fake mapping that spans the entire
220 // address space. Assume that the address has already been
221 // adjusted, so no additional base adjustment is necessary.
222 return 0, nil
223 }
224
225 switch fh.Type {
226 case elf.ET_EXEC:
227 if loadSegment == nil {
228 // Assume fixed-address executable and so no adjustment.
229 return 0, nil
230 }
231 if stextOffset == nil && start > 0 && start < 0x8000000000000000 {
232 // A regular user-mode executable. Compute the base offset using same
233 // arithmetic as in ET_DYN case below, see the explanation there.
234 // Ideally, the condition would just be "stextOffset == nil" as that
235 // represents the address of _stext symbol in the vmlinux image. Alas,
236 // the caller may skip reading it from the binary (it's expensive to scan
237 // all the symbols) and so it may be nil even for the kernel executable.
238 // So additionally check that the start is within the user-mode half of
239 // the 64-bit address space.
240 return start - offset + loadSegment.Off - loadSegment.Vaddr, nil
241 }
242 // Various kernel heuristics and cases are handled separately.
243 if base, match := kernelBase(loadSegment, stextOffset, start, limit, offset); match {
244 return base, nil
245 }
246 // ChromeOS can remap its kernel to 0, and the caller might have not found
247 // the _stext symbol. Split this case from kernelBase() above, since we don't
248 // want to apply it to an ET_DYN user-mode executable.
249 if start == 0 && limit != 0 && stextOffset == nil {
250 return start - loadSegment.Vaddr, nil
251 }
252
253 return 0, fmt.Errorf("don't know how to handle EXEC segment: %v start=0x%x limit=0x%x offset=0x%x", *loadSegment, start, limit, offset)
254 case elf.ET_REL:
255 if offset != 0 {
256 return 0, fmt.Errorf("don't know how to handle mapping.Offset")
257 }
258 return start, nil
259 case elf.ET_DYN:
260 // The process mapping information, start = start of virtual address range,
261 // and offset = offset in the executable file of the start address, tells us
262 // that a runtime virtual address x maps to a file offset
263 // fx = x - start + offset.
264 if loadSegment == nil {
265 return start - offset, nil
266 }
267 // Kernels compiled as PIE can be ET_DYN as well. Use heuristic, similar to
268 // the ET_EXEC case above.
269 if base, match := kernelBase(loadSegment, stextOffset, start, limit, offset); match {
270 return base, nil
271 }
272 // The program header, if not nil, indicates the offset in the file where
273 // the executable segment is located (loadSegment.Off), and the base virtual

Callers 3

openELFMethod · 0.92
computeBaseMethod · 0.92
TestGetBaseFunction · 0.85

Calls 1

kernelBaseFunction · 0.85

Tested by 1

TestGetBaseFunction · 0.68

Used in the wild real call sites across dependent graphs

searching dependent graphs…