由于memcpy的实现使用了lr寄存器,所以当SIGSEGV发生在memcpy中时,Call Stack未必能很好地追踪出来。
这时可以根据Stack中地址上的符号寻找可能的函数,然后确定发生在memcpy中的是什么问题。
几个示例如下。
(1)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint:
pid: 325, tid: 4048, name: ExtOutThread >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 41cfe000
r0 4180a190 r1 41cfddc0 r2 00000c00 r3 00000000
r4 4134dee0 r5 40071c18 r6 b3634400 r7 40fbf47c
r8 40fc0d30 r9 40fc0d7c sl 41cfe000 fp 4312deb0
ip 00000020 sp 4312de48 lr 00000280 pc 4019f29c cpsr 20000010
d0 0000000000000000 d1 0000000000000000
d2 0000000000000000 d3 0000000000000000
d4 0000000000000000 d5 0000000000000000
d6 0000000000000000 d7 0000000000000000
d8 0000000000000000 d9 0000000000000000
d10 0000000000000000 d11 0000000000000000
d12 0000000000000000 d13 0000000000000000
d14 0000000000000000 d15 0000000000000000
d16 20676e696c6c6143 d17 7274705f636e7973
d18 0000000000000000 d19 0000000000000000
d20 0000000000000000 d21 0000000000000000
d22 0000000000000000 d23 0000000000000000
d24 0000000000000000 d25 0000000000000000
d26 0000000000000000 d27 0000000000000000
d28 0000000000000000 d29 0000000000000000
d30 0000000000000000 d31 0000000000000000
scr 80000010
backtrace:
#00 pc 0000e29c /system/lib/libc.so
#01 pc 00026d78 /system/lib/hw/audio.primary.msm8960.so
stack:
4312de08 00000000
4312de0c 00000000
4312de10 00000000
4312de14 00000000
4312de18 00000000
4312de1c 00000000
4312de20 00000000
4312de24 7cea8fed
4312de28 40071c18
4312de2c 00000000
4312de30 00000000
4312de34 40fbf47c /system/lib/hw/audio.primary.msm8960.so
4312de38 00000020
4312de3c 7cea8fed
4312de40 df0027ad
4312de44 00000000
#00 4312de48 4180a010 r0
4312de4c 40fc0d7c /system/lib/hw/audio.primary.msm8960.so r9
#01 4312de50 00000000 r10
4312de54 40fb8e88 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+352) lr
4312de58 00000300
4312de5c 00000300
4312de60 00000157
4312de64 4312deb4 [stack:4048]
4312de68 4134de50 [heap]
4312de6c 00000000 r4
4312de70 4134ddc8 [heap] r5
4312de74 41915bc8 r6
4312de78 4180ac10 l7
4312de7c 4134de4c [heap] r8
4312de80 00000000 r9
4312de84 40fba94c /system/lib/hw/audio.primary.msm8960.so r10
4312de88 00003e80 r11
4312de8c 40fa8334 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+488) lr
memory near r0:
4180a170 00000000 00000000 00000000 00000000 ................
4180a180 00000000 00000000 00000000 00000000 ................
4180a190 00000000 00000000 00000000 00000000 ................
4180a1a0 00000000 00000000 00000000 00000000 ................
4180a1b0 00000000 00000000 00000000 00000000 ................
memory near r1:
41cfdda0 ffffffff ffffffff ffffffff ffffffff ................
41cfddb0 ffffffff ffffffff ffffffff ffffffff ................
41cfddc0 ffffffff ffffffff ffffffff ffffffff ................
41cfddd0 ffffffff ffffffff ffffffff ffffffff ................
41cfdde0 ffffffff ffffffff ffffffff ffffffff ................
memory near r4:
4134dec0 00000000 00000000 00000000 00000000 ................
4134ded0 00000000 4127b638 419112c8 000000f3 ....8.'A...A....
4134dee0 40fc2ab0 6c616e61 4100676f 4134c327 .*[email protected]'.4A
4134def0
可以看出,backtrace由于使用LR寄存器来反推,memcpy的调用函数并不对,所以得出的backtrace并不准确。
这时可以通过
4312de54 40fb8e88 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+352)
4312de8c 40fa8334 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+488)
来确定调用栈。
(gdb) info symbol 'android_audio_legacy::ALSADevice::readFromProxy'
_ZN20android_audio_legacy10ALSADevice13readFromProxyEPPvPl in section .text
(gdb)disass 'android_audio_legacy::ALSADevice::readFromProxy' or
(gdb)disass _ZN20android_audio_legacy10ALSADevice13readFromProxyEPPvPl
Dump of assembler code for function android_audio_legacy::AudioHardwareALSA::extOutThreadFunc():
0x0000e14c <+0>: ldr r3, [r0, #116] ; 0x74
0x0000e150 <+4>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x0000e154 <+8>: cmp r3, #0
0x0000e158 <+12>: sub sp, sp, #52 ; 0x34
0x0000e15c <+16>: mov r5, r0
0x0000e160 <+20>: beq 0xe564 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+1048>
0x0000e164 <+24>: ldr r0, [r0, #8]
0x0000e168 <+28>: bl 0x1f484 <android_audio_legacy::ALSADevice::isProxyDeviceOpened()>
0x0000e16c <+32>: cmp r0, #0
...................................................
0x0000e2e8 <+412>: bl 0x8e10
0x0000e2ec <+416>: add sp, sp, #52 ; 0x34
0x0000e2f0 <+420>: pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
0x0000e2f4 <+424>: ldr r0, [r5, #8]
0x0000e2f8 <+428>: bl 0x1f484 <android_audio_legacy::ALSADevice::isProxyDeviceOpened()>
0x0000e2fc <+432>: cmp r0, #0
0x0000e300 <+436>: beq 0xe228 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+220>
0x0000e304 <+440>: ldr r0, [r5, #8]
0x0000e308 <+444>: bl 0x1f4ac <android_audio_legacy::ALSADevice::isProxyDeviceSuspended()>
0x0000e30c <+448>: cmp r0, #0
0x0000e310 <+452>: bne 0xe228 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+220>
0x0000e314 <+456>: cmp r9, #0
0x0000e318 <+460>: bne 0xe228 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+220>
0x0000e31c <+464>: mov r0, r8
0x0000e320 <+468>: bl 0x8e70
0x0000e324 <+472>: ldr r0, [r5, #8]
0x0000e328 <+476>: add r1, sp, #32
0x0000e32c <+480>: add r2, sp, #36 ; 0x24
0x0000e330 <+484>: bl 0x1ed28 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)>
0x0000e334 <+488>: subs r6, r0, #0
Dump of assembler code for function android_audio_legacy::ALSADevice::readFromProxy(void**, long*):
0x0001ed28 <+0>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x0001ed2c <+4>: sub sp, sp, #20
0x0001ed30 <+8>: mov r4, r0
0x0001ed34 <+12>: mov r11, r1
0x0001ed38 <+16>: str r2, [sp, #12]
0x0001ed3c <+20>: bl 0x1eb48 <android_audio_legacy::ALSADevice::initProxyParams()>
0x0001ed40 <+24>: mov r0, r4
0x0001ed44 <+28>: bl 0x1ebe4 <android_audio_legacy::ALSADevice::startProxy()>
0x0001ed48 <+32>: subs r6, r0, #0
0x0001ed4c <+36>: bne 0x1efc4 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+668>
0x0001ed50 <+40>: ldr r7, [pc, #808] ; 0x1f080 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+856>
.......................................................
0x0001ee64 <+316>: cmp r6, r3
0x0001ee68 <+320>: strhi r3, [r4, #224] ; 0xe0
0x0001ee6c <+324>: bl 0x9320
0x0001ee70 <+328>: mov r1, r0
0x0001ee74 <+332>: ldr r0, [r4, #184] ; 0xb8
0x0001ee78 <+336>: cmp r0, #0
0x0001ee7c <+340>: beq 0x1f068 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+832>
0x0001ee80 <+344>: ldr r2, [r4, #180] ; 0xb4
=> 0x0001ee84 <+348>: bl 0x8f78
根据在同一个库文件中的extOutThreadFunc()和readFromProxy(...)的保存寄存器压栈个数和局部变量压栈字节,可以确认调用栈和数据栈的正确性。
本例的保存寄存器已经在数据栈中做了标注。
而且可以得到audio.primary.msm8960.so库的重定位偏移:
relocation offset of audio.primary.msm8960.so: 40fb8e88 - 0x1ee88 = 0x40F9A000.
从而调用栈如下:
#00 pc 0000e29c /system/lib/libc.so memcpy(...)
#01 pc 40fb8e88 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+352) lr
#02 pc 40fa8334 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+488) lr
对应ALSADevice::readFromProxy源码如下:
2008ssize_t ALSADevice::readFromProxy(void **captureBuffer , ssize_t *bufferSize) {
2020 struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle;
2073 void *data = dst_address(capture_handle);
2074 //TODO: Return a pointer to AudioHardware
2075 if(mProxyParams.mCaptureBuffer == NULL)
2076 mProxyParams.mCaptureBuffer = malloc(mProxyParams.mCaptureBufferSize); /* NG, no malloc success test */
2077 memcpy(mProxyParams.mCaptureBuffer, (char *)data, mProxyParams.mCaptureBufferSize); !!!crash!!!
2079 mProxyParams.mX.frames -= mProxyParams.mFrames;
在memcpy中r0, r1, r2用来传参,大部分实现版本在copy过程中r0-r2会被修改,r0,r1会增加,r2会减少。
r10 is used for source address advance validity detection in every copy loop.
可以通过其汇编实现考察,多数情况下r0会被压栈保存。可以结合memcpy caller一起来获取更多信息。
本版本的memcpy会把{r0, r9, r10, lr}压栈,从而可知保存的目标buffer首地址。
本例中,从栈上得到r0的初始值为0x4180a010;很难从ALSADevice::readFromProxy(...)获得其它参数信息。
出错的指令是,ldr r3, [r10],使用r10探测一下源buffer界限是否还有效。
所以是源buffer不够长或者字节数太大。更多地,
r2 0x0c00 bytes will be copied in current copy loop.
r0 - r0_saved = 4180a190 - 4180a010(saved on stack) = 0x0180 bytes has been copied to destination.
Source buffer size is less than 0x280 less than 0xc00, and leads to the buffer violate access.
Reference:
use the minimum size as argument size to avoid crash.
(2)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint:
pid: 309, tid: 27139, name: mediaserver >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 41be1000
r0 44f91c08 r1 41be0c40 r2 001d4c00 r3 00000000
r4 40e83863 r5 43415998 r6 00000640 r7 001d4c00
r8 000004b0 r9 00000000 sl 41be1000 fp 4081dec9
ip 00007030 sp 43bfcb80 lr 00000408 pc 4028171c cpsr 20000010
d0 0000000000000000 d1 0000000000000000
d2 0000000000000000 d3 0000000000000000
d4 0000000000000000 d5 0000000000000000
d6 0000000000000000 d7 0000000000000000
d8 0000000000000000 d9 0000000000000000
d10 0000000000000000 d11 0000000000000000
d12 0000000000000000 d13 0000000000000000
d14 0000000000000000 d15 0000000000000000
d16 46737365636f7270 d17 3d203120656d6172
d18 696f72646e612074 d19 656d6143513a3a64
d20 6d61657274536172 d21 776569766572705f
d22 7365636f72703a3a d23 7765697665725073
d24 3ff009bb63fc01c8 d25 000000000000374c
d26 0000000000000000 d27 0000000000000000
d28 0000000000000000 d29 0000000000003b66
d30 00000000000035bb d31 00000000000035ab
scr 60000010
backtrace:
#00 pc 0001871c /system/lib/libc.so
#01 pc 00000404 <unknown>
stack:
43bfcb40 ffffffff
43bfcb44 00000000
43bfcb48 fffffff0
43bfcb4c 43bfcba4 [stack:27139]
43bfcb50 4187de80
43bfcb54 00000001
43bfcb58 001d4c00
43bfcb5c 00000640
43bfcb60 001d4c00
43bfcb64 000004b0
43bfcb68 43bfcbd4 [stack:27139]
43bfcb6c 4081de4d /system/lib/libcameraservice.so
43bfcb70 4081dec9 /system/lib/libcameraservice.so
43bfcb74 4027af31 /system/lib/libc.so (dlcalloc+44)
43bfcb78 df0027ad
43bfcb7c 00000000
#00 43bfcb80 44f7e008
........ ........
#01 43bfcb80 44f7e008 r0
43bfcb84 43bfcbd4 [stack:27139] r9
43bfcb88 4081de4d /system/lib/libcameraservice.so r10
43bfcb8c 40e7ade3 /system/lib/hw/camera.msm8960.so (android::CustemedFace::processFrame(camera_memory*)+114) lr
43bfcb90 43415998
43bfcb94 43bfcbd4 [stack:27139]
43bfcb98 002bf200
43bfcb9c 42f12308
43bfcba0 43bfcc70 [stack:27139]
43bfcba4 42f12340
43bfcba8 40e8ad44 /system/lib/hw/camera.msm8960.so
43bfcbac 00000043
43bfcbb0 00000030
43bfcbb4 40e743b3 /system/lib/hw/camera.msm8960.so (android::QCameraStream_preview::processPreviewFrameWithDisplay(mm_camera_ch_data_buf_t*)+1306)
43bfcbb8 00000000
43bfcbbc 00000000
memory near r0:
44f91be8 00000000 00000000 00000000 00000000
44f91bf8 00000000 00000000 00000000 00000000
44f91c08 00000000 00000000 00000000 00000000
memory near r1:
41be0c20 ffffffff ffffffff ffffffff
同样可以看出backtrace有问题,从0001871c /system/lib/libc.so可以知道问题发生在memcpy()中且
0x0001871c <+220>: ldr r3, [r10]
同样是源buffer探测指令处。源buffer长度小于第三参数。
backtrace:
#00 pc 0001871c /system/lib/libc.so
#01 pc 40e7ade3 /system/lib/hw/camera.msm8960.so (android::CustemedFace::processFrame(camera_memory*)+114)
该栈打印出的地址好像有点错误,与反汇编出的代码地址不符。
r0_current - r0_saved = 0x44f91c08 - 0x44f7e008 = 0x13C00
r1_current 0x41be0c40
r2 001d4c00
588void CustemedFace::processFrame(camera_memory_t *mem) {
589 size_t size;
590 int width, height;
592 if (checkAndSetProcessingFrame()) {
593 // set the size of the gray scale map for the color format YUV420SP
594 size = (mem->size * 2) / 3;
596
597 // Avoid using mParameters.getPreviewSize as the parameter get / set is not safty in OS layer
598 // Add protection before calloc memory for mLuminanceMap
599 width = mQualcommCameraHardware->mPreviewWidth;
600 height = mQualcommCameraHardware->mPreviewHeight;
601
602 if (size == (size_t)(width * height)) {
604 // allocate the gray scale map to process
605 mLuminanceMap = (unsigned char *) calloc(size, sizeof(unsigned char));
606 if (mLuminanceMap) {
607 // copy the luminance from the frame with color format YUV420SP
608 memcpy(mLuminanceMap, (uint8_t *) mem->data, size);
(3)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint:
pid: 166, tid: 946, name: Binder_2 >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 40217000
r0 40216ff0 r1 4149eb0c r2 fffff670 r3 0000000f
r4 400e1230 r5 ffffffff r6 4149e1fd r7 00000000
r8 400e10d8 r9 fffffffd sl 4031ba6c fp 00000001
ip e0000000 sp 4215ab30 lr 00000000 pc 402d9240 cpsr a0000010
d0 ae4c01642bc9b676 d1 f3d8a10701d62264
d2 51d1c9c899b526b5 d3 2c4466025d9d9d23
d4 1c1965106cb060dd d5 ef57a9e63c0f8a7b
d6 f58ae0ebc8c7e486 d7 e7abcebee67d0fed
d8 00000000003cff3f d9 0000000000000000
d10 0000000000000000 d11 0000000000000000
d12 0000000000000000 d13 0000000000000000
d14 0000000000000000 d15 0000000000000000
d16 ffffffffffffffff d17 ffffffffffffffff
d18 ffffffffffffffff d19 ffffffffffffffff
d20 ffffffffffffffff d21 ffffffffffffffff
d22 ffffffffffffffff d23 ffffffffffffffff
d24 3ff01272163691fc d25 0000000000000000
d26 0000000000000000 d27 0000000000000000
d28 0000000000000000 d29 0000000000000000
d30 0000000000000000 d31 0000000000000000
scr 20000010
backtrace:
#00 pc 0000e240 /system/lib/libc.so
#01 pc 000509d1 /system/lib/libmedia.so (android::AutoDetect::addString(char const*, int)+60)
#02 pc 000bc047 /system/lib/libstagefright.so (android::ID3::getEncodingSuggestion() const+58)
#03 pc 000bc263 /system/lib/libstagefright.so (android::ID3::ID3(android::sp<android::DataSource> const&, long long)+66)
这个调用栈是对的。
stack:
4215aaf0 00000000
4215aaf4 00000000
4215aaf8 4215ab50 [stack:946]
4215aafc 40935e67 /system/lib/libstagefright.so (android::ID3::Iterator::findFrame()+190)
4215ab00 4215ab50 [stack:946]
4215ab04 40935e67 /system/lib/libstagefright.so (android::ID3::Iterator::findFrame()+190)
4215ab08 00000000
4215ab0c 4097c772 /system/lib/libstagefright.so
4215ab10 00000000
4215ab14 00000000
4215ab18 00000000
4215ab1c 4215ab50 [stack:946]
4215ab20 4215ab68 [stack:946]
4215ab24 4215abf4 [stack:946]
4215ab28 df0027ad
4215ab2c 00000000
#00 4215ab30 40216741 r0
4215ab34 4038a9d5 /system/lib/libmedia.so (android::AutoDetect::addString(char const*, int)+64) lr
#01 4215ab38 4215abf4 [stack:946] r4
4215ab3c 4215ab4c [stack:946] r5
4215ab40 00001f40 r6
4215ab44 4093604b /system/lib/libstagefright.so (android::ID3::getEncodingSuggestion() const+62) lr
#02 4215ab48 00000000
4215ab4c ffffffff
4215ab50 4215abf4 [stack:946]
4215ab54 00000000
4215ab58 000061ea
4215ab5c 400e1230
4215ab60 4149e1fc
4215ab64 0000000a
4215ab68 400e1230
4215ab6c 4215abf4 [stack:946]
4215ab70 400e1230
4215ab74 40936267 /system/lib/libstagefright.so (android::ID3::ID3(android::sp<android::DataSource> const&, long long)+70)
#03 4215ab78 00000000
4215ab7c 400e10b8
4215ab80 400e10c8
4215ab84 408ddcb7 /system/lib/libstagefright.so (android::MP3Extractor::MP3Extractor(android::sp<android::DataSource> const&, android::sp<android::AMessage> const&)+594)
1141void AutoDetect::addString(const char* str, int numBytes) {
1142 // No need to store strings unless we will attempt to detect a two-byte encoding.
1143 if (str != NULL && mLocaleEncoding & ~kOneByteEncodings) {
1144 if (mAddedStringSize < mAddedStringLen + numBytes) {
1145 // Grow space
1146 while (mAddedStringSize < mAddedStringLen + numBytes) {
1147 mAddedStringSize += 128;
1148 }
1149 mAddedStrings = (char*)realloc(mAddedStrings, mAddedStringSize);
1150 }
1151
1152 if (mAddedStrings) {
1153 memcpy(mAddedStrings + mAddedStringLen, str, numBytes);
1154 mAddedStringLen += numBytes;
1155 }
1156 }
1157}
From the call trace and source code, the root cause is
When the MediaExtractor try to extract mp3 ID3 tag information, it encounters the SIGSEGV:SEGV_MAPERR crash when doing memcpy.
Dump of assembler code for function android::AutoDetect::addString(char const*, int):
0x00050994 <+0>: push {r4, r5, r6, lr}
0x00050996 <+2>: mov r4, r0
0x00050998 <+4>: mov r6, r1
0x0005099a <+6>: mov r5, r2
0x000509ca <+54>: mov r1, r6
0x000509cc <+56>: adds r0, r3, r2
0x000509ce <+58>: mov r2, r5
0x000509d0 <+60>: blx 0x3abb4
r4-r6 are not changed until crash occurs, so use current register value.
this pointer : r4 400e1230
src_buf str : r6 4149e1fd
numBytes : r5 ffffffff
Notice the {r0, lr} pushed by memcpy on the stack
#00 4215ab30 40216741
4215ab34 4038a9d5
r0 is the start address of destination in memcpy. dst_buf = 40216741.
So, memcpy(dst=0x40216741, src=0x4149e1fd, size_t num=0xffffffff) with invalid arg numBytes -1 which is promoted to unsigned int 0xffffffff.
The memcpy starts and encounters the unmapped destination page.
r0 40216ff0 r1 4149eb0c r2 fffff670 r3 0000000f
r0 40216741->40216ff0->40217000(fault addr).
r0_current - r0_saved = 0x40216ff0 - 0x40216741 + 1 = 0x8B0
r1_current - r1_saved = 0x4149eb0c - 0x4149e1fd + 1 = 0x910
[reference solution]
Add if(numBytes>0) statement.
[END]