1. After crash, the green information is output in logcat:
05-02 10:14:37.130: I/DEBUG(1890): backtrace:05-02 10:14:37.130: I/DEBUG(1890): #00 pc 00033fda /data/data/com.XXXXX.map/lib/libmapengine.so (TextureCache::_touchListNode(TextureCacheItem*)+25)05-02 10:14:37.130: I/DEBUG(1890): #01 pc 0003407d /data/data/com.XXXXX.map/lib/libmapengine.so (TextureCache::getTexItem(char, char, int, int)+32)05-02 10:14:37.130: I/DEBUG(1890): #02 pc 00032c9f /data/data/com.XXXXX.map/lib/libmapengine.so (prepareTiles(int, int, int, double)+158)05-02 10:14:37.130: I/DEBUG(1890): #03 pc 000332cf /data/data/com.XXXXX.map/lib/libmapengine.so (nativePrepareRender+566)05-02 10:14:37.130: I/DEBUG(1890): #04 pc 0002fb79 /data/data/com.XXXXX.map/lib/libmapengine.so (Java_com_XXXXX_map_gl_JNI_nativePrepareRender+192)05-02 10:14:37.130: I/DEBUG(1890): #05 pc 0001de70 /system/lib/libdvm.so (dvmPlatformInvoke+112)05-02 10:14:37.130: I/DEBUG(1890): #06 pc 0004d0c3 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+394)05-02 10:14:37.130: I/DEBUG(1890): #07 pc 000009e0 /dev/ashmem/dalvik-jit-code-cache (deleted)
2. Find the corresponding so package in the app and obtain the Assembly source code of SO.
Note that the so package must be compiledNoteThere are two sentences in the MK file:
cmd-strip = $(TOOLCHAIN_PREFIX)strip --strip-all -x $1-fvisibility=hidden
CMD-strip is a script used to filter compiled symbols.-fvisibility = hidden is used to hide the internal symbol table of the JNI library.
D: \ android-ndk-r7c \ toolchains \ arm-linux-androideabi-4.4.3 \ prebuilt \ windows \ bin
The following objdump tool generates the so package assembly.
Command for generating so package assembly code: arm-linux-androideabi-objdump.exe-DX libmapengine. So> temp.txt
3. Locate the problem
If you are lucky, the logcat output can be directly located in the function. The next step is to locate the number of wrong lines of code. Note that it refers to the lines of C/C ++ code rather than assembly.
Combined with so assembly and logcat output, you can directly read Arm Assembly if the function code is short. If the function is long, it will be very painful to directly read the assembly.
4. Some basic commands of arm assemble
Number of register operations loaded by LDR from a specified address,
STR saves the number of register operations to the specified address,
Add two registers,
Adds registers and values are added together,
Value assignment between mov registers,
Movs assigns a value to a register,
CMP compares two registers.
Comparison condition judgment:
B Indicates unconditional branch: http://sourceware.org/cgen/gen-doc/arm-thumb-insn.html#insn-b
Bx lr indicates that the execution of a function has ended. For details, refer to [3]
5. Example
C/C ++ source code is as follows:
Void texturecache: _ touchlistnode (texturecacheitem * node) {If (node = NULL) {return;} // move * item to team end if (tail! = Node) {// retrieve the node separately if (Head = node) {head = head-> next; head-> pre = NULL;} else {// node! = Head & node! = Tailnode-> pre-> next = node-> next; node-> next-> pre = node-> pre; // ### node-> next is empty, addressing pre causes crash ###} tail-> next = node; node-> pre = tail; tail = node; tail-> next = NULL ;}}
There are 28 lines of assembly code:
00033fc0 <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem>: 33fc0:2900 cmpr1, #0 33fc2:d012 beq.n33fea <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2a> 33fc4:68c3 ldrr3, [r0, #12] 33fc6:428b cmpr3, r1 33fc8:d00f beq.n33fea <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2a> 33fca:6883 ldrr3, [r0, #8] 33fcc:428b cmpr3, r1 33fce:d00d beq.n33fec <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2c> 33fd0:694b ldrr3, [r1, #20] 33fd2:698a ldrr2, [r1, #24] 33fd4:619a strr2, [r3, #24] 33fd6:698b ldrr3, [r1, #24] 33fd8:694a ldrr2, [r1, #20] 33fda:615a strr2, [r3, #20] 33fdc:68c3 ldrr3, [r0, #12] 33fde:6199 strr1, [r3, #24] 33fe0:68c3 ldrr3, [r0, #12] 33fe2:614b strr3, [r1, #20] 33fe4:2300 movsr3, #0 33fe6:60c1 strr1, [r0, #12] 33fe8:618b strr3, [r1, #24] 33fea:4770 bxlr 33fec:698b ldrr3, [r1, #24] 33fee:2200 movsr2, #0 33ff0:6083 strr3, [r0, #8] 33ff2:615a strr2, [r3, #20] 33ff4:e7f2 b.n33fdc <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x1c> 33ff6:46c0 nop(mov r8, r8)
Analysis:
The touchlistnode function moves the node nodes in the two-way linked list to the end of the queue. The R0 register stores the entire current object address. R0 + 8 is the head, R0 + 12 is the tailr1, And the node pointer to the function parameter is the address, that is, the value 00033fc0 in the register <_ zn12texturecache14_touchlistnodeep16texture: 2900 cmpr1, #0 33fc2: d012 beq. n33fea <_ zn12texturecache14_touchlistnodeep16texturecacheitem + 0x2a> If node is null for the first time, Jump directly to 33fea to exit function 33fc4: 68c3 ldrr3, [r0, #12] // use the R0 register to get the tail pointer 33fc6: 428b cmpr3, R1 // compare the tail and node pointer 33fc8: d00f beq. n33fea <_ zn12texturecache14_touc Hlistnodeep16texturecacheitem + 0x2a> If tail is equal to node for the second time, Jump directly to 33fea and exit the function 33fca: 6883 ldrr3, [r0, #8] // get the head pointer 33fcc: 428b cmpr3, R1 through the R0 register // compare the head and node pointer 33fce: d00d beq. n33fec <_ zn12texturecache14_touchlistnodeep16texturecacheitem + 0x2c> // head! = Node directly jumps to row 33fec to compare whether the head is equal to node for the third time. If the head is equal, directly jumps to row 33fea to exit the function 33fd0: 694b ldrr3, [R1, #20] // R3 = R1:: _ pre: Assign the node pre pointer to R3 33fd2: 698a ldrr2, [R1, #24] // r2 = R1 :: _ next: Assign the next pointer of node to R2 33fd4: 619a strr2, [R3, #24] // R3 :: _ next = r2node-> pre-> next = node-> next 33fd6: 698b ldrr3, [R1, #24] // R3 = R1: _ next; 33fd8: 694a ldrr2, [R1, #20] // r2 = R1: _ pre; 33fda: 615a strr2, [R3, #20] // R3: _ pre = R2; node-> next-> pre = No De-> pre 33fdc: 68c3 ldrr3, [r0, #12] // R3 = tail; assign the tail of the linked list to R3 33fde: 6199 strr1, [R3, #24] // R3: _ next = r1tail-> next = node 33fe0: 68c3 ldrr3, [r0, #12] // R3 = tail; take the tail of the linked list and assign it to R3 33fe2: 614b strr3, [R1, #20] // r1: _ pre = R3; node-> pre = tail 33fe4: 2300 movsr3, #0 // reset R3 register clear R3 register 33fe6: 60c1 strr1, [r0, #12] // tail = node; Convert r1 (node) assign R0 + 12, that is, tail 33fe8: 618b strr3, [R1, #24] // r1: _ next = R3; assign r3 Give the next pointer to R1. At this time, R3 is equal to 0 33fea: 4770 bxlr // The sub-function execution is complete! 33fec: 698b ldrr3, [R1, #24] // R3 = R1: _ next; 33133: 2200 movsr2, #0 // reset R2 register 33ff0: 6083 strr3, [r0, #8] // R0: _ head = R3; 33ff2: 615a strr2, [R3, #20] // R3: _ pre = R2; # r2 = 0 #33ff4: e7f2 B. n33fdc <_ zn12texturecache14_touchlistnodeep16texturecacheitem + 0x1c> jump to 33fdc line unconditionally and execute 33ff6: 46c0 Nop (mov R8, R8)
Combined with the first part of the crash stack top information: #00 PC 00033fda, corresponds to33fdaLine. by reading the assembly code, you can know the C/C ++ source code of line 33fda:
Node-> next-> pre = node-> pre;
Crash reasonIt is because [R3, #20] The addressing error is that node-> next is empty and node-> next-> pre is executed.
6. refer:
1. http://sourceware.org/cgen/gen-doc/arm-thumb-insn.html
2. http://www.peter-cockerell.net/aalp/html/ch-3.html
3. http://hi.baidu.com/wuqi19881003/item/f293c7a7e228e613a8cfb756