Eclipse IDE debugger : step into isn't working properly - c

All the functions used in the main file are correctly defined. However when I try to enter the debugging mode, for some reason IDE isn't stepping into said functions when asked to. Instead it acts like a step over and ignores the lines until the very last line, where out of the blue all variables appear in the window ; prior to that, no variable is present whatsoever.
Here's the main file :
#include "pointers.h"
int main(void){
whatisapointer();
whatisthesizeofapointer();
whatareNpointersplacedsuccessively(6);
return 0;
}
the pointers.c file used to define the functions in main :
#include "pointers.h"
void whatisapointer(){
int *pointer;
pointer = allocateOneInteger();
*pointer = 42;
}
void whatisthesizeofapointer(){
int a = sizeof(char);
int b = sizeof(int);
int c = sizeof(char*);
int d = sizeof(int*);
}
void whatareNpointersplacedsuccessively(int N){
int i, *Npointer, *current;
char *Npointerchar, *currentchar;
Npointer = allocateNInteger(N);
current = Npointer;
current = Npointer+1;
current = Npointer+2;
for(i=0;i<N;i++) *(Npointer+i) = i;
N=2*N;
Npointerchar = allocateNChar(N);
currentchar = Npointerchar;
currentchar = Npointerchar+1;
currentchar = Npointerchar+2;
for(i=0;i<N;i++) Npointerchar[i] = 65+i;
Npointer[N-3] = 0x68676665;
current = Npointer+N-3;
}
int* allocateOneInteger(){
return (int*)malloc(1*sizeof(int));
}
int* allocateNInteger(int N){
return (int*)malloc(N*sizeof(int));
}
char* allocateNChar(int N){
return (char*)malloc(N*sizeof(char));
}
void echange(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
void echangep(int *pa,int *pb)
{
int temp;
temp=*pa;
*pa=*pb;
*pb=temp;
}
/* Fonction allocateNFloat
*/
void allocateNFloat(int N){
}
And the makefile :
CC := gcc
FLAGS := -g -Wall -Werror
all : prog
prog : pointers.o mainpointers.o
$(CC) pointers.o mainpointers.o -o prog
fonctions.o : pointers.c pointers.h
$(CC) -c pointers.c $(FLAGS) -o pointers.o
mainpointers.o : mainpointers.c pointers.h
$(CC) -c mainpointers.c $(FLAGS) -o mainpointers.o
clean :
rm -f *.o
rm -f prog
I've done some research, none of which has helped me solve this issue.

You're very likely finding that the compiler is optimizing away your code, because the functions have no side-effects. (If you're not familiar with the concept of side effects, the gist is 'changes to program state that might influence other parts of the program'---compilers aggressively prune away side-effect-free code because, by definition, doing so doesn't change the behavior of the program.)
Even allocating memory isn't a side affect, because correct code should never be able to tell whether another part of the program has allocated memory.
The easiest side-effect is to print out the result of any intermediate computation you want to inspect via the debugger; that will force the optimizer to leave the code in place.
E.g.,
int foo() //no side effects, will be optimized to an empty function or pruned.
{
char *test = malloc(4096);
strcpy(test, "My test string");
return 0;
}
int foo() //dumb side effects
{
char *test = malloc(4096);
strcpy(test, "My test string");
printf("%02x", ((int)test & 0xff) ^ (test[0]) );//make output depend on the operations you wish to observe
return 0;
}
An alternate means to verify that the compiler is pruning away your code would be to disassemble the resulting object file...you should see that the functions consist of a single 'return' instruction...which is what the debugger is showing by highlighting the closing curly brace.

Related

Variable 'c' set but not used [-Wunused-but-set-variable]

I have searched and haven't really found and understood this error. It's weird that I only get the error for c, d, e and not for a and b or them all.
Program is about Dooubly Link List.
This happens when I compile with:
gcc -Wall -g -c program.c
Error part:
void try_mymem(int argc, char** argv) {
strategies strat;
void *a, *b, *c, *d, *e;
if (argc > 1)
strat = strategyFromString(argv[1]);
else
strat = First;
/* A simple example.
Each algorithm should produce a different layout. */
initmem(strat, 500);
a = mymalloc(100);
b = mymalloc(100);
c = mymalloc(100);
myfree(b);
d = mymalloc(50);
myfree(a);
e = mymalloc(25);
print_memory();
print_memory_status();
}
What am I doing wrong?
They're not used, just like the compiler says. You assign but never read. a and b are used as arguments, the others are not.

Parsing ssv file

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

Weird pointer conversion in C

I'm having trouble while writing my garbage collector in C. I give you a minimal and verifiable example for it.
The first file is in charge of dealing with the virtual machine
#include <stdlib.h>
#include <stdint.h>
typedef int32_t value_t;
typedef enum {
Lb, Lb1, Lb2, Lb3, Lb4, Lb5,
Ib, Ob
} reg_bank_t;
static value_t* memory_start;
static value_t* R[8];
value_t* engine_get_Lb(void) { return R[Lb]; }
value_t engine_run() {
memory_start = memory_get_start();
for (reg_bank_t pseudo_bank = Lb; pseudo_bank <= Lb5; ++pseudo_bank)
R[pseudo_bank] = memory_start + (pseudo_bank - Lb) * 32;
value_t* block = memory_allocate();
}
Then I have the actual garbage collector, the minimized code is:
#include <stdlib.h>
#include <stdint.h>
typedef int32_t value_t;
static value_t* memory_start = NULL;
void memory_setup(size_t total_byte_size) {
memory_start = calloc(total_byte_size, 1);
}
void* memory_get_start() { return memory_start; }
void mark(value_t* base){
value_t vbase = 0;
}
value_t* memory_allocate() {
mark(engine_get_Lb());
return engine_get_Lb();
}
Finally, minimal main is:
int main(int argc, char* argv[]) {
memory_setup(1000000);
engine_run();
return 0;
}
The problem I'm getting with gdb is that if I print engine_get_Lb() I get the address (value_t *) 0x7ffff490a800 while when printing base inside of the function mark I get the address (value_t *) 0xfffffffff490a800.
Any idea why this is happening?
Complementary files that may help
The makefile
SHELL=/bin/bash
SRCS=src/engine.c \
src/main.c \
src/memory_mark_n_sweep.c
CFLAGS_COMMON=-std=c11 -fwrapv
CLANG_SAN_FLAGS=-fsanitize=address
# Clang warning flags
CLANG_WARNING_FLAGS=-Weverything \
-Wno-format-nonliteral \
-Wno-c++98-compat \
-Wno-gnu-label-as-value
# Flags for debugging:
CFLAGS_DEBUG=${CFLAGS_COMMON} -g ${CLANG_SAN_FLAGS} ${CLANG_WARNING_FLAGS}
# Flags for maximum performance:
CFLAGS_RELEASE=${CFLAGS_COMMON} -O3 -DNDEBUG
CFLAGS=${CFLAGS_DEBUG}
all: vm
vm: ${SRCS}
mkdir -p bin
clang ${CFLAGS} ${LDFLAGS} ${SRCS} -o bin/vm
File with instructions .asm
5c190000 RALO(Lb,25)
value_t* memory_allocate() {
mark(engine_get_Lb());
return engine_get_Lb();
}
engine_get_Lb is not declared before use. It is assumed by the compiler to return int, per an antiquated and dangerous rule of the C language. It was deprecated in the C standard for quite some time, and now is finally removed.
Create a header file with declarations of all your global functions, and #include it in all your source files.
Your compiler should have at least warned you about this error at its default settings. If it did, you should have read and completely understood the warnings before continuing. If it didn't, consider an upgrade. If you cannot upgrade, permanently add -Wall -Wextra -Werror to your compilation flags. Consider also -Wpedantic and -std=c11.

undefined reference to `main' error in gcc 4.7

I created a program in C and I tried to compile it. When I use my gcc 4.8.1 compiler in Widows everything worked and my program too.
I compiled with the following arguments:
gcc -std=c99 -O2 -DCONTEST -s -static -lm children.c
But in linux I getting the following error:
/usr/lib/gcc/i486-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: error: ld returned 1 exit status
Why is that? My programm is working and I can't understand why I getting compiling errors in linux.
My code is:
/*---------------------*/
/* included files */
/*---------------------*/
#include <stdio.h>
#include <stdlib.h>
/*---------------------*/
/* defined constants */
/* for restriction */
/*---------------------*/
#define MIN 1
#define MAX 1000000
#define IOERROR 5 // 'Input/Output Error'
/*---------------------*/
/* function prototypes */
/*---------------------*/
int main();
FILE *read_input(const char *filename_r);
int count_children(FILE *input);
int pass_heights(FILE *input, int *children, int size);
int check_tall(const int *children, int size);
void write_output(const int total,const char *filename_w);
/*---------------------*/
/* start of program */
/*---------------------*/
int main() {
const char *filename_r = "xxx.in";
const char *filename_w = "xxx.out";
FILE *input = read_input(filename_r);
int size = count_children(input);
int *children = malloc(size * sizeof *children);
if (children==NULL)
exit(1); //General application error
pass_heights(input, children, size);
fclose(input);
int total = check_tall(children, size);
free(children);
write_output(total,filename_w);
return 0;
}
FILE *read_input(const char *filename_r) {
FILE *input = fopen(filename_r, "r");
if(input == NULL)
exit(IOERROR);
return input;
}
int count_children(FILE *input) {
int count = 0;
fscanf(input, "%d",&count);
if(count > MAX || count < MIN)
exit(1); //General application error
return count;
}
int pass_heights(FILE *input, int *children, int size) {
for(int i = 0; i < size; i++)
fscanf(input, "%d",&children[i]);
return *children;
}
int check_tall(const int *children, int size) {
int total = 0;
int tmp_max = 0;
for(int i = size - 1; i >= 0; i--)
{
if(children[i] > tmp_max) {
tmp_max = children[i];
total++;
}
}
return total;
}
void write_output(const int total,const char *filename_w) {
FILE *output = fopen(filename_w, "w");
if(output == NULL)
exit(IOERROR);
fprintf(output, "%d\n", total);
fclose(output);
}
You used -static option, which modifies the way executable is linked.
I was unable to reproduce your exact error message, but on my Linux it says that it is unable to link with -lc in static mode, and under my OSX it says that it is unable to locate -lcrt0.o. For me in both case, this means that the system is unable to locate the static stub.
If you remove -static it should work. If not, your problem is very strange.
The error you show indicates the linker is not finding the main() function in your code. As it is evident that you have included it in the source file, it is also evident you are not compiling with that command line (or you are compiling in other directory where you have a non-main() source called children.c, perhaps the build system makes a touch children.c if it doesn't find the source, and then compiles it --on that case it will not have a main() routine). Check that the files are properly created and where, as I think you aren't compiling that file anyway.
Try to use simple options before you go to more complicated ones. Try something like:
gcc -std=c99 -o children children.c
before trying to experiment with optimization or static linking anyway. Also, dynamic linking is normally better than static, so you'll get smaller executables (8Kb vs. 800Kb, and multiple copies of libc loaded per executable). Also, you don't need to include -lm as you aren't using any of the <math.h> functions (having it doesn't hurt anyway).
I have compiled your source with the following command line without any problem, but I do have support for statically linked executables and perhaps you don't (the command line I have put above would work in any linux, I suppose)
$ make CC='gcc' CFLAGS='-std=c99 -O2 -DCONTEST' LDFLAGS='-s -static -lm' children
gcc -std=c99 -O2 -DCONTEST -s -static -lm children.c -o children
children.c: In function ‘pass_heights’:
children.c:81:11: warning: ignoring return value of ‘fscanf’, declared with attribute warn_unused_result [-Wunused-result]
children.c: In function ‘count_children’:
children.c:69:11: warning: ignoring return value of ‘fscanf’, declared with attribute warn_unused_result [-Wunused-result]

Can a running C program access its own symbol table?

I have a linux C program that handles request sent to a TCP socket (bound to a particular port). I want to be able to query the internal state of the C program via a request to that port, but I dont want to hard code what global variables can be queried. Thus I want the query to contain the string name of a global and the C code to look that string up in the symbol table to find its address and then send its value back over the TCP socket. Of course the symbol table must not have been stripped. So can the C program even locate its own symbol table, and is there a library interface for looking up symbols given their name? This is an ELF executable C program built with gcc.
This is actually fairly easy. You use dlopen / dlsym to access symbols. In order for this to work, the symbols have to be present in the dynamic symbol table. There are multiple symbol tables!
#include <dlfcn.h>
#include <stdio.h>
__attribute__((visibility("default")))
const char A[] = "Value of A";
__attribute__((visibility("hidden")))
const char B[] = "Value of B";
const char C[] = "Value of C";
int main(int argc, char *argv[])
{
void *hdl;
const char *ptr;
int i;
hdl = dlopen(NULL, 0);
for (i = 1; i < argc; ++i) {
ptr = dlsym(hdl, argv[i]);
printf("%s = %s\n", argv[i], ptr);
}
return 0;
}
In order to add all symbols to the dynamic symbol table, use -Wl,--export-dynamic. If you want to remove most symbols from the symbol table (recommended), set -fvisibility=hidden and then explicitly add the symbols you want with __attribute__((visibility("default"))) or one of the other methods.
~ $ gcc dlopentest.c -Wall -Wextra -ldl
~ $ ./a.out A B C
A = (null)
B = (null)
C = (null)
~ $ gcc dlopentest.c -Wall -Wextra -ldl -Wl,--export-dynamic
~ $ ./a.out A B C
A = Value of A
B = (null)
C = Value of C
~ $ gcc dlopentest.c -Wall -Wextra -ldl -Wl,--export-dynamic -fvisibility=hidden
~ $ ./a.out A B C
A = Value of A
B = (null)
C = (null)
Safety
Notice that there is a lot of room for bad behavior.
$ ./a.out printf
printf = ▯▯▯▯ (garbage)
If you want this to be safe, you should create a whitelist of permissible symbols.
file: reflect.c
#include <stdio.h>
#include "reflect.h"
struct sym_table_t gbl_sym_table[1] __attribute__((weak)) = {{NULL, NULL}};
void * reflect_query_symbol(const char *name)
{
struct sym_table_t *p = &gbl_sym_table[0];
for(; p->name; p++) {
if(strcmp(p->name, name) == 0) {
return p->addr;
}
}
return NULL;
}
file: reflect.h
#include <stdio.h>
struct sym_table_t {
char *name;
void *addr;
};
void * reflect_query_symbol(const char *name);
file: main.c
just #include "reflect.h" and call reflect_query_symbol
example:
#include <stdio.h>
#include "reflect.h"
void foo(void)
{
printf("bar test\n");
}
int uninited_data;
int inited_data = 3;
int main(int argc, char *argv[])
{
int i;
void *addr;
for(i=1; i<argc; i++) {
addr = reflect_query_symbol(argv[i]);
if(addr) {
printf("%s lay at: %p\n", argv[i], addr);
} else {
printf("%s NOT found\n", argv[i], addr);
}
}
return 0;
}
file:Makefile
objs = main.o reflect.o
main: $(objs)
gcc -o $# $^
nm $# | awk 'BEGIN{ print "#include <stdio.h>"; print "#include \"reflect.h\""; print "struct sym_table_t gbl_sym_table[]={" } { if(NF==3){print "{\"" $$3 "\", (void*)0x" $$1 "},"}} END{print "{NULL,NULL} };"}' > .reflect.real.c
gcc -c .reflect.real.c -o .reflect.real.o
gcc -o $# $^ .reflect.real.o
nm $# | awk 'BEGIN{ print "#include <stdio.h>"; print "#include \"reflect.h\""; print "struct sym_table_t gbl_sym_table[]={" } { if(NF==3){print "{\"" $$3 "\", (void*)0x" $$1 "},"}} END{print "{NULL,NULL} };"}' > .reflect.real.c
gcc -c .reflect.real.c -o .reflect.real.o
gcc -o $# $^ .reflect.real.o
The general term for this sort of feature is "reflection", and it is not part of C.
If this is for debugging purposes, and you want to be able to inspect the entire state of a C program remotely, examine any variable, start and stop its execution, and so on, you might consider GDB remote debugging:
GDB offers a 'remote' mode often used when debugging embedded systems.
Remote operation is when GDB runs on one machine and the program being
debugged runs on another. GDB can communicate to the remote 'stub'
which understands GDB protocol via Serial or TCP/IP. A stub program
can be created by linking to the appropriate stub files provided with
GDB, which implement the target side of the communication
protocol. Alternatively, gdbserver can be used to remotely debug
the program without needing to change it in any way.

Resources