I'm having some fun with context switching. I've copied the example code into a file
http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.html
and i defined the macro _XOPEN_SOURCE for OSX.
#define _XOPEN_SOURCE
#include <stdio.h>
#include <ucontext.h>
static ucontext_t ctx[3];
static void
f1 (void)
{
puts("start f1");
swapcontext(&ctx[1], &ctx[2]);
puts("finish f1");
}
static void
f2 (void)
{
puts("start f2");
swapcontext(&ctx[2], &ctx[1]);
puts("finish f2");
}
int
main (void)
{
char st1[8192];
char st2[8192];
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = sizeof st1;
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], f1, 0);
getcontext(&ctx[2]);
ctx[2].uc_stack.ss_sp = st2;
ctx[2].uc_stack.ss_size = sizeof st2;
ctx[2].uc_link = &ctx[1];
makecontext(&ctx[2], f2, 0);
swapcontext(&ctx[0], &ctx[2]);
return 0;
}
I build it
gcc -o context context.c -g
winges at me about get, make, swap context being deprecated. Meh.
When I run it it just hangs. It doesn't seem to crash. It just hangs.
I tried using gdb, but once I step into the swapcontext, it just is blank. It doesn't jump into f1. I just keep hitting enter and it will just move the cursor into a new line on the console?
Any idea what's a happening? Something to do with working on the Mac/deprecate methods?
Thanks
It looks like your code is just copy/pasted from the ucontext documentation, which must make it frustrating that it's not working...
As far as I can tell, your stacks are just too small. I couldn't get it to work with any less than 32KiB for your stacks.
Try making these changes:
#define STACK_SIZE (1<<15) // 32KiB
// . . .
char st1[STACK_SIZE];
char st2[STACK_SIZE];
yup fixed it. why did it fix it though?
Well, let's dig into the problem a bit more. First, let's find out what's actually going on.
When I run it it just hangs. It doesn't seem to crash. It just hangs.
If you use some debugger-fu (be sure to use lldb—gdb just doesn't work right on os x), then you will find that when the app is "hanging", it's actually spinning in a weird loop in your main function, illustrated by the arrow in the comments below.
int
main (void)
{
char st1[8192];
char st2[8192];
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = sizeof st1;
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], f1, 0);
getcontext(&ctx[2]);// <---------------------+ back to here
ctx[2].uc_stack.ss_sp = st2;// |
ctx[2].uc_stack.ss_size = sizeof st2;// |
ctx[2].uc_link = &ctx[1];// |
makecontext(&ctx[2], f2, 0); // |
// |
puts("about to swap...");// |
// |
swapcontext(&ctx[0], &ctx[2]);// ------------+ jumps from here
return 0;
}
Note that I added an extra puts call above in the middle of the loop. If you add that line and compile/run again, then instead of the program just hanging you'll see it start spewing out the string "about to swap..." ad infinitum.
Obviously something screwy is going on based on the given stack size, so let's just look for everywhere that ss_size is referenced...
(Note: The authoritative source code for the Apple ucontext implementation is at https://opensource.apple.com/source/, but there's a GitHub mirror that I'll use since it's nicer for searching and linking.)
If we take a look at makecontext.c, we see something like this:
if (ucp->uc_stack.ss_size < MINSIGSTKSZ) {
// fail without an error code since makecontext is a void function
return;
}
Well, that's nice! What is MINSIGSTKSZ? Well, let's take a look in signal.h:
#define MINSIGSTKSZ 32768 /* (32K)minimum allowable stack */
#define SIGSTKSZ 131072 /* (128K)recommended stack size */
Apparently these values are actually part of the POSIX standard. Although I don't see anything in the ucontext documentation that references these values, I guess it's kind of implied since ucontext preserves the current signal mask.
Anyway, this explains the screwy behavior we're seeing. Since the makecontext call is failing due to the stack size being too small, the call to getcontext(&ctx[2]) is what is setting up the contents of ctx[2], so the call to swapcontext(&ctx[0], &ctx[2]) just ends up swapping back to that line again, creating the infinite loop...
Interestingly, MINSIGSTKSZ is 32768 bytes on os x, but only 2048 bytes on my linux box, which explains why it worked on linux but not os x.
Based on all of that, it looks like a safer option is use the recommended stack size from sys/signal.h:
char st1[SIGSTKSZ];
char st2[SIGSTKSZ];
That, or switch to something that isn't deprecated. You might take a look at Boost.Context if you're not averse to C++.
Related
It's a kind of training task, because nowadays these methods (I guess) don't work anymore.
Win XP and MinGW compiler are used. No special compiler options are involved (just gcc with stating one source file).
First of all, saving an address to exit from the program and jumping to the some Hook function:
// Our system uses 4 bytes for addresses.
typedef unsigned long int DWORD;
// To save an address of the exit from the program.
DWORD addr_ret;
// An entry point.
int main()
{
// To make a direct access to next instructions.
DWORD m[1];
// Saving an address of the exit from the program.
addr_ret = (DWORD) m[4];
// Replacing the exit from the program with a jump to some Hook function.
m[4] = (DWORD) Hook;
// Status code of the program's execution.
return 0;
}
The goal of this code is to get an access to the system's privileges level, because when we return (should return) to the system, we just redirecting our program to some of our methods. The code of this method:
// Label's declaration to make a jump.
jmp_buf label;
void Hook()
{
printf ("Test\n");
// Trying to restore the stack using direct launch (without stack's preparation) of the function (we'll wee it later).
longjmp(label, 1);
// Just to make sure that we won't return here after jump's (from above) finish, because we are not getting stuck in the infinite loop.
while(1) {}
}
And finally I'll state a function which (in my opinion) should fix the stack pointer - ESP register:
void FixStack()
{
// A label to make a jump to here.
setjmp(label);
// A replacement of the exit from this function with an exit from the whole program.
DWORD m[1];
m[2] = addr_ret;
}
Of course we should use these includes for the stated program:
#include <stdio.h>
#include <setjmp.h>
The whole logic of the program works correctly in my system, but I can not restore my stack (ESP), so the program returns an incorrect return code.
Before the solution described above, I didn't use jumps and FixStack function. I mean that these lines were in the Hook function instead of jump and while cycle:
DWORD m[1];
m[2] = addr_ret;
But with this variant I was getting an incorrect value in ESP register before an exit from the program (it was on 8 bytes bigger then this register's value before an enter in this program). So I decided to add somehow these 8 bytes (avoiding any ASM code inside of the C program). It's the purpose of the jump into the FixStack function with an appropriate exit from it (to remove some values from stack). But, as I stated, it doesn't return a correct status of the program's execution using this command:
echo %ErrorLevel%
So my question is very wide: beginning from asking of some recommendations in a usage of debugging utilities (I was using only OllyDbg) and ending in possible solutions for the described Hook's implementation.
Ok, I could make my program work, as it was intended, finally. Now we can launch compiled (I use MinGW in Win XP) program without any errors and with correct return code.
Maybe will be helpful for someone:
#include <stdio.h>
#include <setjmp.h>
typedef unsigned long int DWORD;
DWORD addr_ret;
int FixStack()
{
DWORD m[1];
m[2] = addr_ret;
// This line is very necessary for correct running!
return 0;
}
void Hook()
{
printf("Test\n");
FixStack();
}
int main()
{
DWORD m[1];
addr_ret = (DWORD) m[4];
m[4] = (DWORD) Hook;
}
Of course it seems that you've realized that this will only work with a very specific build environment. It most definitely won't work on a 64-bit target (because the addresses aren't DWORD-ish).
Is there any reason why you don't want to use the facilities provided by the C standard library to do exactly this? (Or something very similar to this.)
#include <stdlib.h>
void Hook()
{
printf("Test\n");
}
int main()
{
atexit(Hook);
}
I have to find out the size of a instruction which I have in memory (actually, I have a small code segment in memory and want to get the size of the first instruction).
It took me some time to find libopcodes and libbfd. I red the headers and tried to come up with a simple solution but it seems like I missunderstood something since the program always crashes:
int main(int argc, char **argv) {
disassemble_info *dis = malloc(sizeof(*dis));
assert(dis != NULL);
dis->arch = bfd_arch_i386;
dis->read_memory_func = buffer_read_memory;
dis->buffer_length = 64;
dis->buffer = malloc(dis->buffer_length);
memset(dis->buffer, 0x90, dis->buffer_length);
disassemble_init_for_target(dis);
int instr_size = print_insn_i386(0, dis);
printf("instruction size is %d\n", instr_size);
return 0;
}
The expected result would be an instruction size of 1 (nop).
EDIT:
sorry guys, I'm a stupid person.
memset(dis, 0, sizeof(*dis));
There is some code in the Linux kernel you can steal. It should work well if copied into a user mode program.
Take a look at arch/x86/lib and arch/x86/tools
There's an opcode map file there, and an awk script that reads it to produce a table in a file named innat.c. There are some other files there that use the table to implement a decoder.
It is sufficient to determine instruction sizes.
This assumes you are ok with GPL, of course.
It looks like the disassemble_info data structure requires more initialization than you have provided. From examples I have been studying, the correct way to initialize is to call init_disassemble_info().
See if that helps. Failing that, compile your program with debug info ('-g') and run gdb to diagnose where the crash occurs.
Okay we are given the following code:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "callstack.h"
#include "tweetIt.h"
#include "badguy2.c"
static char *correctPassword = "ceriaslyserious";
char *message = NULL;
int validateSanity(char *password) {
for(int i=0;i<strlen(password);i++)
if(!isalpha(password[i]))
return 0;
unsigned int magic = 0x12345678;
return badguy(password);
}
int validate(char *password) {
printf("--Validating something\n", password);
if (strlen(password) > 128) return 0;
char *passwordCopy = malloc(strlen(password) + 1);
strcpy(passwordCopy, password);
return validateSanity(passwordCopy);
}
int check(char *password, char *expectedPassword) {
return (strcmp(password, expectedPassword) == 0);
}
int main() {
char *password = "wrongpassword";
unsigned int magic = 0xABCDE;
char *expectedPassword = correctPassword;
if (!validate(password)) {
printf("--Invalid password!\n");
return 1;
}
if (check(password, expectedPassword)) {
if (message == NULL) {
printf("--No message!\n");
return 1;
} else {
tweetIt(message, strlen(message));
printf("--Message sent.\n");
}
} else {
printf("--Incorrect password!\n");
}
return 0;
}
We are supposed to trick main into sending a tweet using the function badguy. In badguy we have an offset from a previous problem which is the difference between the declaration of password in main and the argument passed to badguy. We have been instructed to use this offset to find the addresses of the correctPassword and password in main and manipulate the value in password to correctPassword so when the password check occurs, it is believed to be legitimate. I am having some trouble figuring out how to use this offset to find the addresses and continuing from there.
First of all, make sure you have good control over your compiler behavior. That is: make sure you know the calling conventions and that they're being respected (not optimized away or altered in any manner). This usually boils down to turn off optimization settings, at least for testing under more controlled conditions until a robust method is devised. Pay special attention to variables such as expectedPassword, since it is highly likely they'll be optimized away (expectedPassword might never be created in the stack, being substituted with the equivalent of correctPassword, rendering you with no stack reference to the correct password at all).
Secondly, note that "wrongpassword" is shorter than "ceriaslyserious"; in other words, if I got it straight, attempting to crack into the buffer pointed to by passwordCopy (whose size is the length of "wrongpassword" plus one) in order to copy "ceriaslyserious" into there could result in a segmentation violation. Nonetheless, it should be relatively simple to track the address of expectedPassword in the call stack, if it exists (see above), specially if you do have already an offset from main()'s stack frame.
Considering an x86 32-bit target under controlled circumstances, expectedPassword will reside 8 bytes below password (4 for password, 4 for magic if it is not optimized away). Having an offset from password to a parameter as you said, it should suffice to subtract the offset from the address of that parameter, and then add 8. The resulting pointer should be expectedPassword, which then points to the static area containing the password. Again, double check your environment. Check this for an explanation on the stack layout in x64 (the layout in the 32-bit case is similar).
Lastly, if expectedPassword does not exist in the call stack, then, since correctPassword is a global static, it will reside in a data segment, rendering the method useless. To achieve the goal in this situation, you would need to carefully scan the data segment with a more intelligent algorithm. It would probably be easier, though, to simply attempt to find the test for check()'s return value in the program text and replace with nops (after properly manipulating the page permissions to allow writing to the text segment).
If you're having problems, inspecting the resulting assembly code is the way to go. If you're using GCC, gcc -S halts the compilation just before assembling (that is, producing an assembly source code file as output). objdump -d could also help. gdb can step between instructions, show the disassembly of a frame and display register contents; check the documentation.
These exercises are specially useful to understand how security breaches occur in common programs, and to provide some basic notions on defensive programming.
I want to write a piece of code that changes itself continuously, even if the change is insignificant.
For example maybe something like
for i in 1 to 100, do
begin
x := 200
for j in 200 downto 1, do
begin
do something
end
end
Suppose I want that my code should after first iteration change the line x := 200 to some other line x := 199 and then after next iteration change it to x := 198 and so on.
Is writing such a code possible ? Would I need to use inline assembly for that ?
EDIT :
Here is why I want to do it in C:
This program will be run on an experimental operating system and I can't / don't know how to use programs compiled from other languages. The real reason I need such a code is because this code is being run on a guest operating system on a virtual machine. The hypervisor is a binary translator that is translating chunks of code. The translator does some optimizations. It only translates the chunks of code once. The next time the same chunk is used in the guest, the translator will use the previously translated result. Now, if the code gets modified on the fly, then the translator notices that, and marks its previous translation as stale. Thus forcing a re-translation of the same code. This is what I want to achieve, to force the translator to do many translations. Typically these chunks are instructions between to branch instructions (such as jump instructions). I just think that self modifying code would be fantastic way to achieve this.
You might want to consider writing a virtual machine in C, where you can build your own self-modifying code.
If you wish to write self-modifying executables, much depends on the operating system you are targeting. You might approach your desired solution by modifying the in-memory program image. To do so, you would obtain the in-memory address of your program's code bytes. Then, you might manipulate the operating system protection on this memory range, allowing you to modify the bytes without encountering an Access Violation or '''SIG_SEGV'''. Finally, you would use pointers (perhaps '''unsigned char *''' pointers, possibly '''unsigned long *''' as on RISC machines) to modify the opcodes of the compiled program.
A key point is that you will be modifying machine code of the target architecture. There is no canonical format for C code while it is running -- C is a specification of a textual input file to a compiler.
Sorry, I am answering a bit late, but I think I found exactly what you are looking for : https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/
In this article, they change the value of a constant by injecting assembly in the stack. Then they execute a shellcode by modifying the memory of a function on the stack.
Below is the first code :
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
void foo(void);
int change_page_permissions_of_address(void *addr);
int main(void) {
void *foo_addr = (void*)foo;
// Change the permissions of the page that contains foo() to read, write, and execute
// This assumes that foo() is fully contained by a single page
if(change_page_permissions_of_address(foo_addr) == -1) {
fprintf(stderr, "Error while changing page permissions of foo(): %s\n", strerror(errno));
return 1;
}
// Call the unmodified foo()
puts("Calling foo...");
foo();
// Change the immediate value in the addl instruction in foo() to 42
unsigned char *instruction = (unsigned char*)foo_addr + 18;
*instruction = 0x2A;
// Call the modified foo()
puts("Calling foo...");
foo();
return 0;
}
void foo(void) {
int i=0;
i++;
printf("i: %d\n", i);
}
int change_page_permissions_of_address(void *addr) {
// Move the pointer to the page boundary
int page_size = getpagesize();
addr -= (unsigned long)addr % page_size;
if(mprotect(addr, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {
return -1;
}
return 0;
}
It is possible, but it's most probably not portably possible and you may have to contend with read-only memory segments for the running code and other obstacles put in place by your OS.
This would be a good start. Essentially Lisp functionality in C:
http://nakkaya.com/2010/08/24/a-micro-manual-for-lisp-implemented-in-c/
Depending on how much freedom you need, you may be able to accomplish what you want by using function pointers. Using your pseudocode as a jumping-off point, consider the case where we want to modify that variable x in different ways as the loop index i changes. We could do something like this:
#include <stdio.h>
void multiply_x (int * x, int multiplier)
{
*x *= multiplier;
}
void add_to_x (int * x, int increment)
{
*x += increment;
}
int main (void)
{
int x = 0;
int i;
void (*fp)(int *, int);
for (i = 1; i < 6; ++i) {
fp = (i % 2) ? add_to_x : multiply_x;
fp(&x, i);
printf("%d\n", x);
}
return 0;
}
The output, when we compile and run the program, is:
1
2
5
20
25
Obviously, this will only work if you have finite number of things you want to do with x on each run through. In order to make the changes persistent (which is part of what you want from "self-modification"), you would want to make the function-pointer variable either global or static. I'm not sure I really can recommend this approach, because there are often simpler and clearer ways of accomplishing this sort of thing.
A self-interpreting language (not hard-compiled and linked like C) might be better for that. Perl, javascript, PHP have the evil eval() function that might be suited to your purpose. By it, you could have a string of code that you constantly modify and then execute via eval().
The suggestion about implementing LISP in C and then using that is solid, due to portability concerns. But if you really wanted to, this could also be implemented in the other direction on many systems, by loading your program's bytecode into memory and then returning to it.
There's a couple of ways you could attempt to do that. One way is via a buffer overflow exploit. Another would be to use mprotect() to make the code section writable, and then modify compiler-created functions.
Techniques like this are fun for programming challenges and obfuscated competitions, but given how unreadable your code would be combined with the fact you're exploiting what C considers undefined behavior, they're best avoided in production environments.
In standard C11 (read n1570), you cannot write self modifying code (at least without undefined behavior). Conceptually at least, the code segment is read-only.
You might consider extending the code of your program with plugins using your dynamic linker. This require operating system specific functions. On POSIX, use dlopen (and probably dlsym to get newly loaded function pointers). You could then overwrite function pointers with the address of new ones.
Perhaps you could use some JIT-compiling library (like libgccjit or asmjit) to achieve your goals. You'll get fresh function addresses and put them in your function pointers.
Remember that a C compiler can generate code of various size for a given function call or jump, so even overwriting that in a machine specific way is brittle.
My friend and I encountered this problem while working on a game that self-modifies its code. We allow the user to rewrite code snippets in x86 assembly.
This just requires leveraging two libraries -- an assembler, and a disassembler:
FASM assembler: https://github.com/ZenLulz/Fasm.NET
Udis86 disassembler: https://github.com/vmt/udis86
We read instructions using the disassembler, let the user edit them, convert the new instructions to bytes with the assembler, and write them back to memory. The write-back requires using VirtualProtect on windows to change page permissions to allow editing the code. On Unix you have to use mprotect instead.
I posted an article on how we did it, as well as the sample code.
These examples are on Windows using C++, but it should be very easy to make cross-platform and C only.
This is how to do it on windows with c++. You'll have to VirtualAlloc a byte array with read/write protections, copy your code there, and VirtualProtect it with read/execute protections. Here's how you dynamically create a function that does nothing and returns.
#include <cstdio>
#include <Memoryapi.h>
#include <windows.h>
using namespace std;
typedef unsigned char byte;
int main(int argc, char** argv){
byte bytes [] = { 0x48, 0x31, 0xC0, 0x48, 0x83, 0xC0, 0x0F, 0xC3 }; //put code here
//xor %rax, %rax
//add %rax, 15
//ret
int size = sizeof(bytes);
DWORD protect = PAGE_READWRITE;
void* meth = VirtualAlloc(NULL, size, MEM_COMMIT, protect);
byte* write = (byte*) meth;
for(int i = 0; i < size; i++){
write[i] = bytes[i];
}
if(VirtualProtect(meth, size, PAGE_EXECUTE_READ, &protect)){
typedef int (*fptr)();
fptr my_fptr = reinterpret_cast<fptr>(reinterpret_cast<long>(meth));
int number = my_fptr();
for(int i = 0; i < number; i++){
printf("I will say this 15 times!\n");
}
return 0;
} else{
printf("Unable to VirtualProtect code with execute protection!\n");
return 1;
}
}
You assemble the code using this tool.
While "true" self modifying code in C is impossible (the assembly way feels like slight cheat, because at this point, we're writing self modifying code in assembly and not in C, which was the original question), there might be a pure C way to make the similar effect of statements paradoxically not doing what you think are supposed do to. I say paradoxically, because both the ASM self modifying code and the following C snippet might not superficially/intuitively make sense, but are logical if you put intuition aside and do a logical analysis, which is the discrepancy which makes paradox a paradox.
#include <stdio.h>
#include <string.h>
int main()
{
struct Foo
{
char a;
char b[4];
} foo;
foo.a = 42;
strncpy(foo.b, "foo", 3);
printf("foo.a=%i, foo.b=\"%s\"\n", foo.a, foo.b);
*(int*)&foo.a = 1918984746;
printf("foo.a=%i, foo.b=\"%s\"\n", foo.a, foo.b);
return 0;
}
$ gcc -o foo foo.c && ./foo
foo.a=42, foo.b="foo"
foo.a=42, foo.b="bar"
First, we change the value of foo.a and foo.b and print the struct. Then we change only the value of foo.a, but observe the output.
GNU libc's backtrace and In-circuit emulators/debuggers are not always available when porting code to a new platform, especially when the target is a micro C compiler such as for the Z80. (Typically a program bug would "just hang" somewhere, or crash the gadget.)
Is there an alternative to the classic "wolf fencing" method of manually inserting printf? Something simple and portable (using no C extensions) that a coder can do while developing a program that includes tracing and backtracing into a C program?
BTW: Here are a couple of other question on stackoverflow that are related, but these both use GNU GLIBC's backtrace and backtrace is often compiler/implementation specific:
Is there a function to invoke a stack dump in C?
How to generate a stacktrace when my gcc C++ app crashes
Here is the kernel of the kernel of my answer: write some code.
The kernel of my answer is: If your compiler allocates locals on the stack always, then...
Add blobs to the stack at every function entry that record the name of the function, throw in some magic numbers to maybe catch stack smashes.
typedef struct stack_debug_blob_ {
int magic1;
const char * function_name;
int magic2;
struct stack_debug_blob_ * called_by;
int magic3;
} stack_debug_blob;
stack_debug_blob * top_of_stack_debug_blobs = 0;
Create a macro ENTER(f) taking the name of the function. The macro should be about the first line of code in every function after the opening {. It adds a struct with a pointer to the (const) char * function name, a pointer to the previous struct on the stack, and maybe some magic numbers to check sanity. Make the top of blob stack pointer point at this new struct.
#define ENTER(f) \
stack_debug_blob new_stack_debug_blob = { \
MAGIC1, (f), MAGIC2, top_of_stack_debug_blobs, MAGIC3}; \
stack_debug_blob * evil_hack = (top_of_stack_debug_blobs = (&new_stack_debug_blob))
To keep things as portable as possible, all ENTER can do is declare and initialize variables. Hence the evil_hack to do a little extra computation than just initializing a variable.
Create a function to walk down the list of blobs checking pointers and magic numbers. It should signal an error (maybe print to stderr, maybe lockup the cpu with while (1) { /* nada */ }, maybe enter the debugger... depends on your hardware) if it finds things messed up.
Create a macro EXIT() that checks your stack of blobs, then de-links the topmost from the linked list. It needs to be put at the exit points of all your functions.
#define EXIT() do { \
check_debug_blobs(); \
top_of_stack_debug_blobs = new_stack_debug_blob.called_by; \
new_stack_debug_blob.magic1 -= 1; /* paranoia */ \
} while (0)
Probably will also need to replace all return's with RETURN macro calls, the RETURN macro is just like EXIT, but has a return before the } while (0).
Create a function to walk down the list of blobs printing out the function names, call it something like stacktrace or backtrace maybe.
Write a program to instrument your C code with calls to ENTER(f) and EXIT() and RETURN(x).
Left out a few details to let you have fun with it...
See also Any porting available of backtrace for uclibc?
There is an implementation at RosettaCode.org which uses the same basic idea as #jsl4tv's suggestion.
Example, given the following classic C code with built in "hang":
#include <stdio.h>
#include <stdlib.h>
void inner(int k)
{
for(;;){} /* hang */
}
void middle(int x, int y)
{
inner(x*y);
}
void outer(int a, int b, int c)
{
middle(a+b, b+c);
}
int main()
{
outer(2,3,5);
return(EXIT_SUCCESS);
}
#define STACK_TRACE_ON and #include "stack_trace.h" from RosettaCode.org then insert BEGIN(f)/ENDs where required:
#include <stdio.h>
#include <stdlib.h>
#define STACK_TRACE_ON /* compile in these "stack_trace" routines */
#include "stack_trace.h"
void inner(int k)
BEGIN(inner)
print_indent(); printf("*** Now dump the stack ***\n");
print_stack_trace();
for(;;){} /* hang */
END
void middle(int x, int y)
BEGIN(middle)
inner(x*y);
END
void outer(int a, int b, int c)
BEGIN(outer)
middle(a+b, b+c);
END
int main()
BEGIN(main)
stack_trace.on = TRUE; /* turn on runtime tracing */
outer(2,3,5);
stack_trace.on = FALSE;
RETURN(EXIT_SUCCESS);
END
Produces:
stack_trace_test.c:19: BEGIN outer[0x80487b4], stack(depth:1, size:60)
stack_trace_test.c:14: BEGIN middle[0x8048749], stack(depth:2, size:108)
stack_trace_test.c:8: BEGIN inner[0x80486d8], stack(depth:3, size:156)
stack_trace_test.c:8: *** Now dump the stack ***
stack_trace_test.c:8: inner[0x80486d8] --- stack(depth:4, size:156) ---
stack_trace_test.c:14: middle[0x8048749] --- stack(depth:3, size:108) ---
stack_trace_test.c:19: outer[0x80487b4] --- stack(depth:2, size:60) ---
stack_trace_test.c:24: main[0x804882a] --- stack(depth:1, size:0) ---
stack_trace_test.c:8: --- (depth 4) ---
A well polished [open source] version of this BEGIN ~ END method would be perfect. (Esp if it has a "FINALLY" clause for exception handling).
Hints/URLs appreciated.
on Symbian there were some scripts made to go over the registers and stack looking for things that looked like code addresses.
This is not portable, but it doesn't depend on decorating the code either. This was a necessary tradeoff on a platform where byte counts mattered... and it wasn't nearly as limited as Z80! But limited enough to compile without frame-pointers and such.
To calculate a backtrace from a stack without frame-pointers you have to work up the stack not down it.