catchsegv、gdb、valgrind、pmapなどのさまざまなユーティリティでデバッグする方法を学ぶために、意図的にコードに SIGSEGV を生成しました。mprotect() によって PROT_READ のフラグが設定されている mmap されたファイルに対して、意図的に memcpy() を使用しました。gdb でデバッグしているときに、アセンブリ出力から結論を出すことができません。組み立てに関してはかなりの初心者です。
詳細 -
メモリースタッフ:
(gdb) x/35i 0x00002aaaaad55500
0x2aaaaad55500 <memccpy+32>: jne 0x2aaaaad554e8 <memccpy+8>
0x2aaaaad55502 <memccpy+34>: mov %rdi,%rax
0x2aaaaad55505 <memccpy+37>: retq
0x2aaaaad55506 <memccpy+38>: nopw %cs:0x0(%rax,%rax,1)
0x2aaaaad55510 <memccpy+48>: xor %eax,%eax
0x2aaaaad55512 <memccpy+50>: retq
0x2aaaaad55513: nop
0x2aaaaad55514: nop
0x2aaaaad55515: nop
0x2aaaaad55516: nop
0x2aaaaad55517: nop
0x2aaaaad55518: nop
0x2aaaaad55519: nop
0x2aaaaad5551a: nop
0x2aaaaad5551b: nop
0x2aaaaad5551c: nop
0x2aaaaad5551d: nop
0x2aaaaad5551e: nop
0x2aaaaad5551f: nop
0x2aaaaad55520 <__memcpy_chk>: cmp %rdx,%rcx
0x2aaaaad55523 <__memcpy_chk+3>: jb 0x2aaaaadcb590 <__chk_fail>
0x2aaaaad55529: nopl 0x0(%rax)
0x2aaaaad55530 <memcpy>: cmp $0x20,%rdx
0x2aaaaad55534 <memcpy+4>: mov %rdi,%rax
0x2aaaaad55537 <memcpy+7>: jae 0x2aaaaad555b0 <memcpy+128>
0x2aaaaad55539 <memcpy+9>: test $0x1,%dl
0x2aaaaad5553c <memcpy+12>: je 0x2aaaaad55549 <memcpy+25>
0x2aaaaad5553e <memcpy+14>: movzbl (%rsi),%ecx
=> 0x2aaaaad55541 <memcpy+17>: mov %cl,(%rdi)
0x2aaaaad55543 <memcpy+19>: inc %rsi
0x2aaaaad55546 <memcpy+22>: inc %rdi
0x2aaaaad55549 <memcpy+25>: test $0x2,%dl
0x2aaaaad5554c <memcpy+28>: je 0x2aaaaad55560 <memcpy+48>
0x2aaaaad5554e <memcpy+30>: movzwl (%rsi),%ecx
0x2aaaaad55551 <memcpy+33>: mov %cx,(%rdi)
ご覧のとおり、SEGFAULT が命令 0x2aaaaad55541 で発生したことがわかります。これは、64 ビット命令ポインター レジスタ RIP にも示されています。
レジスター:
(gdb) info registers
rax 0x2aaaaaacf002 46912496267266
rbx 0x40146a 4199530
rcx 0x69 105
rdx 0x1 1
rsi 0x40146a 4199530
rdi 0x2aaaaaacf002 46912496267266
rbp 0x7 0x7
rsp 0x7fffffffe468 0x7fffffffe468
r8 0x40146a 4199530
r9 0x53202c444145525f 5989836176067220063
r10 0x7fffffffe1f0 140737488347632
r11 0x2aaaaad55530 46912498914608
r12 0x2aaaab05eac8 46912502098632
r13 0x7fffffffe5a0 140737488348576
r14 0x7fffffffe590 140737488348560
r15 0x2aaaaaacf000 46912496267264
rip 0x2aaaaad55541 0x2aaaaad55541 <memcpy+17>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
プロセス マッピング:
以下は、gdb 内の「info proc mappings」コマンドの出力です。
[excerpt]
0x2aaaaaacf000 0x2aaaaaad0000 0x1000 0 /tmp/dst_file
[/excerpt]
/tmp/dst_file は mmap() を使用してメモリにマップされ、memcpy() 呼び出しの前に PROT_READ を使用して読み取り専用にされ、memcpy() はそれにコンテンツを書き込もうとするため、SEGFAULT が表示されます。
使用される Memcpy() 呼び出し:
memcpy (mmap_start + myfilestat1.st_size, str1, strlen(str1))
mmap_start は開始アドレスで、myfilestat1.st_size は切り捨てられた新しいファイル サイズです。str1 は、ファイルに追加する文字列です。
これが私のソースコードの小さな流れです -
1. Fstat original size of file
2. Set Offset of file to grow depending upon strlen() of string to append
3. Ftruncate() to grow file size
4. Fstat new file size.
5. Mmap the newly truncated file
6. If segmentation fault need to be generated, call mprotect() to convert to PROT_READ.
7. Memcpy() with Orignal fstat size to append contents to text file.
質問 -
今、私が理解できないのは
0x2aaaaad55541 <memcpy+17>: mov %cl,(%rdi)
この指示は正確に何をしますか?RDI レジスタには、書き込みを開始するようにマップされたファイルの終了アドレスが含まれていますが、RDI アドレスの値が CX レジスタに書き込まれているのはなぜですか?
どんな助けでも大歓迎です。さらに情報が必要な場合はお知らせください。