Linuxリアルタイム組み込みアプリのソフトウェアクラッシュをデバッグする方法

どんなソフトウェアにもクラッシュはつきものです。厳密なソフトウェア品質保証プラクティスのもとでコード分析ツールを使って徹底的なコード確認を行なっても、ソフトウェアクラッシュは起こり得ます。クラッシュが起きた場合、コードのバグを修正するためにはクラッシュに関わる詳細情報をできるだけ多く収集したいところです。

クラッシュ発生後に入手できる最も有用な情報として、スタックトレースが挙げられます。スタックトレース自身に不備がなければ、スタックトレースはクラッシュの発生元であるコード行を識別できます。しかし、スタックトレースやその他事後データの取得プロセスは、組み込みドメインに移行するにつれてますます困難になります。 シェルターミナル、モニタ、キーボード、デバッガ(例:gdb)にアクセスできない場合があり、組み込み環境におけるデバッグ作業の工数が大幅に増えるのです。

この記事では、Linuxのリアルタイム組み込みアプリケーションでクラッシュが起きた際に、簡単に実施できるデバッグ方法をお伝えします。

f:id:PSYGIG:20190709135431j:plain

目次

  • プログラムの実行状態をキャプチャする「スタックトレース」とは
  • スタックトレースを取得するには
  • 無料便利ツール「psymon」とは?
  • psymonの無料ダウンロード・インストールはこちら
  • psymonでクラッシュをデバッグする方法
  • psymonを使用する上での詳細ガイド

プログラムの実行状態をキャプチャする「スタックトレース」とは

スタックトレースは、プログラム実行中の任意の時点におけるプログラムの実行状態をキャプチャします。アプリケーションがクラッシュする前の時点のスタックトレースを取得できれば、クラッシュの発生元である正確なコード行を特定できます。もし正確なコード行を特定できなくても、不具合があった特定のモジュールを特定することで、より小さなコードのサブセットに絞ってクラッシュの原因解明に集中することができます。

スタックトレースの例は次の通りです。

#1 0x0000000000400fee in crash () at ./test.c:10

#2 0x000000000040105d in foo1 () at ./test.c:17

#3 0x000000000040102e in foo2 () at ./test.c:21

#4 0x000000000040102e in foo3 () at ./test.c:25

#5 0x000000000040102e in foo4 () at ./test.c:29

#6 0x00000000004010cb in main (argc=2, argv=0x7fffffffe1f8) at ./test.c:40

プログラムがデバッグ情報とともにコンパイルされたかどうかによって、スタックトレースは特定の関数名、ソースファイル、そして行番号を含むことがあります。

スタックトレースを取得するには

スタックトレースを収集することの重要性を理解いただけたところで、実際にクラッシュが起きた際にどのようにスタックトレースを取得すればいいのかについてご説明します。多くの場合、プログラムのクラッシュ時には下記のような不可解なエラーメッセージが表示されます。

./test Segmentation fault (core dumped)

OSによっては、クラッシュ後に大きなコアダンプファイルが自動的に生成されることがあります。このファイルには、スタックトレースを始めとするデータが含まれています。 しかし、多くの場合、組み込み機器には限られた容量の記憶スペースしかなく、そのようなデータを保存することができません。

そこで、スタックトレースおよびその他関連データを含む簡易クラッシュレポートを取得するための方法をご紹介します。

  1. クラッシュ発生直前に簡易クラッシュレポートを保存するシグナルハンドラをプログラムにインストールする
  2. クラッシュ発生後に自動実行されるカスタムコアダンプハンドラをインストールする

このような組み込みアプリケーション用の簡易クラッシュレポートを収集するために開発されたpsymonと呼ばれる簡易ツールがあります。psymonでプログラムを実行すると、自動でシグナルハンドラをインストール(上記1)、オプションでコアダンプハンドラをインストール(上記2)することで、クラッシュレポートを生成してくれます。

無料便利ツール「psymon」とは?

psymonはUNIXベースのコマンドラインプログラムで、あらゆるプログラムにクラッシュレポート生成機能を追加してくれます。たとえば、次のコマンドを実行します。

psymon --crash [command-to-run-our-program]

psymon --crashから始まるコマンドを実行すると、プログラムの実行中にクラッシュが起きた際、簡易クラッシュレポートを自動生成してくれます。

psymonの無料ダウンロード・インストールはこちら

psymonの無料最新版は下記のリンクからダウンロードできます:

https://bintray.com/psygig/releases/psyiage

詳しいインストール方法は上記リンク内の「Readme」をご覧ください。

psymonでクラッシュをデバッグする方法

psymonを使えば、コマンドの前にpsymon --crashを追加するだけで、簡単に組み込みアプリケーションにクラッシュレポート生成機能を拡張することができます。

psymon --crash [command-to-run-our-program]

上記のプログラムを実行すると、プログラムがクラッシュする直前にO/Sによって送られた致命的なシグナルを受信するためにシグナルハンドラがインストールされます。シグナルハンドラは、スタックトレースに加えて、プログラムの実行状態(スレッド、レジスタ、メモリマップ)も収集し、人間が理解できるJSON形式で保存してくれます。

The following is an example of a crash report generated after a program illegally access memory space a process is not allowed to access.

下記は、プログラムがアクセスを許可されていないメモリ空間に不正アクセスした後に生成されるクラッシュレポートの例です。

{
"TaskInfo": {
"ProcID": 23066,
"UserID": 1000,
"GroupID": 1000,
"Cmdline": "/opt/psygig/psyiage/sample/bin/crash_report",
"Name": "crash_report",
"Signal": 11
},
"CrashInfo": {
"ThreadId": 23066,
"Exception": "Segmentation fault",
"StackTrace": {
"Frames": [
{
"FrameNum": 0,
"InstrAddr": "0x00000000004009e0",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "crash",
"Offset": "0x0",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d18",
"rip": "0x00000000004009e0",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 1,
"InstrAddr": "0x00000000004009f7",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "foo4",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d20",
"rip": "0x00000000004009f7",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 2,
"InstrAddr": "0x0000000000400a07",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "foo3",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d28",
"rip": "0x0000000000400a07",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 3,
"InstrAddr": "0x0000000000400a17",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "foo2",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d30",
"rip": "0x0000000000400a17",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 4,
"InstrAddr": "0x0000000000400a27",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "induce_segfault",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d38",
"rip": "0x0000000000400a27",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 5,
"InstrAddr": "0x00000000004008a3",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "main",
"Offset": "0xb3",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d40",
"rip": "0x00000000004008a3",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 6,
"InstrAddr": "0x00007f6372948830",
"FilePath": "/lib/x86_64-linux-gnu/libc.so.6",
"Function": "_libc_start_main",
"Offset": "0xf0",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d60",
"rip": "0x00007f6372948830",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000" },
},
{
"FrameNum": 7,
"InstrAddr": "0x0000000000400909",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "
start",
"Offset": "0x29",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000000000",
"rsp": "0x00007ffced711e20",
"rip": "0x0000000000400909",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
]
},
}
}

スタックの先頭を見ると、クラッシュは関数crash()によって引き起こされているように見えます。

"FrameNum": 0, "InstrAddr": "0x00000000004009e0", "FilePath": "/opt/psygig/psyiage/sample/bin/crash_report", "Function": "crash",

ソースコードを見てプログラムのバグを識別してみましょう。

int crash() { char * p = NULL; *p = 0; return 0; }

上記の例からは、アクセス許可のないメモリアドレス0x0に書き込もうとしている箇所がバグだと識別することができます。

psymonを使用する上での詳細ガイド

  • リソースの監視以外にも、psymonには下記の便利機能があります。
  • コードプロファイリング
  • クラッシュレポート
  • ログ監視
  • システム情報収集
  • アラート報告

上記で紹介した機能に加えて、psymonは組み込みアプリケーションの品質と安定性を向上するための便利機能を備えています。詳しい機能内容については、psymon公式ページ(https://bintray.com/psygig/releases/psyiage#)をご覧ください。


この記事を書いた人|キース
アイスホッケーとお笑いをこよなく愛するみんなのムードメーカー、キース。サイギグの共同創業者兼チーフエンジニア。カナダ・バンクーバー出身。カナダの名門ブリティッシュコロンビア大学卒。SonyPlayStationのハード/ソフト開発をリードしてきた組み込みエンジニア。カナダ出身なだけあって、平日の夜はアイスホッケーを楽しむスポーツマン。一時期ブルゾンちえみにハマっていた。プライベートは謎に包まれていることが多いため、最近の生態(マイブーム)は誰も知らない。

[English Below]

Debugging software crashes in your real-time, embedded applications in Linux

Software crashes are largely unavoidable, and can occur despite implementing strict software quality assurance practices, conducting thorough code reviews and running a suite of code analysis tools. In such cases, we want to gather as much detail about the crash as possible, in order to fix the bug in the code.

One of the most useful information that can be obtained after a crash has occurred is the stack trace. The stack trace, if complete, can identify the exact line of code where the crash occurred.

However, the process of obtaining the stack trace and other post-mortem data is increasingly difficult as we move further into the embedded domain. We may not have access to a shell terminal, monitor, keyboard, debugger (eg. gdb). The debugging effort required increases significantly within an embedded environment.

What is a stack trace?

A stack trace captures the execution state of a program at any point of its lifetime. If we can obtain a stack trace at the point before the application crashes, at best we can identify the exact line of code where the failure occurred. At worst, we can still isolate the specific module that failed and focus our efforts on a smaller subset of code.

An example of a stack trace is as follows

#1 0x0000000000400fee in crash () at ./test.c:10

#2 0x000000000040105d in foo1 () at ./test.c:17

#3 0x000000000040102e in foo2 () at ./test.c:21

#4 0x000000000040102e in foo3 () at ./test.c:25

#5 0x000000000040102e in foo4 () at ./test.c:29

#6 0x00000000004010cb in main (argc=2, argv=0x7fffffffe1f8) at ./test.c:40

Depending on whether our program was compiled with debug information, the stack trace may contain the specific function names, source files, and line numbers.

How to get a stack trace

Now that we understand the importance of gathering a stack trace, we need to figure out how to obtain one after a crash. More often than not, a program will crash with a cryptic error message such as the following:

./test Segmentation fault (core dumped)

Depending on the operating system, it may automatically generate a large core dump file after a crash, which will contain a stack trace among other data. In many cases, however, there is a limited amount of storage space on an embedded device making it infeasible to store such data.

There are several options to get a minimal crash report, which contains a stack trace along with other relevant data. Install a signal handler in our program that will save a minimal crash report just before the crash occurs Install a custom core dump handler that automatically runs after a program crashes

There is a lightweight tool called psymon developed for collecting a minimal crash report for such embedded applications. Running any program with psymon automatically installs a signal handler (1) and optionally a core dump handler (2) for generating a crash report.

What is psymon?

psymon is a UNIX-based command line program that extends any program with crash report generation capability. For example, we would run the following command:

psymon --crash [command-to-run-our-program]

Running our command prefixed with psymon --crash will automatically trigger a generation of a minimal crash report if our program crashes during any point of its execution.

Downloading and installing psymon

psymon is a free tool that you can get the latest version here:

https://bintray.com/psygig/releases/psyiage

Follow the instructions in the Readme to install.

Example of using psymon to debug crashes

Extending our embedded applications with crash report generation is simple, as all we need to do is prepend the command with psymon --crash

psymon --crash [command-to-run-our-program]

When our program is run in this manner, a signal handler shall be installed to capture fatal signals sent by the O/S just before a program crashes. The signal handler will collect a stack trace, as well as the program’s execution state (threads, registers, memory map) and store in a human-readable JSON format.

The following is an example of a crash report generated after a program illegally access memory space a process is not allowed to access.

{
"TaskInfo": {
"ProcID": 23066,
"UserID": 1000,
"GroupID": 1000,
"Cmdline": "/opt/psygig/psyiage/sample/bin/crash_report",
"Name": "crash_report",
"Signal": 11
},
"CrashInfo": {
"ThreadId": 23066,
"Exception": "Segmentation fault",
"StackTrace": {
"Frames": [
{
"FrameNum": 0,
"InstrAddr": "0x00000000004009e0",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "crash",
"Offset": "0x0",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d18",
"rip": "0x00000000004009e0",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 1,
"InstrAddr": "0x00000000004009f7",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "foo4",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d20",
"rip": "0x00000000004009f7",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 2,
"InstrAddr": "0x0000000000400a07",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "foo3",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d28",
"rip": "0x0000000000400a07",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 3,
"InstrAddr": "0x0000000000400a17",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "foo2",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d30",
"rip": "0x0000000000400a17",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 4,
"InstrAddr": "0x0000000000400a27",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "induce_segfault",
"Offset": "0x7",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d38",
"rip": "0x0000000000400a27",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 5,
"InstrAddr": "0x00000000004008a3",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "main",
"Offset": "0xb3",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d40",
"rip": "0x00000000004008a3",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
{
"FrameNum": 6,
"InstrAddr": "0x00007f6372948830",
"FilePath": "/lib/x86_64-linux-gnu/libc.so.6",
"Function": "_libc_start_main",
"Offset": "0xf0",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000400a30",
"rsp": "0x00007ffced711d60",
"rip": "0x00007f6372948830",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000" },
},
{
"FrameNum": 7,
"InstrAddr": "0x0000000000400909",
"FilePath": "/opt/psygig/psyiage/sample/bin/crash_report",
"Function": "
start",
"Offset": "0x29",
"Registers": {
"rax": "0x0000000000000000",
"rbx": "0x0000000000000000",
"rcx": "0x00007f6372a1f2c0",
"rdx": "0x00007f6372cee780",
"rsi": "0x0000000002351010",
"rdi": "0x0000000000000001",
"rbp": "0x0000000000000000",
"rsp": "0x00007ffced711e20",
"rip": "0x0000000000400909",
"r8": "0x2e2e2e676e697473",
"r9": "0x6166206e6f697461",
"r10": "0x20726f6620746c75",
"r11": "0x0000000000000246",
"r12": "0x00000000004008e0",
"r13": "0x00007ffced711e30",
"r14": "0x0000000000000000",
"r15": "0x0000000000000000"
},
},
]
},
}
}

Looking at the top of the stack, the crash appears to be caused by a function crash()

"FrameNum": 0, "InstrAddr": "0x00000000004009e0", "FilePath": "/opt/psygig/psyiage/sample/bin/crash_report", "Function": "crash",

Looking at our source code, we can identify the bug in our program

int crash() { char * p = NULL; *p = 0; return 0; }

We can identify the trivial bug in our program which is attempting to write to memory address 0x0, which the process is not permitted to access.

Advanced instrumentation using psymon

Other than crash reporting, psymon includes other instrumentation features such as:

  • Code profiling
  • Metrics monitoring
  • Log monitoring
  • System information collection
  • Alert reporting

Take a look at the official psymon documentation page to see if any other the instrumentation features would be beneficial to improving the quality and robustness of your embedded applications.