ます’s Blog - どうでもいい記事100選

どうでもいい記事100選

「?:」演算子(続きの続きの続きの続き)

少し時間が空いてしまいましたが、まだまだモチベーションは下がっていないようで一安心です。先日の続きです。
今回は(前回に宣言した)変数の変更(改竄)あたりをやってみたいと思います。
どの関数を対象にしようか迷いましたが、適当にround関数をターゲットにしてみます。。。って、特に深い事をやっている訳ではないのでhnwさんに登場されるとマジで焦ります。(w


以前「strings」コマンドを使って関数の実体を探した事を思い出したので、今回その方法でやってみました。

% cd $HOME/php-5.3-dev
% strings ./php-cli | grep 'round'
zif_round
round
body {background-color: #ffffff; color: #000000;}
a:link {color: #000099; text-decoration: none; background-color: #ffffff;}
.e {background-color: #ccccff; font-weight: bold; color: #000000;}
.h {background-color: #9999cc; font-weight: bold; color: #000000;}
.v {background-color: #cccccc; color: #000000;}
.vr {background-color: #cccccc; text-align: right; color: #000000;}
hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000000;}

なる程。「zif_round」か「round」のどっちかだね。
gdbを起動してブレーク・ポイントに設定してみる。

% gdb ./php-cli

(gdb) b round
Function "round" not defined.
Make breakpoint pending on future shared library load? (y or [n])

(gdb) b zif_round
Breakpoint 1 at 0x81580b5: file $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c, line 184.

(gdb) i breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x081580b5 in zif_round at $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:184

「zif_round」が正解。それでは実際に実行してみる。

(gdb) r -r 'echo round( 5.045, 2 );'
Starting program: $HOME/php-5.3-dev/php-cli -r 'echo round( 5.045, 2 );'
Failed to read a valid object file image from memory.

Breakpoint 1, zif_round (ht=2, return_value=0xb7decee0, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:184
184             int places = 0;

(gdb) bt
#0  zif_round (ht=2, return_value=0xb7decee0, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:184
#1  0x0823655b in zend_do_fcall_common_helper_SPEC (execute_data=0xb7d75048)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/Zend/zend_vm_execute.h:315
#2  0x0823aa3d in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0xb7d75048)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/Zend/zend_vm_execute.h:1574
#3  0x08235a49 in execute (op_array=0xb7deca10) at $HOME/php-5.3-dev/work/php5.3-200808250230/Zend/zend_vm_execute.h:104
#4  0x081ffe56 in zend_eval_string (str=0xbfbcb9a6 "echo round( 5.045, 2 );", retval_ptr=0x0, string_name=0x834a4dc "Command line code")
    at $HOME/php-5.3-dev/work/php5.3-200808250230/Zend/zend_execute_API.c:1112
#5  0x08200011 in zend_eval_string_ex (str=0xbfbcb9a6 "echo round( 5.045, 2 );", retval_ptr=0x0,
    string_name=0x834a4dc "Command line code", handle_exceptions=1)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/Zend/zend_execute_API.c:1147
#6  0x08293ecc in main (argc=3, argv=0xbfbca404) at $HOME/php-5.3-dev/work/php5.3-200808250230/sapi/cli/php_cli.c:1169

(gdb) l
179     /* {{{ proto float round(float number [, int precision])
180        Returns the number rounded to specified precision */
181     PHP_FUNCTION(round)
182     {
183             zval **value;
184             int places = 0;
185             long precision = 0;
186             double return_val;
187
188             if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &value, &precision) == FAILURE) {

(gdb)
189                     return;
190             }
191
192             if (ZEND_NUM_ARGS() == 2) {
193                     places = (int) precision;
194             }
195             convert_scalar_to_number_ex(value);
196
197             switch (Z_TYPE_PP(value)) {
198                     case IS_LONG:

(gdb) c
Continuing.
5.05
Program exited normally.

結果は「5.05」となりました。期待通り。


前準備はこれくらいにしておいて、今回はround関数の第2引数を変更(改竄)してみたいと思います。
最終的には変数「places」で処理されているっぽいので、変数「places」へ代入している位置をブレーク・ポイントに設定してみる。

(gdb) d 1

(gdb) b $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:193
Breakpoint 2 at 0x81580f4: file $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c, line 193.

(gdb) i breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep y   0x081580f4 in zif_round at $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:193

(gdb) r -r 'echo round( 5.045, 2 );'
Starting program: $HOME/php-5.3-dev/php-cli -r 'echo round( 5.045, 2 );'
Failed to read a valid object file image from memory.

Breakpoint 2, zif_round (ht=2, return_value=0xb7dd9ee0, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:193
193                     places = (int) precision;

止まった。ここからが本題。


「pt(ptype)type_name」で指定した「type_name」の型が分かる、と。
「p(print)variable_name」で指定した「variable_name」の値が分かる、と。
「s(set)variable_name = expression」で指定した「variable_name」の値を変更できる、と。
「expression」には値だけではなくて式も指定できるみたいなんだけど、現時点では「何のこっちゃ?」って感じ。
いづれ分かるさ。。。きっと。_| ̄|○


気を取り直して内容と中身を確認。

(gdb) pt places
type = int

(gdb) p places
$1 = 0

この時点では(まだ)初期値のママなので「n(next)」で次へ進んでみる。

(gdb) n
195             convert_scalar_to_number_ex(value);

(gdb) p places
$2 = 2

おぉっ!第2引数で指定した値に変わってる。
それでは、今回の目的である変更(改竄)をやってみます。

(gdb) s places = 1
197             switch (Z_TYPE_PP(value)) {

(gdb) p places
$3 = 1

(gdb) c
Continuing.
5
Program exited normally.

おぉっ!変更(改竄)した値で正しく処理されています。結果も「5」となり、期待通り。すげぇ。
ただ、気になるのは変数を変更(改竄)しただけなのに次へ処理が進んでいるのは何故なんだろうか。。。こういう仕様なの?
使いづらいような。。。全然分かりません。ヘタれっぷりは(いつまでも)健在です。_| ̄|○


ここからは(若干)話が逸れますが「zval **value」の変更(改竄)に挑戦。
ブレーク・ポイントの設定は残したママで再実行。

(gdb) r -r 'echo round( 5.045, 2 );'
Starting program: $HOME/php-5.3-dev/php-cli -r 'echo round( 5.045, 2 );'
Failed to read a valid object file image from memory.

Breakpoint 2, zif_round (ht=2, return_value=0xb7d5bee0, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)
    at $HOME/php-5.3-dev/work/php5.3-200808250230/ext/standard/math.c:193
193                     places = (int) precision;

止まったので、内容を確認。

(gdb) pt value
type = struct _zval_struct {
    zvalue_value value;
    zend_uint refcount__gc;
    zend_uchar type;
    zend_uchar is_ref__gc;
} **

うへ。複雑。中身を確認。

(gdb) p value
$4 = (zval **) 0xb7ce40a8

(gdb) p *value
$5 = (zval *) 0xb7d5b31c

(gdb) p **value
$6 = {value = {lval = 2061584302, dval = 5.0449999999999999, str = {val = 0x7ae147ae <Address 0x7ae147ae out of bounds>,
      len = 1075064340}, ht = 0x7ae147ae, obj = {handle = 2061584302, handlers = 0x40142e14}}, refcount__gc = 1, type = 2 '\002',
  is_ref__gc = 0 '\0'}

pointerのpointerなので、中身を確認するには「*」が二つ必要、と。
それでは変更(改竄)に挑戦!

(gdb) s **value.value = 4.0449999999999999
Attempt to take contents of a non-pointer value.

(gdb) p **value
$7 = {value = {lval = 2061584302, dval = 5.0449999999999999, str = {val = 0x7ae147ae <Address 0x7ae147ae out of bounds>,
      len = 1075064340}, ht = 0x7ae147ae, obj = {handle = 2061584302, handlers = 0x40142e14}}, refcount__gc = 1, type = 2 '\002',
  is_ref__gc = 0 '\0'}

(gdb) s *value.value = 4.0449999999999999
Attempt to take contents of a non-pointer value.

(gdb) p **value
$8 = {value = {lval = 2061584302, dval = 5.0449999999999999, str = {val = 0x7ae147ae <Address 0x7ae147ae out of bounds>,
      len = 1075064340}, ht = 0x7ae147ae, obj = {handle = 2061584302, handlers = 0x40142e14}}, refcount__gc = 1, type = 2 '\002',
  is_ref__gc = 0 '\0'}

(gdb) s value.value = 4.0449999999999999
Value can't be converted to integer.

(gdb) p **value
$9 = {value = {lval = 2061584302, dval = 4.0449999999999999, str = {val = 0x7ae147ae <Address 0x7ae147ae out of bounds>,
      len = 1074802196}, ht = 0x7ae147ae, obj = {handle = 2061584302, handlers = 0x40102e14}}, refcount__gc = 1, type = 2 '\002',
  is_ref__gc = 0 '\0'}

(gdb) c
Continuing.
4.05
Program exited normally.

(gdb) q

%

うーん。。。全然分かりません。_| ̄|○
実行結果を見る限りでは「4.05」になっているので(一応)変更されたっぽいけど、警告っぽいのも出ているので、この方法は間違っている気がする。。。けど、そもそも使い方を理解していないので、何が正しいのかすらサッパリ分かりません。
全然駄目スギ。。。久々に涙目。_| ̄|○


そろそろ本でも購入すべきかな。。。と思いつつ、今日はここまで。
次は条件付きブレーク・ポイントの設定や関数呼び出しあたりを重点的に勉強してみたい。
。。。次からはタイトルを変更しよう。意味不明スギ。_| ̄|○