特に大きな(〜10 ^ 6 LOC)プログラムのために私のstty設定がからに変更されましたecho ixon icanon
。-echo -ixon -icanon
私は明らかにこの混乱のOOPスパゲッティコードを介して実行を追跡したくありません。
stty設定を監視し、変更を記録する方法は?strace
私は必要な情報を提供できると思いますawk
が、どのシステムコールをフィルタリングするのかわかりません。
答え1
特定のタスクや対話によってイベントが発生する可能性があると思う場合、最も簡単な方法は次のとおりです。
watch -d -n1 "stty -F /dev/pts/106 -a | grep -Eo '.(icanon|ixon)'"
新しい端末で実行してください。オプションは-F
プログラムを実行する端末です(tty
実行する前に実行してプログラムが何であるかを確認してください)。| grep ..
端末の状態全体を観察するには、省略してください。
Linuxを使用している場合、次のオプションは次のものを使用することです。ltrace
ライブラリ呼び出しのトレースは似ていますがstrace
(一部の機能を含むstrace
)、カーネルシステム呼び出しだけでなくユーザー空間ライブラリでも機能します。
ltrace -tt -e tcgetattr+tcsetattr myprogram ...
tcgetattr()
これにより、ターミナル属性を取得して設定するためのlibc関数と関数のタイムスタンプ呼び出しが表示され、追加されます。tcsetattr()
ioctl()
最終的に、これらのlibc呼び出しは、またはを使用して追跡できるシステム呼び出しを使用します。strace
Linuxでこれを行う方法は次のとおりですtruss
。strace
strace -tt -e trace=ioctl myprogram [...]
ここで大きな利点は、strace
さまざまなパラメータをシステムコールにデコードすることです。
上記のいずれも、プログラムで問題が発生する可能性がある場所を論理的に知らせず、デバッガまたはDLLの挿入という2つのオプションがあります。
簡単にgdb
ブレークポイントを設定しtcsetattr()
てから呼び出しスタックを調べることができますが、呼び出しが多い場合は面倒です。libcのビルドまたはシンボルのデバッグ最良の結果を得るために)。
最も包括的なオプション(ターゲットプログラムが動的にリンクされていると仮定)は、追跡する必要がある機能を傍受またはラップする独自のDLLを挿入することですtcsetattr()
。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <dlfcn.h>
#include <unistd.h>
#include <termios.h>
/*
* gcc -nostartfiles -shared -ldl -Wl,-soname,tcsetattr -o tc.so wraptc.c
* LD_PRELOAD=./tc.so stty -icanon ixon
*
*/
#define DEBUG 1
#define dfprintf(fmt, ...) \
do { if (DEBUG) fprintf(stderr, "[%14s#%04d:%8s()] " fmt, \
__FILE__, __LINE__, __func__, __VA_ARGS__); } while (0)
typedef int tcsetattr_fp(int fd, int optional_actions,
const struct termios *termios_p);
static tcsetattr_fp *real_tcsetattr;
void _init()
{
dfprintf("It's alive!\n","");
real_tcsetattr = dlsym(RTLD_NEXT, "tcsetattr");
dfprintf("Hooked %p tcsetattr()\n",(void *)real_tcsetattr);
}
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
{
void *bt[20];
size_t btsz;
int rc,stacktr=0;
dfprintf("Caught tcsetattr(%i,%04x,...)\n",fd,optional_actions);
if ( (fd==0) && !((termios_p->c_lflag) & ICANON)) {
dfprintf("ICANON off!\n","");
stacktr=1;
}
if ( (fd==0) && !((termios_p->c_iflag) & IXON)) {
dfprintf("IXON off!\n","");
stacktr=1;
}
if (stacktr) {
btsz=backtrace(bt,sizeof(bt));
backtrace_symbols_fd(bt,btsz,STDERR_FILENO);
}
rc=real_tcsetattr(fd,optional_actions, termios_p);
return rc;
}
コメントの指示に従ってコンパイルして呼び出します。このコードは実際のlibctcsetattr()
関数を探し、代替バージョンを含みます。このコードは、backtrace()
FD 0で潜在的に興味深いアクティビティを見つけて、実際のlibcバージョンを呼び出すと呼び出されます。若干の調整が必要な場合があります。