live_stack

package module
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2025 License: MIT Imports: 9 Imported by: 0

README

go-live-stack

go-live-stack offers tools to resolve the stack trace of running Linux process, given the instruction pointers.

It leverages both the /proc/pid/maps and the ELF file format to resolve the symbols that the instruction pointers reference. The ELF files must not be stripped of their symbol tables.

Why we need this

The Linux loader uses Address Space Layout Randomization (ASLR) to map the different sections of an executable at random addresses in the virtual memory. This means that the addresses of functions and variables are not fixed, and they change every time the program is run. Thus resolving the symbol that contain a certain memory address involves taking into account the processes memory layout.

You can obtain this information using gdb using the following command:

(gdb) info proc mappings

However, for programmatic use, you need to implement it yourself or use something like go-live-stack.

Personally, I use it to resolve stacks that I collect using EBPF probes.

Usage

Build a process context:

ctx, err := NewProcessContext(pid)
if err != nil {
  // handle error
}

Resolve the stack trace:

frames := ctx.GetStackTrace(addresses)

Contributing and improving

The interface to the library is simple, intuitive, and probably subject to changes. Feel free to open an issue or a pull request for any improvements.

License

Licensed under the MIT License.

Documentation

Index

Constants

View Source
const (
	READ    = 1
	WRITE   = 2
	EXECUTE = 4
	SHARED  = 8
	PRIVATE = 16
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ElfContext

type ElfContext struct {
	// The path of the ELF file
	Pathname string
	// The ELF file handle
	File *elf.File
	// The complete symbol table, sorted by FileOffset
	Symbols []Symbol
}

A parsed ELF file

func NewElfContext

func NewElfContext(pathname string) (ElfContext, error)

Parse an ELF file

func (*ElfContext) GetSection

func (ctx *ElfContext) GetSection(idx elf.SectionIndex) *elf.Section

Fetch a section from an ELF file, based on the section index

func (*ElfContext) GetSymbol

func (ctx *ElfContext) GetSymbol(offset uint64) (*Symbol, error)

Fetch a symbol from an ELF file, based on the file offset

type MappedRegion

type MappedRegion struct {
	// Start of the virtual memory region
	Start uint64
	// End of the virtual memory region
	End uint64
	// Permissions of the memory region; can be a combination of READ, WRITE, EXECUTE and zero or one of SHARED or PRIVATE
	Permissions Permissions
	// Offset in the associated file
	Offset uint64
	// The device where the associated file is stored
	Device string
	// The inode associated with the mapped file
	Inode uint64
	// The full path to the mapped file, or the memory segment like [stack], [heap], etc.
	Pathname string
	// Whether Pathname points to a file
	IsFile bool
}

Each MappedRegion corresponds to a single line in /proc/<pid>/maps. It describes a memory area mapped into the process's virtual memory space.

func (*MappedRegion) IsExecutable

func (region *MappedRegion) IsExecutable() bool

Check if the memory is executable

func (*MappedRegion) IsExecutableFile

func (region *MappedRegion) IsExecutableFile() bool

Check if it's mapped from a file and executable

func (*MappedRegion) Size

func (region *MappedRegion) Size() uint64

The size of the memory region

func (*MappedRegion) String

func (region *MappedRegion) String() string

type Permissions

type Permissions uint32

func (Permissions) String

func (perm Permissions) String() string

type ProcessContext

type ProcessContext struct {
	// The process id
	Pid int

	// Mapped regions from /proc/<pid>/maps
	Regions []MappedRegion

	// The parsed ELF files for the executable and shared libraries
	Elfs map[string]ElfContext
}

A wrapper objects around the data on a running process and it's consituend ELF binaries

func NewProcessContext

func NewProcessContext(pid int) (ProcessContext, error)

Create a ProcessContext for a running process

func (*ProcessContext) GetStackTrace

func (ctx *ProcessContext) GetStackTrace(stack []uint64) []StackFrame

Resolve a stack trace from a running process, given the list of instruction pointers on the stack

func (*ProcessContext) ResolveFrame

func (ctx *ProcessContext) ResolveFrame(ip uint64) StackFrame

Resolve a StackFrame from a running process, based on the instruction pointer

func (*ProcessContext) String

func (ctx *ProcessContext) String() string

type StackFrame

type StackFrame struct {
	// The instruction pointer in the running process's memory
	InstructionPointer uint64
	// The resolved symbol
	Symbol *Symbol
	// The offset inside the symbol
	Offset uint64
	// The mapped region where this address resides
	Region *MappedRegion
	// The error, if resolving the symbol failed
	Error error
}

A StackFrame, possibly resolved

func (*StackFrame) Describe

func (frame *StackFrame) Describe(idx int) string

func (*StackFrame) IsNull added in v0.1.3

func (frame *StackFrame) IsNull() bool

type Symbol

type Symbol struct {
	// The original ELF-file symbol in the symbol table
	elf.Symbol
	// The offset inside the file where this symbol resides
	FileOffset uint64
}

All the information related to a symbol from the symbol table of an ELF file

Directories

Path Synopsis
examples
print_symbols command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL