Crash Log
Thread 1 "eduke32" received signal SIGSEGV, Segmentation fault.
0xb6e25e68 in memset () from /lib//libc.so.0
(gdb) bt
#0 0xb6e25e68 in memset () from /lib//libc.so.0
#1 0x001e1e68 in decodeframe (
srcP=0xb4df2bc6 "((\v\v\026!\342Ƴ\001\263\263\263\001\263\001\361\241_,,\017`\032\032!\026(",
dstP=0x1d229bb <error: Cannot access memory at address 0x1d229bb>)
at source/jmact/animlib.c:180
#2 0x001e212c in renderframe (framenumber=0, pagepointer=0xb4df0b78)
at source/jmact/animlib.c:239
#3 0x001e2198 in drawframe (framenumber=0) at source/jmact/animlib.c:253
#4 0x001e2a98 in ANIM_DrawFrame (framenumber=1) at source/jmact/animlib.c:330
#5 0x000cf2d0 in G_PlayAnim (fn=0x26a658 "logo.anm", t=5 '\005')
at source/anim.c:261
#6 0x0006bccc in G_DisplayLogo () at source/game.c:8668
#7 0x0007055c in app_main (argc=1, argv=0xbeedbdf4) at source/game.c:9960
#8 0x00250f20 in main (argc=1, argv=0xbeedbdf4) at src/sdlayer.c:208
Crash位置在第11行
static void decodeframe(uint8_t * srcP, uint8_t * dstP)
{
do
{
int32_t count=*srcP++;
if (!count) /* Short RLE */
{
int32_t color = *(srcP+1);
count = *(uint8_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t));
Bmemset((dstP += count) - count, color, count);
continue;
}
else if ((count & 0x80) == 0) /* Short copy */
{
Bmemcpy((dstP += count) - count, (srcP += count) - count, count);
continue;
}
else if ((count &= ~0x80) > 0) /* short skip */
{
dstP += count;
continue;
}
/* long op */
count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t))));
if (!count) /* stop sign */
return;
else if ((count & 0x8000) == 0) /* long skip */
{
dstP += count;
continue;
}
else if ((count &= ~0x8000) & 0x4000) /* long RLE */
{
int32_t color = *srcP++;
count &= ~0x4000;
Bmemset((dstP += count) - count, color, count);
continue;
}
/* long copy */
Bmemcpy((dstP += count) - count, (srcP += count) - count, count);
}
while (1);
}
但是仔細追查後,發現有問題是這行
count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t))));
改寫比較容易看懂的程式
count = B_LITTLE16(*(uint16_t *)srcP); srcP += sizeof(int16_t);
GDB看了一下
count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t)))); (gdb) p/x count $2 = 0x9d80 (gdb) x/16x srcP-4 0xb4dc9b81: 0x8000 0xd99d 0x0000 0x2605 0x2d80 0x00c1 0x2605 0x2826 0xb4dc9b91: 0x280b 0x0600 0x0b0b 0x0b16 0x1a16 0x1a0b 0x0b1a 0x0b1a
srcP的位址是0xb4dc9b83,所以*(uint_16_t*)srcP應該是拿到0xd99d,但是結果竟然是0x9d80
司徒也不知道為何LDRH是取低位址的值(0xb4dc9b83 ~ 0xb4dc9b82),而不是高位址的值(0xb4dc9b84 ~ 0xb4dc9b83)
(gdb) stepi 0x001e1f08 <+304>: sub r3, r3, #2 => 0x001e1f0c <+308>: ldrh r3, [r3] 0x001e1f10 <+312>: str r3, [r11, #-8] 0x001e1f14 <+316>: ldr r3, [r11, #-8] (gdb) info r r3 0xb4dc9b83 3034356611 (gdb) stepi 0x001e1f08 <+304>: sub r3, r3, #2 0x001e1f0c <+308>: ldrh r3, [r3] => 0x001e1f10 <+312>: str r3, [r11, #-8] 0x001e1f14 <+316>: ldr r3, [r11, #-8] (gdb) info r r3 0x9d80 40320
因此,使用一個workaround的方式修掉
//count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t)))); count = B_LITTLE16(srcP[0] + (((uint16_t)srcP[1]) << 8)); srcP += sizeof(int16_t);