Even though we set currentMethod.bytes with local function to generate random numbers, the RAND_bytes is not invoking. After we set RAND_set_rand_method(&cuurentMethod).
Here I attached link [https://github.com/openssl/openssl/blob/master/test/sm2_internal_test.c] which I already tried.
int main()
{
unsigned char rand[16];
int ret;
RAND_METHOD *oldMethod,currentMethod,*temp;
oldMethod = RAND_get_rand_method();/*getting default method*/
currentMethod = *oldMethod;
currentMethod.bytes = local_function_rand;
if((ret = RAND_set_rand_method(¤tMethod))!= 1)
return 0;
/* Now we are printing both address of local_function_method_rand() and
temp->bytes , those address are same after getting. */
temp = RAND_get_rand_method();
/* after we are comparing with RAND_SSLeay() function , to find default or not*/
if((ret = RAND_bytes(rand,16)) != 1)
return 0;
return 1;
}
Expecting result is our local function should invoke. Also, to invoke RAND_bytes() is it required to set fips mode in Linux system?
After cleaning up and minimizing your test program and filling in the missing parts:
#include <openssl/rand.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int local_function_rand(unsigned char *buf, int num) {
printf("in local_function_rand(); requested %d bytes\n", num);
memset(buf, 4, num); // RFC 1149.5 standard random number
return 1;
}
int main(void) {
unsigned char rand[16];
RAND_METHOD currentMethod = {.bytes = local_function_rand};
RAND_set_rand_method(¤tMethod);
if (RAND_bytes(rand, sizeof rand) != 1) {
return EXIT_FAILURE;
}
return 0;
}
and running it (With OpenSSL 1.1.1):
$ gcc -Wall -Wextra rand.c -lcrypto
$ ./a.out
in local_function_rand(); requested 16 bytes
it works as expected; the user-supplied function is being called by RAND_bytes(). If you're getting different results from your code, there's probably a problem in the bits you didn't include in your question.
Related
On windows you can capturing the stack trace using CaptureStackBackTrace as
void* frames[USHRT_MAX];
USHORT framesCount = CaptureStackBackTrace(0, USHRT_MAX, frames, NULL);
However, capturing it by smaller chunks in a loop to avoid allocating a USHRT_MAX buffer doesn't provide the same result.
This code
#include <Windows.h>
#include <assert.h>
#include <stdio.h>
__declspec(noinline) void CheckStack(void)
{
printf("Checking stack...\n");
void* entireStack[USHRT_MAX];
USHORT frameCount = CaptureStackBackTrace(0, USHRT_MAX, entireStack, NULL);
printf("Stack size is: %u\n", frameCount);
ULONG frameOffset = 1;
for (;;)
{
void* chunk[64];
USHORT framesFound = CaptureStackBackTrace(frameOffset, 64, chunk, NULL);
if (framesFound)
{
if (memcmp(entireStack + frameOffset, chunk, sizeof(chunk)) != 0)
{
printf("Incorrect content\n");
}
frameOffset += (ULONG)framesFound;
}
else
{
break;
}
}
if (frameCount != frameOffset)
{
printf("Incorrect count (%u != %u)\n", frameCount, frameOffset);
}
printf("Done\n");
}
__declspec(noinline) void Test(int i)
{
if (i != 500)
Test(++i);
else
CheckStack();
}
int main()
{
Test(0);
}
produces the following output
Checking stack...
Stack size is: 507
Incorrect count (507 != 257)
Done
when building as cl /Od main.c /link /OUT:main.exe.
Am I using the FramesToSkip parameter incorrectly or why are the counts not equal?
If you are using Windows Server 2003 and Windows XP,
The sum of the FramesToSkip and FramesToCapture parameters must be
less than 63.
That's in document.
Else, as #RbMm says, In the API source code, there is the following logic:
if(FramesToSkip>0xfe)
{
return 0; //There are too many stack structures skipped, returning directly to 0.
}
However, this is not metioned on msdn both in the CaptureStackBackTrace and RtlCaptureStackBackTrace.
I am not going to post the source code here, but prove it in debugging:
1.Create a sample:
#include <Windows.h>
#include <assert.h>
#include <stdio.h>
__declspec(noinline) void CheckStack(void)
{
void* entireStack[USHRT_MAX];
USHORT frameCount = CaptureStackBackTrace(255, USHRT_MAX, entireStack, NULL);
}
__declspec(noinline) void Test(int i)
{
if (i != 500)
Test(++i);
else
CheckStack();
}
int main()
{
Test(0);
}
2. Step into CaptureStackBackTrace in Disassembly:
You can see that dword ptr[ebp+8](the first parameter of CaptureStackBackTrace pushed in stack) will be compared with 0feh(254). If true, return 0.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Edit: I am really sorry if I have wasted time of your guys, I was running out of time when posting this problem. Here comes the code that I have done my best to minimize it
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum Error {
ERROR_UNRESOLVED_NAME = 1,
ERROR_CANNOT_OPEN_FILE,
ERROR_NO_ARGV,
ERROR_UNRECOGNIZED_SYMBOL,
ERROR_UNCOMPLETED_SENTENCE,
ERROR_RECURSIVE_SELF
};
struct _Piece;
typedef struct _Piece *(*PieceFunc)(struct _Piece *, void *);
struct _Piece {
PieceFunc function;
void *backpack;
};
typedef struct _Piece Piece;
Piece *piece_create(PieceFunc func, void *pack) {
Piece *piece = malloc(sizeof(Piece));
piece->function = func;
piece->backpack = pack;
return piece;
}
typedef struct _Record {
char *name;
int name_len;
Piece *piece;
struct _Record *previous;
} Record;
Record *record_register(Record *pre, char *name, int name_len, Piece *piece) {
Record *record = malloc(sizeof(Record));
record->name = name;
record->name_len = name_len;
record->piece = piece;
record->previous = pre;
return record;
}
typedef struct {
char *file_name;
char *source;
int length;
int current;
int line;
int column;
} Source;
Source *source_create(char *s, int len, char *file_name) {
Source *source = malloc(sizeof(Source));
source->source = s;
source->file_name = file_name;
source->length = len;
source->current = 0;
source->line = source->column = 1;
return source;
}
Piece *apply(Piece *caller, Piece *callee) {
return caller->function(callee, caller->backpack);
}
// Part 3, internals
Piece *internal_self(Piece *callee, void *backpack) {
if (callee->function == internal_self) {
fprintf(stderr,
"recursive `self` calling between two pieces\n"
"piece 1 backpack: %p\n"
"piece 2: %p backpack: %p",
backpack, callee, callee->backpack);
exit(ERROR_RECURSIVE_SELF);
}
return apply(callee, piece_create(internal_self, backpack));
}
Piece *internal_put(Piece *callee, void *backpack) {
int *p_char = callee->backpack;
putchar(*p_char);
return piece_create(internal_self, NULL);
}
Source *main_create_source(char *file_name) {
FILE *source_file = fopen(file_name, "r");
if (!source_file) {
fprintf(stderr, "cannot open file \"%s\"\n", file_name);
exit(ERROR_CANNOT_OPEN_FILE);
}
char *source = NULL;
int length = 0;
while (true) {
char *line = NULL;
int line_len = 0;
line_len = (int)getline(&line, (size_t *)&line_len, source_file);
if (line_len < 0) {
break;
}
if (source == NULL) {
source = line;
} else {
source = realloc(source, sizeof(char) * (length + line_len + 1));
strcat(source, line);
// free(line);
}
length += line_len;
}
fclose(source_file);
return source_create(source, length, file_name);
}
#define MAIN_REGISTER_INTERNAL(record, name, func) \
record = record_register(record, name, sizeof(name) - 1, \
piece_create(func, NULL)); \
printf("%p %p\n", record, record->previous);
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "please specify source file by command line argument\n");
exit(ERROR_NO_ARGV);
}
Record *r = NULL;
MAIN_REGISTER_INTERNAL(r, "put", internal_put);
printf("main %p\n", r);
Source *s = main_create_source(argv[1]);
printf("main %p\n", r);
}
At first, the program crashed with a segmentation fault, I located the bad access code line, which have been deleted in this code demo. I figure out the original bug is that variable r in main would unexpected change after an unrelated calling to main_create_source, which would be demonstrated like this (save this code file as foo.c)
$ cc -O0 -g foo.c
$ ./a.out futaba_test.ftb
0x7fc0024025b0 0x0
main 0x7fc0024025b0
main 0x7fc0024025b0
$ cc -O3 -g foo.c
$ ./a.out futaba_test.ftb
0x7fe861c025b0 0x0
main 0x7fe861c025b0
main 0x7fe800000000
The behavior varied when changing optimization level. It has nothing todo with EOF since I have removed it, and in my opinion the memory for strcat's destination is rich enough. Thanks for any help.
By the way if there is any requirement to point out the purpose of this snippet. This is an interpreter for a minimal language I am working on. It is able to evaluate small source code snippet at the time and this is the first time I have tried to build it with -O3. The bug will only disappear without any level optimization.
(The following is the original post and is able to be ignored.)
I have this code file. When compiling with cc -O0 futaba.c, and running it with ./a.out futaba_test.ftb, the result will be
0x7fba60c025b0 0x0
0x7fba60c025e0 0x7fba60c025b0
0x7fba60c02610 0x7fba60c025e0
0x7fba60c02640 0x7fba60c02610
0x7fba60c02670 0x7fba60c02640
0x7fba60c026b0 0x7fba60c02670
0x7fba60c026d0 0x7fba60c026b0
0x7fba60c02700 0x7fba60c026d0
0x7fba60c02730 0x7fba60c02700
main 0x7fba60c02730
main 0x7fba60c02730
A%
(Zsh add the postfix %) everything is going well. But when compiling with -O3 rather than -O0, than result will be
0x7f8f274025b0 0x0
0x7f8f274025e0 0x7f8f274025b0
0x7f8f27402610 0x7f8f274025e0
0x7f8f27402640 0x7f8f27402610
0x7f8f27402670 0x7f8f27402640
0x7f8f274026b0 0x7f8f27402670
0x7f8f274026d0 0x7f8f274026b0
0x7f8f27402700 0x7f8f274026d0
0x7f8f27402730 0x7f8f27402700
main 0x7f8f27402730
main 0x7f8f00000000
[1] 27811 segmentation fault ./a.out futaba_test.ftb
The last two main line print different address, and the second one is not valid, which cause the stack overflow bug later in record_resolve function.
What is the problem?
That's a lot of code, but here's at least a flag:
char source_fetch(Source *s) {
return s->current == s->length ? EOF : s->source[s->current];
}
This forces EOF into a char, which is a very bad idea. That's why all standard C functions that can return EOF (like getchar() return int.
No idea what an optimizing compiler can make out of that, but once you factor in code that waits for EOF using that ... it's smelly.
Note: this is perhaps bad form as an answer; but it's pointing out a concrete problem with the code.
Also none of the heap allocations seems to have code looking for NULL being returned; that's a bit scary too.
Using libfuse in my c-project, I 'm trying to add custom command-line arguments and handle them.
Here is an example on which I rely
https://github.com/libfuse/libfuse/wiki/Option-Parsing
First, I tried to do the argument for the mount point configuration -с <pathtoconfig>
I tried many ways to describe an option like -c --config conf= -o conf=, but ineffectually
Please, help me find the right path to solve the problem :(
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fuse.h>
#include "fuu_walk.h"
#include "jsmnload.h"
#define _JSMN_TOKEN_SIZE_ 256
#define _JSMN_BUFFER_SIZE_ 4096
#define MYFS_OPT(t, p, v) { t, offsetof(struct myfs_config, p), v }
struct myfs_config {
char *mystring;
} conf;
static struct fuse_opt myfs_opts[] = {
MYFS_OPT("-c %s", mystring, 1),
FUSE_OPT_END
};
jsmntok_t t[_JSMN_TOKEN_SIZE_];
char buf[_JSMN_BUFFER_SIZE_];
#if 0
= ""
"{\"root\": ["
"{\"path\":\"/\", \"mode\":\"drw-------\"},"
"{\"path\":\"/12ABC345DE67\", \"mode\":\"drw-------\"},"
"{\"path\":\"/12ABC345DE67/_XQ01\", \"mode\":\"-rw-------\"},"
"{\"path\":\"/12ABC345DE67/_XQ02\", \"mode\":\"-rw-------\"},"
"{\"path\":\"/12ABC345DE78\", \"mode\":\"drw-------\"},"
"{\"path\":\"/12ABC345DE89\", \"mode\":\"drw-------\"}"
"]}";
#endif
static int myfs_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
{
struct myfs_config *ptr = (struct myfs_config *)data;
FILE *conf;
int rc = 0;
//I wanna check the argument on the each iteration of fuse_opt_parse. It's just the debug printf
printf("arg = %s\t string %s\t key = %i\n", arg, ptr->mystring, key);
switch (key) {
case 1:
conf = fopen(ptr->mystring, "r");
rc = read(fileno(conf), buf, _JSMN_BUFFER_SIZE_);
if ( jsmnload(buf, t, _JSMN_TOKEN_SIZE_, fuu_mkfstree) < 0 ) {
printf("Error load configuration\n");
exit(-1);
}
}
return 1;
}
int main(int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
memset(&conf, 0, sizeof(conf));
fuse_opt_parse(&args, &conf, myfs_opts, myfs_opt_proc);
return fuu_main(args.argc, args.argv);
}
Launch example
./appendix/fuu /mnt/cdrom/ -c /mnt/fs.json
As a result, printf in myfs_opt_proc function works only once and outputs
arg = /mnt/cdrom/ string (null) key = -2
Why myfs_opt_proc does not work for option -c?
I cannot comment so as an answer... looking at the reference you provided it seems to me that there is no option starting with -c. So result seems correct because fuse cannot parse this. Look at this snippet from your link:
fuse_opt_add_arg(&args, "-omodules=subdir,subdir=/foo");
You may try to announce options to fuse using -o.
Edit: Youre example differs from the linked one, try to add to following line to the defined struct:
FUSE_OPT_KEY("-c", "KEY_CONFIG");
and some line before
emum {
KEY_CONFIG
};
and parse it like this in youre myfs_opt_proc function
switch (key) {
case KEY_CONFIG:
/* ... */
. Summed up you missed declaring the -c key.
I will go ahead and say this is a homework assignment for an intro to Linux class. I would not be posting it without extensive attempts on my own, and seeing as I am a distance student this semester, I cannot make it to campus for tutoring. I need some help finding out what the issue is.
Essentially the assignment asks us to make a program that serves the same basic function as the pwd command in POSIX, to show the absolute path for the current directory. We are to use three functions along with main. We are not to use the getcwd command as well. I'll list them and their purpose
inum_to_filename: Accepts three arguments (inode number to translate, a pointer to a buffer where the name is written, and the size of the buffer). Returns nothing. It is to:
Open the current directory,
Read the first directory entry,
If the inode of the current directory matches the one passed in, copy name to buffer and return.
Otherwise read the next directory entry and repeat the previous step.
filename_to_inum: Accepts one argument (a char * representing the filename). It returns the corresponding inode number. It is to:
Read the information from the files inode into a structure in memory.
If there is any problem, display the appropriate error.
Return the inode number from the structure.
display_path: Accepts one argument (inode from the current working directory). It returns nothing. It is to:
Create an array of characters to use as a buffer for the name of the directory.
Get the inode for the parent directory using filename_to_inode.
If the parent inode is equal to the current inode, we have reached root and can return.
Otherwise, change to the parent directory and use inum_to_filename to find the name for the inode that was passed into the function. Use the buffer from step 1 to store it.
Recursively call display_path to display the absolute path.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
while (counter != 1) {
if (inode_arg == dirent_ptr->d_ino) {
strcat(pathBuffer, "/");
strcat(pathBuffer, dirent_ptr->d_name);
counter = counter + 1;
return;
} else {
dirent_ptr = readdir(dir_ptr);
}
}
closedir(dir_ptr);
}
int filename_to_inum (char *src) {
int res = 0;
struct stat info;
int result = stat(src, &info);
if (result != 0) {
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
} else {
res = info.st_ino;
}
return res;
}
void display_path (int ino_src) {
int bufSize = 4096;
char pathBuffer[bufSize];
int ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt) {
//print for test
inum_to_filename(ino_src, pathBuffer, bufSize);
printf("%s", pathBuffer);
return;
} else {
//print for test
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
}
int main (int argc, char *argv[]) {
int c_ino = filename_to_inum(".");
display_path(c_ino);
printf("\n");
}
As of right now it is displaying "/./MyName" with MyName being my personal named directory on the server. It is the directory I am running the program from. When using pwd I return "/home/MyName". I'm not really sure what my next step to getting the absolute path correct is.
The code is mostly set up to print one name at a time in the correct order, so the primary problem is the use of strcat() rather than strcpy(). Also, detecting when you're in the root directory at the start is important; if you don't, you can end up with /. or something similar (depending on exactly how you coordinate the printing) when the current directory is the root directory.
This version of your code has:
Squished the loop in inum_to_filename(), but also added error reporting. Remember, a process can be run in a directory which it does not have permission to get to (it requires a setuid program, usually — although permissions could be changed after the program is launched). In that case, it may fail to open .. (or .).
Lost variable count; it wasn't serving a useful purpose. Using the assign-and-test idiom allows the code to contain a single call to readdir().
Use strcpy() instead of strcat().
Use type ino_t to store inode numbers. Use size_t for sizes.
Reduce number of intermediate variables in filename_to_inum().
Note that the code in the if (ino_src == ino_prnt) statement body is for the root directory; in the absence of the testing print, it would do nothing.
Note that the printing in the else part is a major part of the operations, not just test printing.
Error check chdir("..");
Detect root in main().
Observe that this code is not directly suitable for rewriting into a function because it changes the process's current directory to / when it succeeds.
Revised code:
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static void inum_to_filename(ino_t inode_arg, char *pathBuffer, size_t size_arg)
{
assert(size_arg > 0);
DIR *dir_ptr = opendir(".");
if (dir_ptr == 0)
{
fprintf(stderr, "Failed to open directory '.' (%d: %s)\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
struct dirent *dirent_ptr;
while ((dirent_ptr = readdir(dir_ptr)) != 0)
{
if (inode_arg == dirent_ptr->d_ino)
{
if (strlen(dirent_ptr->d_name) >= size_arg)
{
fprintf(stderr, "File name %s too long (%zu vs %zu max)\n",
dirent_ptr->d_name, strlen(dirent_ptr->d_name), size_arg);
exit(EXIT_FAILURE);
}
strcpy(pathBuffer, dirent_ptr->d_name);
break;
}
}
closedir(dir_ptr);
}
static ino_t filename_to_inum(char *src)
{
struct stat info;
if (stat(src, &info) != 0)
{
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
}
return info.st_ino;
}
static void display_path(ino_t ino_src)
{
size_t bufSize = 4096;
char pathBuffer[bufSize];
ino_t ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt)
{
// print for test
inum_to_filename(ino_src, pathBuffer, bufSize);
printf("%s", "(root): /\n");
}
else
{
// print for real
if (chdir("..") != 0)
{
fprintf(stderr, "Failed to chdir to .. (%d: %s)\n",
errno, strerror(errno));
}
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("/%s", pathBuffer);
}
}
int main(void)
{
ino_t c_ino = filename_to_inum(".");
ino_t r_ino = filename_to_inum("/");
if (r_ino == c_ino)
putchar('/');
else
display_path(c_ino);
printf("\n");
}
There are undoubtedly other ways to fix this.
Caveat: this is giving me some grief when working in /Volumes/CRUZER/Sub-Directory which is a memory stick. It fails to find the inode (1, which is surprising) when scanning /Volumes, and I've not worked out why. One of my programs — a getpwd implementation — is working fine; another is having a different problem. I expect I'll get to the bottom of it all. Testing on Mac OS X 10.10.5 with GCC 5.1.0.
this is really nice assignment :).
I read and tried your code, and it is almost correct. There were two small issues which were causing the incorrect behaviour.
First issue
When display_path reaches the root folder you don't need to call inum_to_filename and print the name of the folder because you have already printed the first folder of the path in the previous iteration. This prevents your code from showing a "./" in the beginning of the path.
That is, the if condition becomes:
if (ino_src == ino_prnt) {
return;
} else {
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
Second Issue:
You're not initializing propertly the buffer where you save the name of the directory. This causes random values to be displayed. To solve this issue you can just set the initial value of the buffer to zero by using memset.
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
memset(pathBuffer, 0, size_arg);
while (counter != 1) {
...
}
closedir(dir_ptr);
}
Full code working :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
memset(pathBuffer, 0, size_arg);
while (counter != 1) {
if (inode_arg == dirent_ptr->d_ino) {
strcat(pathBuffer, "/");
strcat(pathBuffer, dirent_ptr->d_name);
counter = counter + 1;
return;
} else {
dirent_ptr = readdir(dir_ptr);
}
}
closedir(dir_ptr);
}
int filename_to_inum (char *src) {
int res = 0;
struct stat info;
int result = stat(src, &info);
if (result != 0) {
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
} else {
res = info.st_ino;
}
return res;
}
/*
- Create an array of characters to use as a buffer for the name of the directory.
- Get the inode for the parent directory using filename_to_inode.
- If the parent inode is equal to the current inode, we have reached root and can return.
- Otherwise, change to the parent directory and use inum_to_filename to find the name for
the inode that was passed into the function. Use the buffer from step 1 to store it.
- Recursively call display_path to display the absolute path.
*/
void display_path (int ino_src) {
int bufSize = 4096;
char pathBuffer[bufSize];
int ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt) {
return;
} else {
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
}
int main (int argc, char *argv[]) {
int c_ino = filename_to_inum(".");
display_path(c_ino);
printf("\n");
}
Output :
ubuntu#ubuntu-VirtualBox:~/dev$ vi pwd.c
ubuntu#ubuntu-VirtualBox:~/dev$ gcc pwd.c
ubuntu#ubuntu-VirtualBox:~/dev$ ./a.out
/home/ubuntu/dev
ubuntu#ubuntu-VirtualBox:~/dev$ pwd
/home/ubuntu/dev
ubuntu#ubuntu-VirtualBox:~/dev$
The Linux specific backtrace() and backtrace_symbols() allows you to produce a call trace of the program. However, it only prints function addresses, not their names for my program. How can I make them print the function names as well ? I've tried compiling the program with -g as well as -ggdb. The test case below just prints this:
BACKTRACE ------------
./a.out() [0x8048616]
./a.out() [0x8048623]
/lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
./a.out() [0x8048421]
----------------------
I'd want the first 2 items to also show the function names, foo and main
Code:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void foo()
{
print_backtrace();
}
int main()
{
foo();
return 0;
}
The symbols are taken from the dynamic symbol table; you need the -rdynamic option to gcc, which makes it pass a flag to the linker which ensures that all symbols are placed in the table.
(See the Link Options page of the GCC manual, and / or the Backtraces page of the glibc manual.)
Use the addr2line command to map executable addresses to source code filename+line number. Give the -f option to get function names as well.
Alternatively, try libunwind.
The excellent Libbacktrace by Ian Lance Taylor solves this issue. It handles stack unwinding and supports both ordinary ELF symbols and DWARF debugging symbols.
Libbacktrace does not require exporting all symbols, which would be ugly, and ASLR does not break it.
Libbacktrace was originally part of the GCC distribution. Now, a standalone version can be found on Github:
https://github.com/ianlancetaylor/libbacktrace
the answer on the top has a bug
if ret == -1 and errno is EINTER you should try again, but not count ret as copied
(not going to make an account just for this, if you don't like it tough)
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) {
if (errno != EINTR))
break;
//else
continue;
}
buf += (size_t) ret;
len -= (size_t) ret;
}
}
Boost backtrace
Very convenient because it prints both:
unmangled C++ function names
line numbers
automatically for you.
Usage summary:
#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>
std::cout << boost::stacktrace::stacktrace() << std::endl;
I have provided a minimal runnable example for it and many other methods at: print call stack in C or C++