Тип runtime.Frame

Тип runtime.Frame представляет собой структуру, содержащую информацию об одном фрейме в стеке вызовов программы. Он используется в низкоуровневых операциях для анализа стека, отладки и профилирования. Основные поля структуры включают: PC (программный счетчик), Func (указатель на функцию), Function (имя функции), File (путь к файлу с исходным кодом) и Line (номер строки в файле).

Синтаксис

gotype Frame struct {
  PC     uintptr
  Func   *Func
  Function string
  File   string
  Line   int
  Entry  uintptr
}

Пример

Давайте получим информацию о текущем фрейме стека с помощью функции runtime.Caller:

gopackage main

import (
  "fmt"
  "runtime"
)

func main() {
  pc, file, line, ok := runtime.Caller(0)
  if ok {
    fn := runtime.FuncForPC(pc)
    if fn != nil {
      frame := runtime.Frame{
        PC:     pc,
        Func:   fn,
        Function: fn.Name(),
        File:   file,
        Line:   line,
        Entry:  fn.Entry(),
      }
      fmt.Printf("Function: %s\n", frame.Function)
      fmt.Printf("File: %s\n", frame.File)
      fmt.Printf("Line: %d\n", frame.Line)
    }
  }
}

Результат выполнения кода:

go"Function: main.main"
"File: /path/to/main.go"
"Line: 10"

Пример

Давайте получим все фреймы стека с помощью функции runtime.Callers и итератора runtime.Frames:

gopackage main

import (
  "fmt"
  "runtime"
)

func main() {
  callers := make([]uintptr, 10)
  n := runtime.Callers(0, callers)
  frames := runtime.CallersFrames(callers[:n])

  for {
    frame, more := frames.Next()
    if !more {
      break
    }
    fmt.Printf("Function: %s\n", frame.Function)
    fmt.Printf("File: %s\n", frame.File)
    fmt.Printf("Line: %d\n", frame.Line)
    fmt.Println("---")
  }
}

Результат выполнения кода:

go"Function: runtime.Callers"
"File: /usr/local/go/src/runtime/..."
"Line: 123"
"---"
"Function: main.main"
"File: /path/to/main.go"
"Line: 10"
"---"

Пример

Давайте создадим функцию для получения фрейма на определенной глубине стека:

gopackage main

import (
  "fmt"
  "runtime"
)

func getFrame(skip int) runtime.Frame {
  pc, file, line, ok := runtime.Caller(skip)
  if !ok {
    return runtime.Frame{}
  }
  fn := runtime.FuncForPC(pc)
  if fn == nil {
    return runtime.Frame{}
  }
  return runtime.Frame{
    PC:     pc,
    Func:   fn,
    Function: fn.Name(),
    File:   file,
    Line:   line,
    Entry:  fn.Entry(),
  }
}

func main() {
  frame := getFrame(1)
  fmt.Printf("Caller function: %s\n", frame.Function)
  fmt.Printf("Caller file: %s\n", frame.File)
  fmt.Printf("Caller line: %d\n", frame.Line)
}

Результат выполнения кода:

go"Caller function: main.main"
"Caller file: /path/to/main.go"
"Caller line: 25"

Смотрите также

  • функцию runtime.Caller,
    которая возвращает информацию о вызывающем фрейме
  • функцию runtime.Callers,
    которая заполняет срез адресами программных счетчиков
  • тип runtime.Frames,
    который предоставляет итератор по фреймам стека
  • тип runtime.Func,
    который представляет функцию в исполняемом файле