안녕하세요
http://jake.dothome.co.kr/unflatten_device_tree/ 에서 unflatten_dt_nodes 에 궁금증이 생겨 질문 올립니다.
위 링크에서
unflatten_dt_node() 함수에서 29~31줄 line인 for문을 어떻게 빠져 나오는지 궁금합니다.
29 |
for (offset = 0; |
30 |
offset >= 0 && depth >= initial_depth; |
31 |
offset = fdt_next_node(blob, offset, &depth)) { |
실제 for문을 빠져 나오게 되는 49번 줄에 break를 걸고 변수 값을 확인해 보았을 때
다음과 같이 나왔습니다.
------------------------------------------------------------------------------------------------
Thread 1 hit Breakpoint 5, unflatten_dt_nodes (blob=<optimized out>,
mem=0xffff80003ddfcff7, dad=<optimized out>, nodepp=0x0) at drivers/of/fdt.c:406
406 if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
(gdb) p offset
$11 = 7172
(gdb) p depth
$12 = 0
(gdb) p initial_depth
$13 = 0
(gdb) x/10x mem
0xffff80003ddfcff7: 0xbeadde00 0x000000ef 0xe0071300 0xe800007f //dead?? bead???
0xffff80003ddfd007: 0xe0171300 0xe800007f 0xe0271300 0xe800007f
0xffff80003ddfd017: 0xe0371300 0xe800007f
(gdb)
-------------------------------------------------------------------------------------------
offset, depth, initial_depth 값을 for문의 조건문에 대입해 보면 조건문은 true 이므로 for문은 빠져 나올 수 없는데
빠져나와있습니다.
error인가 싶어 for문 나온 후 mem 메모리를 보면 beaddeef값까지 들어가 있습니다.
(질문하면서 발견했는데 원래 deaddeef 가 정상이였네요 qemu 문제 일수 도 있을까요??)
break에 조건문을 아래와 같이 걸어서 분석해보았는데도 잘 모르겠습니다.
현재 break가 걸렸을 때 pc 값은 for문에서 조건식에 멈춰있으며, offset, depth 역시 7172에 멈춰있습니다.
initial_depth는 초기 선언한 0 그대로 유지하고 있으면 (그렇게 생각한 근거는 for문 나왔을 때 initial_depth = 0, depth =0)
for문을 빠져 나올 수 없는데 next로 진행하면 for문을 빠져 나오게 됩니다
어떻게 빠져 나올 수 있었을까요?
감사합니다.
댓글 3
-
문c(문영일)
2019.10.14 23:43
-
에러
2019.10.15 21:34
답변 감사합니다.
GDB Display에 문제가 있었네요~
실제 코드 inline Disassembly 따라가보니 Depth 주소를 볼 수 있었고
Depth는 fdt_next_node 함수 안에 if (depth && ((--(*depth)) < 0)) 에서 변경 되었음을 확인 할 수 있었습니다.
위 질문에 for 문을 빠져 나오기 위해 판단하는 명령어는 CCMP 이고 w0, w1 레지스터 인데
0xffff0000108ddf94 <+136>: ccmp w0, w1, #0x1, ge // ge = tcont
보시다시피 w0 는 0xffffffff를 가리키지만 display에서는 depth = 0으로 표기합니다. &depth에서 오류가 발생한거 같네요
다른 함수 분석 할때도 optimized out 뜨면 난감했는디 위 방법대로 해봐야겠네요
감사합니다. :D
-
문c(문영일)
2019.10.16 20:02
저도 추적이 잘 안될때엔 disassemble하여 보며 같이 레지스터들을 확인합니다.
수고 많으셨습니다.
.
안녕하세요? 문c블로그(http://jake.dothome.co.kr)의 문영일입니다.
잘 아시겠지만 근래 리눅스 커널은 gcc optimization 옵션으로 -O2를 사용하고 있습니다.
이를 -O0로 바꿔서 디버깅을 하여 왔는데, 근래에는 간단한 방법으론 잘 안되고 있습니다.
그러면서 gdb로 커널 디버깅을 하는 경우 행 번호를 잘 따라가지 못하는 경우도 있고,
변수 출력을 보면 <optimized out>으로 표기되어 안보일 때가 있어 어렵게 레지스터를 봐야 하기도 합니다.
많이 불편하죠. 위의 unflatten_dt_nodes() 함수의 경우는 특이하게 디버깅이 더 어렵더군요.
말씀하신 것 처럼 거짓 정보가 출력이 되더군요.
(조금 불편하기만 한 것이 아니라 이제 크게 불편한 상태가 되었습니다.)
실제로 offset 값과, depth를 추적하면
offset은 계속 증가하고, depth는 루프를 벗어나기 위해 -1이 되어야 합니다.
따라서 위와 같이 전혀 해결의 실마리가 안보이고 반드시 디버깅을 통해 추적을 해야 하는 경우라면 함수명 앞에 __attribute__((optimize("-O0"))) 문장을 추가한 후 컴파일하고 다시 해 보시면 디버깅이 잘 될것입니다.
static int unflatten_dt_nodes(...
-> static int __attribute__((optimize("-O0"))) unflatten_dt_nodes(...
감사합니다.