how to debug a perl script using gdb

28
Perl Perl スススススス スススススス gdb gdb ススススス ススススス 2011/10/15 YAPC::Asia Tokyo 2011 @ 2011/10/15 YAPC::Asia Tokyo 2011 @ ススス ススス ススススススス ススス スス ・・ ススススススス ススス スス ・・ スス ス スス ス

Upload: akirahiguchi

Post on 25-May-2015

2.086 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: How to debug a perl script using gdb

PerlPerl スクリプトをスクリプトを gdbgdb でデバッグでデバッグ

2011/10/15 YAPC::Asia Tokyo 2011 @ 2011/10/15 YAPC::Asia Tokyo 2011 @ 大岡山大岡山

株式会社ディー・エヌ・エー株式会社ディー・エヌ・エー樋口 証樋口 証

Page 2: How to debug a perl script using gdb

PerlPerl 実行中のプロセスをデバッ実行中のプロセスをデバッググ

►今どこの今どこの perlperl コードを実行してるのか知コードを実行してるのか知りたいりたい どこかで固まってるが場所がわからないどこかで固まってるが場所がわからない 無限ループしているようだが場所がわからな無限ループしているようだが場所がわからな

いい クラッシュするがクラッシュするが perlperl の呼出し履歴がわからの呼出し履歴がわから

ないない

Page 3: How to debug a perl script using gdb

作った作った

► https://https://github.com/ahiguti/gdbperlgithub.com/ahiguti/gdbperl► 使いかた使いかた ::

実行中プロセスのプロセス実行中プロセスのプロセス idid を指定してを指定して実行実行$ $ gdbperl.pl 24113gdbperl.pl 24113

コアファイルを指定してコアファイルを指定して実行実行$ $ gdbperl.pl core.24113 /usr/bin/perlgdbperl.pl core.24113 /usr/bin/perl

► 実行すると実行すると perlperl の呼出し履歴などを表示するの呼出し履歴などを表示する 呼出し元のファイル名と行番号呼出し元のファイル名と行番号 呼出し先の関数名と引数呼出し先の関数名と引数

Page 4: How to debug a perl script using gdb

使用例使用例use IO::Socket::INET;use IO::Socket::INET;

sub baz {sub baz { while (1) { while (1) { my $sd = new IO::Socket::INET( my $sd = new IO::Socket::INET( PeerAddr =>PeerAddr => '10.1.0.0:80'); # '10.1.0.0:80'); # ここで固まるここで固まる sleep(1);sleep(1); } }}}

sub bar {sub bar { baz($_[0]); baz($_[0]);}}

sub foo {sub foo { bar(35, 5.98, "xyz", @_); bar(35, 5.98, "xyz", @_);}}

foo("abc");foo("abc");

Page 5: How to debug a perl script using gdb

gdbperl.plgdbperl.pl による呼出し履歴出力による呼出し履歴出力例例

[10] IO::Socket::connect() <- /home/user/perl5/perlbrew/perls/perl-[10] IO::Socket::connect() <- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket/INET.pm:257(IO::Socket::IN5.15.3/lib/5.15.3/i686-linux/IO/Socket/INET.pm:257(IO::Socket::INET)ET)

[9] IO::Socket::INET::connect() <- /home/user/perl5/perlbrew/perls/p[9] IO::Socket::INET::connect() <- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket/INET.pm:232(IO::Sockeerl-5.15.3/lib/5.15.3/i686-linux/IO/Socket/INET.pm:232(IO::Socket::INET)t::INET)

[8] (loop) <- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3[8] (loop) <- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket/INET.pm:178(IO::Socket::INET)/i686-linux/IO/Socket/INET.pm:178(IO::Socket::INET)

[7] IO::Socket::INET::configure(ref, ref) <- /home/user/perl5/perlbr[7] IO::Socket::INET::configure(ref, ref) <- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket.pm:48(IO::Soew/perls/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket.pm:48(IO::Socket)cket)

[6] IO::Socket::new("IO::Socket::INET", "PeerAddr", "10.1.0.0:80") <[6] IO::Socket::new("IO::Socket::INET", "PeerAddr", "10.1.0.0:80") <- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-lin- /home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket/INET.pm:37(IO::Socket::INET)ux/IO/Socket/INET.pm:37(IO::Socket::INET)

[5] IO::Socket::INET::new("PeerAddr", "10.1.0.0:80") <- ./t.pl:7(mai[5] IO::Socket::INET::new("PeerAddr", "10.1.0.0:80") <- ./t.pl:7(main)n)

[4] (loop) <- ./t.pl:6(main)[4] (loop) <- ./t.pl:6(main)[3] main::baz(35) <- ./t.pl:13(main)[3] main::baz(35) <- ./t.pl:13(main)[2] main::bar(35, 5.9800000000000004, "xyz", "abc") <- ./t.pl:17(mai[2] main::bar(35, 5.9800000000000004, "xyz", "abc") <- ./t.pl:17(mai

n)n)[1] main::foo("abc") <- ./t.pl:20(main)[1] main::foo("abc") <- ./t.pl:20(main)

Page 6: How to debug a perl script using gdb

どうやっているか?どうやっているか?

►gdb -pgdb -p でプロセスにアタッチでプロセスにアタッチ►gdbgdb にコマンドを送ってにコマンドを送って perlperl インタプリインタプリ

タの内部状態を調べるタの内部状態を調べる►gdbperl.pl 24113 verbose_gdb=1gdbperl.pl 24113 verbose_gdb=1 のよのよ

うにやるとうにやると gdbgdb との会話内容が見れるとの会話内容が見れる

Page 7: How to debug a perl script using gdb

gdbperl.plgdbperl.pl のの動作条件動作条件

►gdbgdb が必要が必要►perlperl が「が「 -g-g 」付きでコンパイルされてい」付きでコンパイルされてい

るる CC のソースレベルデバッグできないといけないのソースレベルデバッグできないといけない

からから perlbrew install 5.15.3 -D ccflags='-g‘perlbrew install 5.15.3 -D ccflags='-g‘

►perl 5.8 perl 5.8 ~ ~ 5.135.13►少なくとも少なくとも GNU/LinuxGNU/Linux とと MacOSXMacOSX でで動作動作

Page 8: How to debug a perl script using gdb

perlperl のの caller()caller() 関数関数

►呼出し履歴を取得する関数呼出し履歴を取得する関数►引数として、呼出しの深さを指定引数として、呼出しの深さを指定►pp_ctl.cpp_ctl.c に定義されている。に定義されている。 CC の関数名はの関数名は

pp_callerpp_caller►この関数この関数とと同等のこと同等のことをを gdbgdb 上からやれ上からやれ

ば、実行中のプロセスの呼出し履歴が調べば、実行中のプロセスの呼出し履歴が調べられるられる

Page 9: How to debug a perl script using gdb

pp_callerpp_caller のキモのキモcx = caller_cx(count, &dbcx);cx = caller_cx(count, &dbcx);

指定された深さの呼出し履歴のポインタ指定された深さの呼出し履歴のポインタstashname = CopSTASHPV(cx->blk_oldcop);stashname = CopSTASHPV(cx->blk_oldcop);

実行中の命令のパッケージ名実行中の命令のパッケージ名mPUSHs(newSVpv(OutCopFILE(cx->blk_oldcop), 0));mPUSHs(newSVpv(OutCopFILE(cx->blk_oldcop), 0));

実行中の命令のファイル名実行中の命令のファイル名mPUSHi((I32)CopLINE(cx->blk_oldcop));mPUSHi((I32)CopLINE(cx->blk_oldcop));

行番号行番号GV * const cvgv = CvGV(dbcx->blk_sub.cv);GV * const cvgv = CvGV(dbcx->blk_sub.cv);gv_efullname3(sv, cvgv, NULL);gv_efullname3(sv, cvgv, NULL);

呼出された関数の名前呼出された関数の名前AV * const ary = cx->blk_sub.argarray;AV * const ary = cx->blk_sub.argarray;

呼出しの呼出しの引数引数

Page 10: How to debug a perl script using gdb

perlperl インタプリタ内部構造につインタプリタ内部構造についていて

►プリプロセッサマクロを大量に使用プリプロセッサマクロを大量に使用► gdbgdb で内部を見るにはマクロを頑張って展開で内部を見るにはマクロを頑張って展開すす

るる►スレッド付きと無しでは内部構造が大幅に異なるスレッド付きと無しでは内部構造が大幅に異なる►バージョンによってもバージョンによっても大幅に異なる大幅に異なる

►以降は以降は 5.145.14 スレッド無しの場合を中心に解説すスレッド無しの場合を中心に解説するる

Page 11: How to debug a perl script using gdb

perlperl インタプリタインスタンスインタプリタインスタンスの取得の取得

► perlperl がスレッド付きでコンパイルされているとインタプリタが複数インスタがスレッド付きでコンパイルされているとインタプリタが複数インスタンスンスにに

► my_perlmy_perl という名前なので、という名前なので、 CC の呼出し履歴から探すの呼出し履歴から探す► スレッド無しのときはインタプリタがグローバルに定義されているのでスレッド無しのときはインタプリタがグローバルに定義されているので my_my_

perlperl は不要は不要

(gdb) bt(gdb) bt#0 0xffffe410 in __kernel_vsyscall ()#0 0xffffe410 in __kernel_vsyscall ()#1 0xb7de2021 in connect () at ../sysdeps/unix/sysv/linux#1 0xb7de2021 in connect () at ../sysdeps/unix/sysv/linux#2 0x0810f623 in Perl_pp_bind () at pp_sys.c:2475#2 0x0810f623 in Perl_pp_bind () at pp_sys.c:2475#3 0x080ce533 in Perl_runops_standard () at run.c:41#3 0x080ce533 in Perl_runops_standard () at run.c:41#4 0x08073c40 in S_run_body (#4 0x08073c40 in S_run_body (my_perl=0x816b008my_perl=0x816b008) at perl.c) at perl.c#5 perl_run (my_perl=0x816b008) at perl.c:2252#5 perl_run (my_perl=0x816b008) at perl.c:2252#6 0x0805e99d in main (argc=2, argv=0xbf9fe104, env=0xbf9#6 0x0805e99d in main (argc=2, argv=0xbf9fe104, env=0xbf9(gdb) frame 4(gdb) frame 4#4 0x08073c40 in S_run_body (my_perl=0x816b008) at perl.c#4 0x08073c40 in S_run_body (my_perl=0x816b008) at perl.c2334 CALLRUNOPS(aTHX);2334 CALLRUNOPS(aTHX);

Page 12: How to debug a perl script using gdb

現在実行中の命令現在実行中の命令

► スレッド付きのときは スレッド付きのときは my_perl-my_perl->Icurcop>Icurcop

► スレッド無しのときは スレッド無しのときは PL_curcopPL_curcop ( ( ググローバル変数ローバル変数 ))

Page 13: How to debug a perl script using gdb

現在実行中の命令現在実行中の命令 (( スレッド付きスレッド付き ))

(gdb) p *my_perl->Icurcop(gdb) p *my_perl->Icurcop$2 = {op_next = 0x823c930, op_sibling = $2 = {op_next = 0x823c930, op_sibling = 0x8260d38, op_ppaddr = 0x80dd030 0x8260d38, op_ppaddr = 0x80dd030 <Perl_pp_nextstate>, op_targ = 0, op_type = <Perl_pp_nextstate>, op_targ = 0, op_type = 181, op_opt = 1,181, op_opt = 1, op_latefree = 0, op_latefree = 0, op_latefreed = 0, op_attached = 0, op_spare op_latefreed = 0, op_attached = 0, op_spare = 0, op_flags = 1 '\001', op_private = 0 '\= 0, op_flags = 1 '\001', op_private = 0 '\000', cop_line = 000', cop_line = 114114,, cop_stashpv = cop_stashpv = 0x8260df0 "0x8260df0 "IO::SocketIO::Socket",", cop_file = 0x8260d90 cop_file = 0x8260d90 ""/home/user/perl5/perlbrew/perls/5.14.2-/home/user/perl5/perlbrew/perls/5.14.2-thr/lib/5.14.2/i686-linux-thread-multi/IO/thr/lib/5.14.2/i686-linux-thread-multi/IO/Socket.pmSocket.pm", cop_hints = 1794,", cop_hints = 1794, cop_seq = 719, cop_seq = 719, cop_warnings = 0x0, cop_hints_hash = 0x0}cop_warnings = 0x0, cop_hints_hash = 0x0}

Page 14: How to debug a perl script using gdb

現在実行中の命令現在実行中の命令 (( スレッド無しスレッド無し ))

(gdb) p *PL_curcop(gdb) p *PL_curcop$2 = {op_next = 0x8184fe8, op_sibling $2 = {op_next = 0x8184fe8, op_sibling = 0x81908f8, op_ppaddr = 0x80d00d0 = 0x81908f8, op_ppaddr = 0x80d00d0 <Perl_pp_nextstate>,<Perl_pp_nextstate>, op_targ = 0, op_targ = 0, op_type = 183, op_opt = 1, op_type = 183, op_opt = 1, op_latefree = 0, op_latefreed = 0, op_latefree = 0, op_latefreed = 0, op_attached = 0,op_attached = 0, op_spare = 0, op_spare = 0, op_flags = 1 '\001', op_private = 0 op_flags = 1 '\001', op_private = 0 '\000', cop_line = 8, cop_stash = '\000', cop_line = 8, cop_stash = 0x816df58,0x816df58, cop_filegv = 0x816e168, cop_filegv = 0x816e168, cop_hints = 0, cop_seq = 1058, cop_hints = 0, cop_seq = 1058, cop_warnings = 0x0, cop_hints_hash = cop_warnings = 0x0, cop_hints_hash = 0x0}0x0}

Page 15: How to debug a perl script using gdb

ファイル名と行番号ファイル名と行番号

(gdb) p PL_curcop->cop_filegv-(gdb) p PL_curcop->cop_filegv->sv_u.svu_gp->gp_sv->sv_u.svu_pv>sv_u.svu_gp->gp_sv->sv_u.svu_pv$3 = 0x818acd0 $3 = 0x818acd0 "/home/user/perl5/perlbrew/perls"/home/user/perl5/perlbrew/perls/perl-5.15.3/lib/5.15.3/i686-/perl-5.15.3/lib/5.15.3/i686-linux/IO/Socket.pm"linux/IO/Socket.pm"(gdb) p PL_curcop->cop_line(gdb) p PL_curcop->cop_line$4 = 114$4 = 114

Page 16: How to debug a perl script using gdb

呼出し履歴呼出し履歴

►スレッド付きスレッド付き ::my_perl->Icurstackinfo->si_cxstack[my_perl->Icurstackinfo->si_cxstack[ 深さ深さ ]]

►スレッド無しスレッド無し ::PL_curstackinfo->si_cxstack[PL_curstackinfo->si_cxstack[ 深さ深さ ]]

►履歴の最大長履歴の最大長 ::*cur_stackinfo->si_cxix*cur_stackinfo->si_cxix

Page 17: How to debug a perl script using gdb

呼出し元ファイル名と行番号呼出し元ファイル名と行番号

(gdb) p PL_curstackinfo-(gdb) p PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blku_>si_cxstack[2].cx_u.cx_blk.blku_oldcop->cop_filegv->sv_u.svu_gp-oldcop->cop_filegv->sv_u.svu_gp->gp_sv->sv_u.svu_pv>gp_sv->sv_u.svu_pv$86 = 0x817a238 "./t.pl"$86 = 0x817a238 "./t.pl"(gdb) p PL_curstackinfo-(gdb) p PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blku_>si_cxstack[2].cx_u.cx_blk.blku_oldcop->cop_lineoldcop->cop_line$87 = 17$87 = 17

Page 18: How to debug a perl script using gdb

呼出し元パッケージ名呼出し元パッケージ名

(gdb) p PL_curstackinfo-(gdb) p PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blku_oldco>si_cxstack[2].cx_u.cx_blk.blku_oldcop->cop_stash->sv_any->xhv_maxp->cop_stash->sv_any->xhv_max$88 = 511$88 = 511(gdb) p (char *)((struct xpvhv_aux *)(gdb) p (char *)((struct xpvhv_aux *)(PL_curstackinfo-(PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blku_oldco>si_cxstack[2].cx_u.cx_blk.blku_oldcop->cop_stash->sv_u.svu_hash+511+1))-p->cop_stash->sv_u.svu_hash+511+1))->xhv_name_u.xhvnameu_name->hek_key>xhv_name_u.xhvnameu_name->hek_key$89 = 0x817686c "main"$89 = 0x817686c "main"

Page 19: How to debug a perl script using gdb

呼出しの種類呼出しの種類 (sub, eval, loop(sub, eval, loop等等 ))

(gdb) p PL_curstackinfo-(gdb) p PL_curstackinfo->si_cxstack[2].cx_u.cx_subst.sbu_type & 0xf>si_cxstack[2].cx_u.cx_subst.sbu_type & 0xf$90 = 8$90 = 8

#define CXt_NULL 0#define CXt_NULL 0#define CXt_WHEN 1#define CXt_WHEN 1#define CXt_BLOCK 2#define CXt_BLOCK 2#define CXt_GIVEN 3#define CXt_GIVEN 3#define CXt_LOOP_FOR 4#define CXt_LOOP_FOR 4#define CXt_LOOP_PLAIN 5#define CXt_LOOP_PLAIN 5#define CXt_LOOP_LAZYSV 6#define CXt_LOOP_LAZYSV 6#define CXt_LOOP_LAZYIV 7#define CXt_LOOP_LAZYIV 7#define CXt_SUB 8#define CXt_SUB 8#define CXt_FORMAT 9#define CXt_FORMAT 9#define CXt_EVAL 10#define CXt_EVAL 10#define CXt_SUBST 11#define CXt_SUBST 11

Page 20: How to debug a perl script using gdb

呼出し先パッケージ名呼出し先パッケージ名

(gdb) p PL_curstackinfo-(gdb) p PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u.blku_s>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.cv->sv_any->xcv_gv-ub.cv->sv_any->xcv_gv->sv_any.xnv_u.xgv_stash->sv_any->sv_any.xnv_u.xgv_stash->sv_any->xhv_max>xhv_max$91 = 511$91 = 511(gdb) p (char *)((struct xpvhv_aux *)(gdb) p (char *)((struct xpvhv_aux *)(PL_curstackinfo-(PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u.blku_s>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.cv->sv_any->xcv_gv-ub.cv->sv_any->xcv_gv->sv_any.xnv_u.xgv_stash->sv_any.xnv_u.xgv_stash->sv_u.svu_hash+511+1))->sv_u.svu_hash+511+1))->xhv_name_u.xhvnameu_name->hek_key>xhv_name_u.xhvnameu_name->hek_key$92 = 0x817686c "main"$92 = 0x817686c "main"

Page 21: How to debug a perl script using gdb

呼出し先関数名呼出し先関数名

(gdb) p (char *)PL_curstackinfo-(gdb) p (char *)PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.cv->sv_any->xcv_gv-.blku_sub.cv->sv_any->xcv_gv->sv_any.xiv_u.xivu_namehek->sv_any.xiv_u.xivu_namehek->hek_key>hek_key$93 = 0x822e2dc "bar“$93 = 0x822e2dc "bar“

Page 22: How to debug a perl script using gdb

呼出しの引数呼出しの引数►引数は配列引数は配列 (AV)(AV)の形で保持されているの形で保持されている►配列要素はスカラ配列要素はスカラ (SV)(SV)►スカラには数値スカラには数値 (IV)(IV) 、浮動小数点数、浮動小数点数

(NV)(NV) 、文字列、文字列 (PV)(PV) などの型があるなどの型がある

Page 23: How to debug a perl script using gdb

引数の数引数の数

(gdb) p PL_curstackinfo-(gdb) p PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.argarray->sv_any-.blku_sub.argarray->sv_any->xav_fill>xav_fill$94 = 3$94 = 3これを更にこれを更に +1+1 した値が引数の数した値が引数の数

Page 24: How to debug a perl script using gdb

スカラ値スカラ値 (SV)(SV) の型の型(gdb) p (PL_curstackinfo-(gdb) p (PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.argarray->si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.argarray->sv_u.svu_array[0]).sv_flags>sv_u.svu_array[0]).sv_flags$95 = 134222082$95 = 134222082この値をこの値を 0xf0xf でマスクするでマスクする

typedef enum {typedef enum { SVt_NULL, /* 0 */ SVt_NULL, /* 0 */ SVt_BIND, /* 1 */ SVt_BIND, /* 1 */ SVt_IV, /* 2 */ SVt_IV, /* 2 */ SVt_NV, /* 3 */ SVt_NV, /* 3 */ SVt_PV, /* 4 */ SVt_PV, /* 4 */

                   ...... } svtype;} svtype;

Page 25: How to debug a perl script using gdb

整数型整数型 (IV)(IV) のときの値取得のときの値取得

(gdb) p ((XPVIV*)(gdb) p ((XPVIV*)(PL_curstackinfo-(PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.argarray-.blku_sub.argarray->sv_u.svu_array[0]).sv_any)->sv_u.svu_array[0]).sv_any)->xiv_u.xivu_iv>xiv_u.xivu_iv$96 = 35$96 = 35

Page 26: How to debug a perl script using gdb

浮動小数点数浮動小数点数 (NV)(NV) のときの値取のときの値取得得

(gdb) p ((XPVNV*)(gdb) p ((XPVNV*)(PL_curstackinfo-(PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.argarray-.blku_sub.argarray->sv_u.svu_array[1]).sv_any)->sv_u.svu_array[1]).sv_any)->xnv_u.xnv_nv>xnv_u.xnv_nv$98 = 5.9800000000000004$98 = 5.9800000000000004

Page 27: How to debug a perl script using gdb

文字列文字列 (PV)(PV) のときの値取得のときの値取得

(gdb) p (PL_curstackinfo-(gdb) p (PL_curstackinfo->si_cxstack[2].cx_u.cx_blk.blk_u>si_cxstack[2].cx_u.cx_blk.blk_u.blku_sub.argarray-.blku_sub.argarray->sv_u.svu_array[2]).sv_u.svu_pv>sv_u.svu_array[2]).sv_u.svu_pv$100 = 0x818ea88 "xyz"$100 = 0x818ea88 "xyz"

Page 28: How to debug a perl script using gdb

まとめ等まとめ等►perlperl のコードも頑張ればのコードも頑張れば gdbgdb でデバッグできでデバッグでき

るる 実行中プロセスもデバッグ可実行中プロセスもデバッグ可

►ただし自動化しないときついただし自動化しないときつい gdbperl.plgdbperl.pl

►perlperl のバージョンとスレッド有無によって内のバージョンとスレッド有無によって内部が大幅に異なる部が大幅に異なる

►実運用環境でもデバッグシンボルは付けてお実運用環境でもデバッグシンボルは付けておきましょうきましょう