Ruby のメソッドと C の関数のスタックトレースを統合して取得するライブラリです。 デバッグ時に C のスタックトレースと mruby VM のスタックトレースを別の紙に印刷して隣に並べる必要はありません。
- 現時点での目的は技術実証です。
- バイナリファイルにデバッグ情報やダイナミックシンボルテーブルが必要です。
- デバッガ (
GDBやLLDB) のプロンプトから呼び出しても、正しい結果は取得できません。 libboostを使う場合は、最低でも C++11 が必要です。- 😿 デバッグ情報やダイナミックシンボルテーブルがあっても、C と Ruby のスタックの同期がずれる可能性があります。
- C API
#include <mruby-stacktrace.h>mrb_value mruby_stacktrace(mrb_state *mrb)void mruby_stacktrace_print(mrb_state *mrb)void mruby_stacktrace_foreach(mrb_state *mrb, mruby_stacktrace_report_func *report, void *opaque)
- Ruby API
Kernel#stacktrace
あなたのビルド設定ファイルに追加し、libmruby をビルドして下さい。 ライブラリの自動検出に頼ることができます。 ただしデバッグセクションあるいはダイナミックシンボルテーブルの出力を行う必要があります。
GCC/Clang 互換コンパイラの場合の例を次に示します。
MRuby::Build.new do |conf|
...
compilers.each { |cc| cc.flags << "-g" } # デバッグ情報を出力する
linker.flags << "-rdynamic" # ダイナミックシンボルテーブルを出力する
#linker.flags << "-Wl,--export-dynamic" # -rdynamic と同等
conf.gem "mruby-stacktrace", github: "dearblue/mruby-stacktrace"
end自動検出に失敗したり、特定のライブラリを使いたい場合は #gem メソッドにブロックを与えて指定します。
conf.gem "mruby-stacktrace", github: "dearblue/mruby-stacktrace" do |g|
g.use_libunwind
end現在のところ、指定可能なメソッドと既定値は以下のとおりです:
def gem.use_libbacktrace( libraries: %w(backtrace),
defines: nil,
include_paths: "/usr/local/include",
library_paths: "/usr/local/lib")
def gem.use_boost( libraries: %w(boost_stacktrace_addr2line dl backtrace),
defines: %w(BOOST_STACKTRACE_USE_ADDR2LINE _GNU_SOURCE),
include_paths: "/usr/local/include",
library_paths: "/usr/local/lib")
def gem.use_execinfo( libraries: %w(execinfo),
defines: nil,
include_paths: "/usr/local/include",
library_paths: "/usr/local/lib")
def gem.use_libunwind( libraries: %w(unwind unwind-x86_64),
defines: nil,
include_paths: "/usr/local/include",
library_paths: "/usr/local/lib")自動検出によるライブラリの優先度や設定値については preset-libs.yaml をご確認ください。
Kernel#stacktrace を呼び出すと、スタックトレースを文字列の配列として取得できます。
読み方は、C 関数の場合は「リターンアドレス」、「関数シンボル名 + 相対位置」、「モジュール名、またはソースコードファイル名」です。 Ruby のメソッドの場合は、「ファイバーのニックネーム + コールスタック位置」、「メソッド名」、「ソースコードファイル名」です。
情報が取得できない場合は項目が省略されます。
% bin/mruby -e 'Class.new { Class.new { Fiber.new { -> { puts stacktrace }.call }.resume } }'
0x00000000004d701f mruby_stacktrace build/repos/host/mruby-stacktrace/src/mruby-stacktrace.c:343
0x00000000004d71e8 obj_stacktrace build/repos/host/mruby-stacktrace/src/mruby-stacktrace.c:352
NFRQE+2 stacktrace
NFRQE+1 <n/a> -e:1
NFRQE+0 <n/a> -e:1
JVSYD+5 resume
JVSYD+4 <n/a> -e:1
0x0000000000442bb5 mrb_vm_exec src/vm.c:1909
0x000000000043f5be mrb_vm_run src/vm.c:1331
0x000000000043ddbc mrb_run src/vm.c:3112
0x000000000043f063 mrb_yield_with_class src/vm.c:1034
0x00000000004137d5 mrb_class_initialize src/class.c:2016
0x00000000004135f8 mrb_class_new_class src/class.c:2036
JVSYD+3 new
JVSYD+2 <n/a> -e:1
0x0000000000442bb5 mrb_vm_exec src/vm.c:1909
0x000000000043f5be mrb_vm_run src/vm.c:1331
0x000000000043ddbc mrb_run src/vm.c:3112
0x000000000043f063 mrb_yield_with_class src/vm.c:1034
0x00000000004137d5 mrb_class_initialize src/class.c:2016
0x00000000004135f8 mrb_class_new_class src/class.c:2036
JVSYD+1 new
JVSYD+0 <n/a> -e:1
0x0000000000442bb5 mrb_vm_exec src/vm.c:1909
0x000000000043f5be mrb_vm_run src/vm.c:1331
0x000000000043e41f mrb_top_run src/vm.c:3121
0x0000000000463fce mrb_load_exec mrbgems/mruby-compiler/core/parse.y:6919
0x0000000000464504 mrb_load_nstring_cxt mrbgems/mruby-compiler/core/parse.y:6991
0x00000000004645a0 mrb_load_string_cxt mrbgems/mruby-compiler/core/parse.y:7003
0x00000000004045ec main mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:358
0x000000082473daf9 (???)
0x000000000040406f (???) /usr/src/lib/csu/amd64/crt1_s.S:83- C++でスタックトレース(関数コール履歴)の取得 - An Embedded Engineer’s Blog
https://an-embedded-engineer.hateblo.jp/entry/2020/08/24/212511 - c++ - How to print a stack trace whenever a certain function is called - Stack Overflow
https://stackoverflow.com/a/54365144 - [Linux][C/C++] backtrace取得方法まとめ #Linux - Qiita
https://qiita.com/koara-local/items/012b917111a96f76d27c
- Package name: mruby-stacktrace
- Version: 0.1
- Project status: CONCEPT
- Author: dearblue
- Project page: https://github.com/dearblue/mruby-stacktrace
- Licensing: Creative Commons Zero License (CC0 / Public Domain)
- Dependency external mrbgems: (NONE)
- Bundled C libraries (git-submodules): (NONE)
- Dependency external libraries:
- boost (with C++ or
gem.use_boost) under Boost Software License - libbacktrace (with
gem.use_libbacktrace) under 3 clause BSD License - libexecinfo (with
gem.use_execinfo) under 2 clause BSD License - libunwind (with
gem.use_libunwind) under MIT License
- boost (with C++ or