- 投稿日:2020-02-20T22:48:35+09:00
Linux カーネルにおけるInstruction Pointer (=プログラムカウンタ)取得方法
Linuxカーネル・ドライバにおいて、Instruction Pointer (=プログラムカウンタ)を取得したい場合、linux/kernel.hで定義された
_THIS_IP_
マクロを使います定義は下記のとおり。
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })LinuxカーネルにおけるInstruction Pointerの簡単な歴史
かつては各アーキテクチャで独自に
current_text_addr()
を定義していたのですが、v4.20あたりでそれらが全て撤廃され、linux/kernel.hにある_THIS_IP_
を使うように統一されたようです。このときのpatchを見ると、各アーキテクチャのアセンブラによるプログラムカウンタの取得方法が見れておもしろいです。
アセンブラを書いたことがある人なら当たり前の話なのですが、プロセッサのプログラムカウンタを保持するレジスタは、アーキテクチャ毎に異なります。そのため、アーキテクチャ毎に個別の実装を用意するというのは、理にかなっているような気がします。ではなぜ、マクロ1本に統一されたのか?なんだこのマクロは?
まずマクロがまったく理解できなかったのでググってみたところ、stackoverflowで優しいお兄様方が解説してくれていました。さすがです。
https://stackoverflow.com/questions/13902431/this-ip-macro-in-linux-kernel
要約すると、
__label__ __here;
はローカルラベル名の宣言__here:
はローカルラベル&&__here;
は上記ローカルラベルのアドレス (unsigned long型にキャストされている)ということのようです。カッコ()の中が1行だとわかりにくいので改行を入れると、
{ __label__ __here; __here: (unsigned long)&&__here; }となり、1行目がローカルラベル名の宣言、2行目がラベルです。
ローカルラベルは、どうやらGCCで使えるものらしいです。
https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Local-Labels.htmlブロック内でのみ参照できるラベルということですね。
3行目の'&&'はラベルのアドレスを示すための特別な演算子です(参考:https://docs.oracle.com/cd/E19205-01/821-0386/bjabt/index.html)
このマクロを埋め込んだ位置では、ブロック内のローカルラベルとして
__here
が貼られ、そのラベルのアドレスを取得することが、詰まるところ現在のプログラムの位置(=プログラムカウンタ)となるわけです。
よって、プログラムの現在の位置を、アセンブラに頼らずC言語のみで表現できるため、カーネル内でも_THIS_IP_
マクロ1本に統一できたというわけです。(なお、gccを使う限りはLinuxに限らず様々な環境に移植可能なはずです。)そしてC言語ようわからんという愚痴
問題はこの外側について。正直よくわからない。通常、ブロック文{}は式として使用できない。試しに、下記のようなコードを書くとコンパイルエラーになる。
int i = {1;};ところが、ブロック文をカッコ()で括るとなぜかコンパイルが通る。
int i = ({1;});このとき、カッコ()式の値はブロック{}文の最後に書いた式を評価した時の値が使用される。試しに下記のコードをgccでコンパイルして実行してみると、コンソールにはブロック文最後の式dの値(=5)が表示される。
#include <stdio.h> int main(void) { int a = ({ int a = 2; int b = 3; int c = 4; int d = 5; a; b; c; d; }); printf("%d\n", a); return 0; }これは文法的にどうなんだ。。。
以上、かれこれ10年以上はC言語を扱ってるのに未だに文法的に知らない・読めないものが出てくることに対する無力感から、備忘録としてまとめました。...精進します。
でもC言語は綺麗じゃないと思う。だって'&&'、お前ずっと二項演算子として俺と付き合ってたはずだよな...?
('&&'もGCCの拡張ですかね https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Labels-as-Values.html#Labels-as-Values)
- 投稿日:2020-02-20T17:53:28+09:00
systemd unit ファイルのパスを得る
$ systemctl show sshd|grep ^FragmentPath|sed -e "s/^.*=//" /usr/lib/systemd/system/sshd.service
- 投稿日:2020-02-20T15:27:16+09:00
環境毎にプロンプトの色を変える
開発環境「もしかして」
— linusnoopy i7 4870HQ (@linusnoopy) February 13, 2020
本番環境「わたしたち」「「入れ替わってる〜〜!?!?」」
とならないために、開発環境、ステージング環境、本番環境のシェルはひと目で判別できるようにしておきたいですね。
bash
とzsh
でプロンプト色を変更してみましょう。bash編
RHEL系のデフォルトプロンプト
[\u@\h \W]\$
白いですね。
bashではPS1
という環境変数を変更する事でプロンプトの変更が可能です。文字色を変える
\e[36m
で色付けを開始して
\e[m
でリセットしています。
36
が水色、33
が黄、35
が紫に対応しています。
開発環境は水色、ステージングは黄、本番環境は紫、などの設定ができますね。文字を太字にする
\e[1m
1
だと文字を太字にする事ができます。太字で色も変える
\e[1;36m
1
と36
の両方を設定して太字フォントかつ文字色が変更になります。さらに色々変える
1
太字で
2
薄色で
3
イタリックで
4
下線を引き
9
取り消し線を入れ
36
文字色を水色に
45
背景色を紫に
できたりします。仕組み
ANSIエスケープシーケンスという特殊文字を使ってターミナルでの表示を制御しています。プロンプトに限らず、プログラムの出力にも使われます。
文字スタイルや、実際の表示色はクライアントのOSやターミナルによって微妙に異なってきます。参考
ANSIエスケープシーケンス チートシート
https://qiita.com/PruneMazui/items/8a023347772620025ad6文字スタイル指定の一覧
https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters色指定の一覧と各ターミナルでの表示色例
https://en.wikipedia.org/wiki/ANSI_escape_code#Colorszsh編
zsh
ではPROMPT
環境変数で設定します。
設定方法もbashとは異なり、zsh独自のタグのようなものを使います。
%B
で太字
%b
で太字解除
%F{cyan}
で文字色を水色にし
%f
で文字色リセット参考
プロンプト拡張
http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html#Prompt-Expansion
表示効果
http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html#Visual-effects
文字装飾
http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Character-Highlightingマシン全体に設定
/etc/profile.d/
にbashなら
export PS1="\e[1;36m\][\u@\h \W]\e[m\$ "zshなら
export PROMPT="%B%F{cyan}[%n@%m]%f%b%~%# "のようなシェルスクリプトを入れておくと、全てのユーザのデフォルトプロンプトにできます。
- 投稿日:2020-02-20T15:16:24+09:00
bcコマンドでPiを求める
恒例
https://www.gnu.org/software/bc/
bcコマンドは、任意の精度の数値を求めることができるコマンド
echo "scale=5000; 4*a(1)" | bc -l -q
- 投稿日:2020-02-20T15:16:24+09:00
BashでPiを求める
恒例
https://www.gnu.org/software/bc/
bcコマンドは、任意の精度の数値を求めることができるコマンド
echo "scale=5000; 4*a(1)" | bc -l -q
- 投稿日:2020-02-20T13:54:15+09:00
scpコマンド メモ
- 投稿日:2020-02-20T00:17:56+09:00
ざっくりsystemctlコマンド
systemctlとはざっくり・・・
サービスを管理するコマンド。
※nginxを起動したり、firewallの自動起動したり、一時的に止めたりとか。
主にLinuxで使われていて、CentOS7やUbuntuで使われているみたい(CentOS6以前はchkconfigコマンドらしい)。ちなみに対象のサービス名は〜.serviceと入れても入れなくてもOK。
例 ↓はどちらも同じ
systemctl status httpd
systemctl status httpd.service
ざっくりsystemctlコマンドを即時反映、自動起動、状態確認の3つの系統に分けてメモ。
1. 即時反映系
- 開始
$ systemctl start サービス名
- 停止
$ systemctl stop サービス名
- 再起動
$ systemctl restart サービス名
- リロード
$ systemctl reload サービス名
- 強制終了
$ systemctl kill サービス名2. 自動起動系
- サービスの自動起動を有効にする。 ※止まっている状態で有効にしてもサービスは止まったまま
$ systemctl enable サービス名
- サービスの自動起動を無効にする。 ※動いている状態で無効にしてもサービスは動いたまま
$ systemctl disable サービス名3. 状態確認系
- サービスの状態を確認
$ systemctl status サービス名
- サービスの詳細を確認
$ systemctl show サービス名
- アクティブかどうかの確認
$ systemctl is-active サービス名
- 自動起動の設定確認
$ systemctl is-enabled サービス名
- 全サービスの一覧
$ systemctl list-units --all
- アクティブなサービスの一覧
$ systemctl list-units --type=service