dSYM Address Lookup - ios

I have parsed out the addresses, file names and line numbers from a dSYM file for an iOS app. I basically have a table that maps an address to a file name and line number, which is very helpful for debugging.
To get the actual lookup address, I use the stack trace address from the crash report and use the formula specified in this answer: https://stackoverflow.com/a/13576028/2758234. So something like this.
(actual lookup address)
= (stack trace address) + (virtual memory slide) - (image load address)
I use that address and look it up on my table. The file name I get is correct, but the line number always points to the end of the function or method that was called, not the actual line that called the following function on the stack trace.
I read somewhere, can't remember where, that frame addresses have to be de-tagged, because they are aligned to double the system pointer size. So for 32-bit systems, the pointer size is 4 bytes, so we de-tag using 8-bytes, using a formula like this:
(de-tagged address) = (tagged address) & ~(sizeof(uintptr_t)*2 - 1)
where uintptr_t is the data type used for pointers in Objective-C.
After doing this, the lookup sort of works, but I have to do something like find the closest address that is less than or equal to the de-tagged address.
Question #1:
Why do I have to de-tag a stack frame address? Why in the stack trace aren't the addresses already pointing to the right place?
Question #2:
Sometimes in the crash report there seems to be a missing frame. For example, if function1() calls function2() which calls function3() which calls function4(), in my stack trace I will see something like:
0 Exception
1 function4()
2 function3()
4 function1()
And the stack trace address for function3() (frame 2, above) doesn't even point to the right line number (but it is the right file, though), even after de-tagging. I see this even when I let Xcode symbolicate a crash report.
Why does this happen?

For question #1, the addresses in an iOS crash report have three components that are taken into account: The original load address of your app, the random slide value that was added to that address when your app was launched, and the offset within the binary. At the end of the crash report, there should be a line showing the actual load address of your binary.
To compute the slide, you need to take the actual load address from the crash report and subtract the original load address. This tells you the random slide value that was applied to this particular launch of the app.
I'm not sure how you derived your table - the problem may lie there. You may want to double check by using lldb. You can load your app into lldb and tell lldb that it should be loaded at address 0x140000 (this would be the actual load address from your crash report, don't worry about slides and original load addresses)
% xcrun lldb
(lldb) target create -d -a armv7 /path/to/myapp.app
(lldb) target modules load -f myapp __TEXT 0x140000
Now lldb has your binary loaded at the actual load address of this crash report. You can do all the usual queries in lldb, such as
(lldb) image lookup -v -a 0x144100
to do a verbose lookup on address 0x144100 (which might appear in your crash report).
You can also do a nifty "dump your internal line table" command in lldb with target modules dump line-table. For instance, I compiled a hello-world Mac app:
(lldb) tar mod dump line-table a.c
Line table for /tmp/a.c in `a.out
0x0000000100000f20: /tmp/a.c:3
0x0000000100000f2f: /tmp/a.c:4:5
0x0000000100000f39: /tmp/a.c:5:1
0x0000000100000f44: /tmp/a.c:5:1
(lldb)
I can change the load address of my binary and try dumping the line table again:
(lldb) tar mod load -f a.out __TEXT 0x200000000
section '__TEXT' loaded at 0x200000000
(lldb) tar mod dump line-table a.c
Line table for /tmp/a.c in `a.out
0x0000000200000f20: /tmp/a.c:3
0x0000000200000f2f: /tmp/a.c:4:5
0x0000000200000f39: /tmp/a.c:5:1
0x0000000200000f44: /tmp/a.c:5:1
(lldb)
I'm not sure I understand what you're doing with the de-tagging of the addresses. The addresses on the call stack are the return addresses of these functions, not the call instruction - so these may point to the line following the actual method invocation / dispatch source line, but that's usually easy to understand when you're looking at the source code. If all of your lookups are pointing to the end of the methods, I think your lookup scheme may have a problem.
As for question #2, the unwind of frame #1 can be a little tricky at times if frame #0 (the currently executing frame) is a leaf function that doesn't set up a stack frame, or is in the process of setting up a stack frame. In those cases, frame #1 can get skipped. But once you're past frame #1, especially on arm, the unwind should not miss any frames.
There is one very edge-casey wrinkle when a function marked noreturn calls another function, the last instruction of the function may be a call -- with no function epilogue -- because it knows it will never get control again. Pretty uncommon. But in that case, a simple-minded symbolication will give you a pointer to the first instruction of the next function in memory. Debuggers et al use a trick where they subtract 1 from the return address when doing symbol / source line lookup to sidestep this issue, but it's not something casual symbolicators usually need worry about. And you have to be careful to not do the decr-pc trick on the currently-executing function (frame 0) because a function may have just started executing and you don't want to back up the pc into the previous function and symbolicate incorrectly.

Related

How can I trace the value of an address in memory?

As the title suggests, I want to see from where came the value of a specific address. I am debugging an ios game with lldb. This game has a muliplier value of 0.4 (how fast combos decrease). I can change this value with cheat engine, but I want to know which instruction in assembly set this value to that address so I can change this instruction with hex editor. I used to use watchpoints breakpoints etc.. for variable values, but in this case, the value is constant and it is set when the app starts immediately.
The equivalent instructions in lldb for Jester's gdb steps are:
(lldb) image lookup -va <ADDRESS>
That will tell you everything lldb knows about that address.

Alter kernel execution path using kprobes

Is it possible to alter the execution path with kprobe and terminate kernel function execution? While searching, I came across this post Replace system call in linux kernel 3
AFAIK, one can change the return value using kretprobe, but what i'm looking for is conditionally terminating kernel function execution from within kprobe handler. Has this been tried before? Thanks!
I found this in the kernel docs, so it seems doable:
Changing Execution Path
Since kprobes can probe into a running kernel code, it can change the
register set, including instruction pointer. This operation requires
maximum care, such as keeping the stack frame, recovering the
execution path etc. Since it operates on a running kernel and needs
deep knowledge of computer architecture and concurrent computing, you
can easily shoot your foot.
If you change the instruction pointer (and set up other related
registers) in pre_handler, you must return !0 so that kprobes stops
single stepping and just returns to the given address. This also means
post_handler should not be called anymore.
Note that this operation may be harder on some architectures which use
TOC (Table of Contents) for function call, since you have to setup a
new TOC for your function in your module, and recover the old one
after returning from it.

Initial stack pointer not starting at the required offset (where are the extra byte offsets coming from?)

I have this following sample code in the start-up file for Cortex-M3 taken from Keil(compiling it with Microlib).
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
EXPORT __initial_sp
Stack_Size EQU 0x00000100
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
And this area is finally placed into a RAM region starting at address 0x20000000 with size of the executable region say 0x400 in the scatter file.
When I get into the debugger I see the that the value at memory address 0x0 is 0x20000118 which is the initial stack pointer and even the register window shows the msp register as 0x20000118.
But my understanding was that the start of the stack would be from 0x20000100 because that is what the above code snippet is doing.
I am unable to get from where are these extra 0x18 bytes coming from.
Also, i just switch off the Microlib mode, now I see the initial stack pointer is 0x20000120.
Again, from where are these extra 0x20 bytes offset coming from to the stack pointer.
Why isn't stack starting from where I want it to be(0x20000100), instead having some extra offsets?
No, this code snippet doesn't say that initial stack pointer will be at 0x20000100.
Firstly, it EXPORTs symbol "__initial_sp". This only declares this symbol as "global" (accessed by other files). Next, the value 0x100 is assigned to symbol "Stack_Size". Next instructions are to create dummy "STACK" section which will be of "stack_size" size.
The initial stack pointer value will be calculated (usually) by linker script. You also need to see source code of vector table (in most cases it will be in a file called startup.s or similar) and see what symbol there is used as a first entry (is it really "__initial_sp"?).
Note, if you have (for example) 32KB of RAM and your RAM starts at 0x20000000, then you want (usually) your initial SP to be at 0x20008000 (end of RAM). If "stack size" is equal to "0x100" it means that you don't expect SP to be less than 0x20007F00. But, you can also have initial stack pointer at address that depends on size of other sections (for instance .heap or .data). This is why you can see differences when linking to standard library (it will change size of other sections).

Can the ELF entry point be different from the usual 0x80****** ? Why would that be done?

I'm playing around with a binary and when I load it into my debugger, or even run readelf, I noticed the entry point is 0x530 instead of the usual 0x80****** that'd learned ELF's were loaded at.
Why is this? Is there anything else going on? The binary is linked and not stripped.
instead of the usual 0x80****** that'd learned ELF's were loaded at.
You learned wrong.
While 0x804800 is the usual address that 32-bit x86 Linux binaries are linked at, that address is by no means universal or special.
64-bit x86_64 and aarch64 binaries are linked at default address of 0x40000, and powerpc64le binaries at default address of 0x10000000.
There is no reason a binary could not be linked at any other (page-aligned) address (so long as it is not 0, and allows for sufficient stack at the high end of the address space.
Why is this?
The binary was likely linked with a custom linker script. Nothing wrong with that.
As mentioned by Employed, the entry address is not fixed.
Just to verify, I've tried on x86_64:
gcc -Wl,-Ttext-segment=0x800000 hello_world.c
which sets the entry point to 0x800000 (+ the ELF header size, which gets loaded at 0x800000 in memory) instead of the default 0x400000.
Then both:
readelf -h a.out
and gdb -ex 'b _start' tell me the entry is at 0x800440 as expected (the header is 0x440 bytes).
This is because that value is an input that tells the Linux kernel where to set the PC when forking a new process.
The default 0x400000 comes from the default linker script used. You can also modify the linker script as mentioned in https://stackoverflow.com/a/31380105/895245 , change 0x400000 there, and use the new script with -T script
If I put it at anything below 0x200000 (2Mb) exactly or other low addresses, the program gets killed. I think this is because ld always loads the sections at multiples of 2Mb, which is the largest page size supported (in huge page), so anything lower starts at 0, which is bad: Why is the ELF execution entry point virtual address of the form 0x80xxxxx and not zero 0x0?

What's the difference of j__objc_msgSend and objc_msgSend?

I'm surprised that searching j__objc_msgSend returns 0 result on stackoverflow, and Google doesn't seem to know it well either. According to it's disassembly, j__objc_msgSend only calls objc_msgSend, then why do we need j__objc_msgSend when we have objc_msgSend already? And in general, what's the difference of j__objc_msgSend and objc_msgSend?
And in this screenshot specifically, what's the difference of the right most branch ending with "End of function", and the left most branch ending without "End of function"? Does it have something to do with j__objc_msgSend?
This is ARM RISC code, and the preferred programming mode for ARM is relative -- don't use absolute addresses, always use "IP+/-offset". Here, the called address was out of range for a direct call or jump, and the compiler used the nearest he could find. It adds an extra jump (or more than 1!) but it's position-independent. (*)
The compiler cannot construct a jump to the target address with a simple instruction, because you cannot immediately load every possible 2^32 number with RISC assembly.
If the routine objc_msgSend returns of its own, then this is equivalent to call objc_msgSend; return -- only shorter. Both forms do a single 'return', from the point of view of the current function.
(*) You can see in the disassembly screenshot (?? why not text?) that R12 gets loaded with the difference between the target and the current address. This difference is calculated by the compiler; it does not appear as a subtraction in the original binary, that's IDA's work. Then the difference is added to the current address -- whatever this is! The immediate value objc_msgSend - 0x1AE030 uses a small enough amount of bits to be loaded into R12 in a single instruction (an ARM RISC 'feature' you ought to be familiar with).
In case you are wondering about the j__label syntax: that's just IDA, telling you this is a direct jump to a known label. Presumably, if your code is long enough, you might find the distance to this label is too big again, and so you might find j__j__objc_msgSend.

Resources