I tryed to implement dynamic memory managemet functions and succeed. However when I try to implement another function that prints some information about memory with the exact same way, I got segmentation fault. I am using Ubuntu, gcc.
Here is my related code:
In mm_alloc.c: (Other functions malloc, free etc. are also here)
#include "mm_alloc.h"
#include "stdlib.h"
#include "stdio.h"
#include "unistd.h"
#include "string.h"
void mm_print_mem() {
printf( "\nstart_addr\tsize\tfree\tprev\tnext\n");
printf("=============================\n");
printf("HEAD OF LL %p\n", metadata);
METADATA *currentPtr = metadata;
int i = 0;
while (currentPtr!= NULL && i <= 10) {
printf("%p\t%d\t%d\t%p\t%p\n", currentPtr, (int)currentPtr-
>size, currentPtr->free,currentPtr->prev,currentPtr->next);
if (currentPtr->next == NULL) break;
currentPtr = currentPtr->next;
i++;
}
return;
}
mm_alloc.h:
#pragma once
#include <stdlib.h>
typedef struct METADATA{
struct METADATA *next;
struct METADATA *prev;
int free;
size_t size;
}METADATA;
METADATA *metadata;
void *mm_malloc(size_t size);
void *mm_realloc(void *ptr, size_t size);
void mm_free(void *ptr);
void mm_print_mem();
And the test function. Here, I got segmentation fault when I call mm_print_mem function, others work well.
int main() {
load_alloc_functions();
int *dizi = (int *)mm_malloc(5 * sizeof(int));
dizi[4] = 5;
dizi[2] = 10;
printf("%d - %d\n", dizi[4], dizi[2]);
mm_print_mem();
return 0;
}
I use these commands on Ubuntu in order to link files and run the test file.
gcc -c -Wall -Werror -fpic mm_alloc.c
gcc -shared -o libfoo.so 14011085.so
gcc mm_test.c -o try -ldl
./try
Notice that even the inside of mm_print_mem was empty, it gives segmentation fault as well. Where am I doing wrong?
You have at least a problem in the declaration of the global variable metadata. It is declared as METADATA *metadata; in an included file. So it has correctly external linkage, but is defined in every translation unit, when one single definition should exist in a full program. Not doing so is explicitely undefined behaviour, with no diagnostic required.
There are different ways to fix that problem:
declare it extern in the include file
extern METADATA *metadata;
and define it in only one translation unit without the extern specifier:
#include "mm_alloc.h" // extern declaration
...
METADATA * metadata; // single definition in whole program
put all the library functions in one single translation unit (if it makes sense), define metadata in that file and remove any reference to it from the mm_alloc.h file. After all, it is private data for the library...
remove the reference to metadata from the mm_alloc.h include file which should only declare the external interface for the library, define it in one single file of the library (at file level without the extern specifier) and declare it in all other files from the library as extern METADATA *metadata;
Without seeing the source for the other functions I cannot say whether there are other problems...
You make things a bit difficult by not providing a A Minimal, Complete, and Verifiable example, but a short example will help. Without seeing your load and alloc functions, you leave us guessing a bit at exactly where your problem is located or the extent of you problems.
That said a short example illustrating your mm_print_mem(); function should at least get that part straightened out. (note: the example uses a cirular linked list where the last node points to the first and first->prev points to the last. You can adjust the test and assignments for metadata->prev and last->next if you want NULL at both ends)
While you can use #pragma once, you will find greater portability just using traditional header-guards to prevent multiple includes, e.g. #ifndef HEADERNAME, then #define it, e.g.
#ifndef __mm_alloc_h__
#define __mm_alloc_h__ 1
#include <stdlib.h>
typedef struct METADATA {
struct METADATA *next;
struct METADATA *prev;
int free;
size_t size;
} METADATA;
METADATA *metadata;
// void *mm_malloc(size_t size);
// void *mm_realloc(void *ptr, size_t size);
// void mm_free(void *ptr);
void mm_print_mem();
#endif
Your mm_alloc.c is fine, but your loop control was a bit strange with the magic number 10 included as a condition. With the example list, you simply iterate and increment nodes until currentPtr->next (e.g. currentPtr after assignment) is equal to metadata (completing the circle)
#include "mm_alloc.h"
#include <stdio.h>
void mm_print_mem() {
METADATA *currentPtr = metadata;
printf ("\nstart_addr\tsize\tfree\tprev\t\tnext\n"
"=========================================================\n"
"HEAD OF LL %p\n", metadata);
for (;;) {
printf ("%p\t%d\t%d\t%p\t%p\n", currentPtr, (int)currentPtr->size,
currentPtr->free,currentPtr->prev,currentPtr->next);
currentPtr = currentPtr->next;
if (currentPtr == metadata)
break;
}
}
I wrote a simple test program that allocates and fills 20 nodes for you showing the independent handling of the 1st and remaining nodes, e.g,
#include "mm_alloc.h"
#include <stdio.h>
#define MAX 20
int main (void) {
int i;
for (i = 0; i < MAX; i++) {
METADATA *node = malloc (sizeof *node);
if (!node) {
perror ("malloc node");
return 1;
}
node->next = node->prev = NULL;
node->free = MAX - i - 1;
node->size = i;
if (!metadata) { /* 1st node is self-referencing */
node->prev = node; /* in circular linked-list */
node->next = node;
metadata = node;
}
else { /* add rest at end as metadata->prev */
node->prev = metadata->prev;
node->next = metadata;
metadata->prev->next = node;
metadata->prev = node;
}
}
mm_print_mem();
return 0;
}
(note: you should free the node when you are done with them)
Compile Shared Object Library & Test Program
$ gcc -Wall -Werror -fPIC -o mm_alloc.o -c mm_alloc.c
$ gcc -shared -o libmm_alloc.so mm_alloc.o
When compiling the test program, make sure your program can find your shared library. using the linker option -rpath is a good way to specify the location for a custom library if not in the standard library search path locations. (just note it must be in the same place on any system you copy it too)
(line-continuation are used below to allow the compile string to fit)
$ gcc -L"/path/to/your/lib/dir" \
-Wl,-rpath="/path/to/your/lib/dir" \
-Wall -o mm_alloc_tst mm_alloc_tst.c -lmm_alloc
Example Use/Output
$ ./mm_alloc_tst
start_addr size free prev next
=========================================================
HEAD OF LL 0x208d010
0x208d010 0 19 0x208d3a0 0x208d040
0x208d040 1 18 0x208d010 0x208d070
0x208d070 2 17 0x208d040 0x208d0a0
0x208d0a0 3 16 0x208d070 0x208d0d0
0x208d0d0 4 15 0x208d0a0 0x208d100
0x208d100 5 14 0x208d0d0 0x208d130
0x208d130 6 13 0x208d100 0x208d160
0x208d160 7 12 0x208d130 0x208d190
0x208d190 8 11 0x208d160 0x208d1c0
0x208d1c0 9 10 0x208d190 0x208d1f0
0x208d1f0 10 9 0x208d1c0 0x208d220
0x208d220 11 8 0x208d1f0 0x208d250
0x208d250 12 7 0x208d220 0x208d280
0x208d280 13 6 0x208d250 0x208d2b0
0x208d2b0 14 5 0x208d280 0x208d2e0
0x208d2e0 15 4 0x208d2b0 0x208d310
0x208d310 16 3 0x208d2e0 0x208d340
0x208d340 17 2 0x208d310 0x208d370
0x208d370 18 1 0x208d340 0x208d3a0
0x208d3a0 19 0 0x208d370 0x208d010
Look things over and let me know if you have further questions.
Related
I have assigned values to a fields in a structure. This resulted in multiple errors.
typedef struct t_queue {
int head = 0;
int tail = 0;
int maxSize = 0;
int size = 0;
SOCKET* queue = NULL;
}Queue;
typedef struct t_threadData {
int topicID;
bool isEngineActive = FALSE;
bool isServerActive = TRUE;
int numberOfConnectedSubs = 0;
Queue* queue;
HANDLE PublisherReady;
HANDLE ThreadReady;
HANDLE BarrierOK;
CRITICAL_SECTION Critical_Section;
int NumberOfThreadsWaiting = 0;
SOCKET sockets[NUMBER_OF_SUBSCRIBERS];
}ThreadData;
Errors are:
E0065 expected a ';'
E0020 identifier "bool" is undefined
I'm working in C on Windows 10 using Visual Studio Enterprise 2017.
Thank you for your help in advance.
Read Modern C and see this C reference. If you compile with a recent GCC compiler, use gcc -Wall -Wextra -g to compile your code. Read also the documentation of your C compiler, and enable all warnings in it. Read also the documentation of your debugger (e.g. GDB)
You should code:
typedef struct t_queue {
int head;
int tail;
int maxSize;
int size;
SOCKET* queue;
} Queue;
BTW, your field names are confusing. Since head and tail suggests a doubly-linked list. Then they should be pointers!
Consider also using the Clang static analyzer -or Frama-C- on your project.
Take inspiration from the source code of some existing open source software coded in C (like Glib, GNU make, the Linux kernel, GNU guile, etc...)
This is my main file
#include<stdio.h>
#include<string.h>
#include "ssv.c"
int main() {
int i,length,acct;
float amnt;
char data[1000], record[1000];
FILE *x = fopen("students.ssv","rt");
while(!feof(x)) {
for (i = 0; data[i] != '\n'; i++) {
record[i] = data[i];
length = i + 1;
}
record[length] = '\0';
parse(record,&acct,&amnt);
fgets(data,999,x);
}
fclose(x);
return 0;
}
This is my ssv.c file
#include<stdio.h>
void parse(char record[], int *acct, float *amnt){
sscanf(record,"%d %f",acct,amnt);
}
For some reason, these two programs are not working very well together. I am still getting used to modular programming. I keep getting the messages "undefined reference to main" and "multiple definition of".
My main goal here is to parse a file like
100 -10.5
13 -2.4
into corresponding fields. Please advise!
The first iteration of the while loop uses data before it has read the line. It should be:
while(fgets(data, sizeof data, x)) {
parse(data,&acct,&amnt);
}
You don't need to subtract 1 from the size of data when calling fgets().
There's no reason to copy data to record. You can simply parse data (the parse() function will ignore the newline). fgets() ends the string with a null terminator, you don't need to add it yourself.
#include should only be used for .h files, not .c files. You combine object files using the linker. So get rid of #include "ssv.c", replace it with #include "ssv.h". This file should just contain a declaration of parse().
void parse(char record[], int *acct, float *amnt);
Compile the two programs using:
gcc main.c ssv.c
Or you can compile each file separately then link them:
gcc -c main.c
gcc -c ssv.c
gcc main.o ssv.o
I need to get base address of stack inside my running process. This would enable me to print raw stacktraces that will be understood by addr2line (running binary is stripped, but addr2line has access to symbols).
I managed to do this by examining elf header of argv[0]: I read entry point and substract it from &_start:
#include <stdio.h>
#include <execinfo.h>
#include <unistd.h>
#include <elf.h>
#include <stdio.h>
#include <string.h>
void* entry_point = NULL;
void* base_addr = NULL;
extern char _start;
/// given argv[0] will populate global entry_pont
void read_elf_header(const char* elfFile) {
// switch to Elf32_Ehdr for x86 architecture.
Elf64_Ehdr header;
FILE* file = fopen(elfFile, "rb");
if(file) {
fread(&header, 1, sizeof(header), file);
if (memcmp(header.e_ident, ELFMAG, SELFMAG) == 0) {
printf("Entry point from file: %p\n", (void *) header.e_entry);
entry_point = (void*)header.e_entry;
base_addr = (void*) ((long)&_start - (long)entry_point);
}
fclose(file);
}
}
/// print stacktrace
void bt() {
static const int MAX_STACK = 30;
void *array[MAX_STACK];
auto size = backtrace(array, MAX_STACK);
for (int i = 0; i < size; ++i) {
printf("%p ", (long)array[i]-(long)base_addr );
}
printf("\n");
}
int main(int argc, char* argv[])
{
read_elf_header(argv[0]);
printf("&_start = %p\n",&_start);
printf("base address is: %p\n", base_addr);
bt();
// elf header is also in memory, but to find it I have to already have base address
Elf64_Ehdr * ehdr_addr = (Elf64_Ehdr *) base_addr;
printf("Entry from memory: %p\n", (void *) ehdr_addr->e_entry);
return 0;
}
Sample output:
Entry point from file: 0x10c0
&_start = 0x5648eeb150c0
base address is: 0x5648eeb14000
0x1321 0x13ee 0x29540f8ed09b 0x10ea
Entry from memory: 0x10c0
And then I can
$ addr2line -e a.out 0x1321 0x13ee 0x29540f8ed09b 0x10ea
/tmp/elf2.c:30
/tmp/elf2.c:45
??:0
??:?
How can I get base address without access to argv? I may need to print traces before main() (initialization of globals). Turning of ASLR or PIE is not an option.
How can I get base address without access to argv? I may need to print traces before main()
There are a few ways:
If /proc is mounted (which it almost always is), you could read the ELF header from /proc/self/exe.
You could use dladdr1(), as Antti Haapala's answer shows.
You could use _r_debug.r_map, which points to the linked list of loaded ELF images. The first entry in that list corresponds to a.out, and its l_addr contains the relocation you are looking for. This solution is equivalent to dladdr1, but doesn't require linking against libdl.
Could you provide sample code for 3?
Sure:
#include <link.h>
#include <stdio.h>
extern char _start;
int main()
{
uintptr_t relocation = _r_debug.r_map->l_addr;
printf("relocation: %p, &_start: %p, &_start - relocation: %p\n",
(void*)relocation, &_start, &_start - relocation);
return 0;
}
gcc -Wall -fPIE -pie t.c && ./a.out
relocation: 0x555d4995e000, &_start: 0x555d4995e5b0, &_start - relocation: 0x5b0
Are both 2 and 3 equally portable?
I think they are about equally portable: dladdr1 is a GLIBC extension that is also present on Solaris. _r_debug predates Linux and would also work on Solaris (I haven't actually checked, but I believe it will). It may work on other ELF platforms as well.
This piece of code produces the same value as your base_addr on Linux:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
Dl_info info;
void *extra = NULL;
dladdr1(&_start, &info, &extra, RTLD_DL_LINKMAP);
struct link_map *map = extra;
printf("%#llx", (unsigned long long)map->l_addr);
The dladdr1 manual page says the following of RTLD_DL_LINKMAP:
RTLD_DL_LINKMAP
Obtain a pointer to the link map for the matched file. The
extra_info argument points to a pointer to a link_map structure (i.e., struct link_map **), defined in as:
struct link_map {
ElfW(Addr) l_addr; /* Difference between the
address in the ELF file and
the address in memory */
char *l_name; /* Absolute pathname where
object was found */
ElfW(Dyn) *l_ld; /* Dynamic section of the
shared object */
struct link_map *l_next, *l_prev;
/* Chain of loaded objects */
/* Plus additional fields private to the
implementation */
};
Notice that -ldl is required to link against the dynamic loading routines.
Suppose you created a main() to deal with an exercise you asked your students.
Every student is supposed to write their own function, with the same API. And a single file will be created, with all functions and the main calling them.
Lets say: int studentname(int a, int b) is the function pattern.
One way I deal with it was using a vector of pointer to functions int (*func[MAX])(). But you need to fulfill the vector one by one func[0]=studentname;.
I wonder, is there a way a function can be called by its name somehow?
Something like: int student1(int a , int b), student2(), etc.
And in main somehow we could just call sscanf(funcname,"student%d",i); funcname();.
Do you have any other idea? Maybe
int studentname(int a, int b, char *fname)
{
strcpy(fname, "studentname");
Anything creative will do! :)
Thanks!
Beco
PS. I tried just a vector of functions, but C won't allow me! :)
int func[2]()={{;},{;}};
This way I could just give to each student a number, and voilá... But no way. It was funny though.
Edited: I'm using linux.
Edited 2: Thanks! I've accepted an answer that helped me, but I've also documented a complete example as an answer bellow.
Maybe a bit overcomplicating it, but spontaneous idea:
Compile all student source files into one shared library with the students' functions being exports.
Then enumerate all exposed functions, call and test them.
As an alternative:
Write a small tool that will compile all "student units" using a preprocessor define to replace a predefined function name with an unique name ("func1", "func2", etc.).
Then let the tool write a small unit calling all these functions while performing tests, etc.
And yet another idea:
Use C++ to write a special class template that's going to register derived classes in a object factory and just embed student's code using extern "C". Depending on the implementation this might look a bit confusing and overcomplicated though.
Then use the factory to create one instance of each and run the code.
Example for the approach with dlopen() and dlsym() (whether only one function per library or all - doesn't matter):
void *pluginlib = dlopen("student1.so", RTLD_NOW); // RTLD_NOW will load the file right away
if (!pluginlib)
; // failed to load
studentproc func = (studentproc)dlsym(pluginlib, "student1"); // this loads the function called "student1"
if (!func)
; // failed to resolve
func("hello world!"); // call the lib
dlclose(pluginlib); // unloads the dll (this will make all further calls invalid)
Similar to what #Jamey-Sharp proposed:
ask each student to provide .c file with entry function of a given name/signature
compile each .c into a shared library, named by the student name, or given whatever unique name. This step can be easily automated with make or simple script.
make a simple host application which enumerates all .so files in a given directory, and uses dlopen() and dlsym() to get to the entry point function.
now you can simply call each student's implementation.
BTW, that's how plug-ins are implemented usually, isn't it?
Edit: Here's a working proof of concept (and a proof, that each student can use the same name of the entry point function).
Here's student1.c:
#include <stdio.h>
void student_task()
{
printf("Hello, I'm Student #1\n");
}
Here's student2.c:
#include <stdio.h>
void student_task()
{
printf("Hello, I'm Student #2\n");
}
And here's the main program, tester.c:
#include <stdio.h>
#include <dlfcn.h>
/* NOTE: Error handling intentionally skipped for brevity!
* It's not a production code!
*/
/* Type of the entry point function implemented by students */
typedef void (*entry_point_t)(void);
/* For each student we have to store... */
typedef struct student_lib_tag {
/* .. pointer to the entry point function, */
entry_point_t entry;
/* and a library handle, so we can play nice and close it eventually */
void* library_handle;
} student_solution_t;
void load(const char* lib_name, student_solution_t* solution)
{
/* Again - all error handling skipped, I only want to show the idea! */
/* Open the library. RTLD_LOCAL is quite important, it keeps the libs separated */
solution->library_handle = dlopen(lib_name, RTLD_NOW | RTLD_LOCAL);
/* Now we ask for 'student_task' function. Every student uses the same name.
* strange void** is needed for C99, see dlsym() manual.
*/
*(void**) (&solution->entry) = dlsym(solution->library_handle, "student_task");
/* We have to keep the library open */
}
int main()
{
/* Two entries hardcoded - you need some code here that would scan
* the directory for .so files, allocate array dynamically and load
* them all.
*/
student_solution_t solutions[2];
/* Load both solutions */
load("./student1.so", &solutions[0]);
load("./student2.so", &solutions[1]);
/* Now we can call them both, despite the same name of the entry point function! */
(solutions[0].entry)();
(solutions[1].entry)();
/* Eventually it's safe to close the libs */
dlclose(solutions[0].library_handle);
dlclose(solutions[1].library_handle);
return 0;
}
Let's compile it all:
czajnik#czajnik:~/test$ gcc -shared -fPIC student1.c -o student1.so -Wall
czajnik#czajnik:~/test$ gcc -shared -fPIC student2.c -o student2.so -Wall
czajnik#czajnik:~/test$ gcc tester.c -g -O0 -o tester -ldl -Wall
And see it works:
czajnik#czajnik:~/test$ ./tester
Hello, I'm Student #1
Hello, I'm Student #2
I'd take a different approach:
Require every student to use the same function name, and place each student's code in a separate source file.
Write one more source file with a main that calls the standard name.
Produce a separate executable from linking main.c with student1.c, then main.c with student2.c, and so on. You might be able to use wildcards in a makefile or shell script to automate this.
That said, at least on Unix-like OSes, you can do what you asked for.
Call dlopen(NULL) to get a handle on the symbols in the main program.
Pass that handle and the function name you want to dlsym. Coerce the resulting pointer to a function pointer of the right type, and call it.
Here is an ugly preprocessor hack:
#Makefile
FILE_NAME=student
${FILE_NAME}: main.c
cc -Wall -DFILE_NAME=\"${FILE_NAME}.c\" -o $# main.c -lm
Teacher's main.c:
#include <math.h>
#include <stdio.h>
#include FILE_NAME
char *my_name(void);
double my_sin(double val);
int main(void)
{
double dd;
dd = my_sin(3.1415923563);
printf("%s: %f\n", my_name(), dd);
return 0;
}
Student's .c File:
#include <math.h>
char * my_name(void);
double my_sin(double val);
char * my_name(void)
{
return "Wildplasser-1.0";
}
double my_sin(double val)
{
return sin (val);
}
The trick lies i the literal inclusion of the student's .c file.
To avoid this, you could also use a different make line, like:
cc -Wall -o $# ${FILE_NAME}.c main.c -lm
(and remove the ugly #include FILENAME, of course)
Thanks you all. I've accepted an answer that gave me the inspiration to solve the question. Here, just to document it, is my complete solution:
File shamain.c
/* Uses shared library shalib.so
* Compile with:
* gcc shamain.c -o shamain -ldl -Wall
*/
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(void)
{
void *libstud;
int (*student[2])(int, int);
char fname[32];
int i,r;
libstud = dlopen("./shalib.so", RTLD_NOW);
if (!libstud)
{
fprintf(stderr, "error: %s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
for(i=0; i<2; i++)
{
sprintf(fname, "func%d", i);
*(void **) (&student[i]) = dlsym(libstud, fname); /* c99 crap */
//student[i] = (int (*)(int, int)) dlsym(libstud, fname); /* c89 format */
}
for(i=0; i<2; i++)
{
r=student[i](i, i);
printf("i=%d,r=%d\n", i, r);
}
return 0;
}
File shalib.c
/* Shared library.
* Compile with:
* gcc -shared -fPIC shalib.c -o shalib.so -Wall
*/
#include <stdio.h>
int func0(int one, int jadv)
{
printf("%d = Smith\n", one);
return 0;
}
int func1(int one, int jadv)
{
printf("%d = John\n", one);
return 0;
}
It is a while since I have used shared libraries, but I have a feeling you can extract named functions from a DLL/shlib. Could you create a DLL/shared library containing all of the implementations and then access them by name from the main?
Per #william-morris's suggestion, you might have luck using dlsym() to do a dynamic lookup of the functions. (dlsym() may or may not be the library call to use on your particular platform.)
When I use gdb to debug a program written in C, the command disassemble shows the codes and their addresses in the code memory segmentation. Is it possible to know those memory addresses at runtime? I am using Ubuntu OS. Thank you.
[edit] To be more specific, I will demonstrate it with following example.
#include <stdio.h>
int main(int argc,char *argv[]){
myfunction();
exit(0);
}
Now I would like to have the address of myfunction() in the code memory segmentation when I run my program.
Above answer is vastly overcomplicated. If the function reference is static, as it is above, the address is simply the value of the symbol name in pointer context:
void* myfunction_address = myfunction;
If you are grabbing the function dynamically out of a shared library, then the value returned from dlsym() (POSIX) or GetProcAddress() (windows) is likewise the address of the function.
Note that the above code is likely to generate a warning with some compilers, as ISO C technically forbids assignment between code and data pointers (some architectures put them in physically distinct address spaces).
And some pedants will point out that the address returned isn't really guaranteed to be the memory address of the function, it's just a unique value that can be compared for equality with other function pointers and acts, when called, to transfer control to the function whose pointer it holds. Obviously all known compilers implement this with a branch target address.
And finally, note that the "address" of a function is a little ambiguous. If the function was loaded dynamically or is an extern reference to an exported symbol, what you really get is generally a pointer to some fixup code in the "PLT" (a Unix/ELF term, though the PE/COFF mechanism on windows is similar) that then jumps to the function.
If you know the function name before program runs, simply use
void * addr = myfunction;
If the function name is given at run-time, I once wrote a function to find out the symbol address dynamically using bfd library. Here is the x86_64 code, you can get the address via find_symbol("a.out", "myfunction") in the example.
#include <bfd.h>
#include <stdio.h>
#include <stdlib.h>
#include <type.h>
#include <string.h>
long find_symbol(char *filename, char *symname)
{
bfd *ibfd;
asymbol **symtab;
long nsize, nsyms, i;
symbol_info syminfo;
char **matching;
bfd_init();
ibfd = bfd_openr(filename, NULL);
if (ibfd == NULL) {
printf("bfd_openr error\n");
}
if (!bfd_check_format_matches(ibfd, bfd_object, &matching)) {
printf("format_matches\n");
}
nsize = bfd_get_symtab_upper_bound (ibfd);
symtab = malloc(nsize);
nsyms = bfd_canonicalize_symtab(ibfd, symtab);
for (i = 0; i < nsyms; i++) {
if (strcmp(symtab[i]->name, symname) == 0) {
bfd_symbol_info(symtab[i], &syminfo);
return (long) syminfo.value;
}
}
bfd_close(ibfd);
printf("cannot find symbol\n");
}
To get a backtrace, use execinfo.h as documented in the GNU libc manual.
For example:
#include <execinfo.h>
#include <stdio.h>
#include <unistd.h>
void trace_pom()
{
const int sz = 15;
void *buf[sz];
// get at most sz entries
int n = backtrace(buf, sz);
// output them right to stderr
backtrace_symbols_fd(buf, n, fileno(stderr));
// but if you want to output the strings yourself
// you may use char ** backtrace_symbols (void *const *buffer, int size)
write(fileno(stderr), "\n", 1);
}
void TransferFunds(int n);
void DepositMoney(int n)
{
if (n <= 0)
trace_pom();
else TransferFunds(n-1);
}
void TransferFunds(int n)
{
DepositMoney(n);
}
int main()
{
DepositMoney(3);
return 0;
}
compiled
gcc a.c -o a -g -Wall -Werror -rdynamic
According to the mentioned website:
Currently, the function name and offset only be obtained on systems that use the ELF
binary format for programs and libraries. On other systems, only the hexadecimal return
address will be present. Also, you may need to pass additional flags to the linker to
make the function names available to the program. (For example, on systems using GNU
ld, you must pass (-rdynamic.)
Output
./a(trace_pom+0xc9)[0x80487fd]
./a(DepositMoney+0x11)[0x8048862]
./a(TransferFunds+0x11)[0x8048885]
./a(DepositMoney+0x21)[0x8048872]
./a(TransferFunds+0x11)[0x8048885]
./a(DepositMoney+0x21)[0x8048872]
./a(TransferFunds+0x11)[0x8048885]
./a(DepositMoney+0x21)[0x8048872]
./a(main+0x1d)[0x80488a4]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7e16775]
./a[0x80486a1]
About a comment in an answer (getting the address of an instruction), you can use this very ugly trick
#include <setjmp.h>
void function() {
printf("in function\n");
printf("%d\n",__LINE__);
printf("exiting function\n");
}
int main() {
jmp_buf env;
int i;
printf("in main\n");
printf("%d\n",__LINE__);
printf("calling function\n");
setjmp(env);
for (i=0; i < 18; ++i) {
printf("%p\n",env[i]);
}
function();
printf("in main again\n");
printf("%d\n",__LINE__);
}
It should be env[12] (the eip), but be careful as it looks machine dependent, so triple check my word. This is the output
in main
13
calling function
0xbfff037f
0x0
0x1f80
0x1dcb
0x4
0x8fe2f50c
0x0
0x0
0xbffff2a8
0xbffff240
0x1f
0x292
0x1e09
0x17
0x8fe0001f
0x1f
0x0
0x37
in function
4
exiting function
in main again
37
have fun!