Why gcc -g doesn't work with multiple files - c

To debug my C code I compile it with the -g flag and use lldb to see where my seg fault is for example.
I use the -g flag so the output of lldb is in C not Assembly.
but now I have a multiple files project and lldb shows only Assembly even tho I'm using the -g flag, it's like the -g flag applies only to one file.
Example:
gcc -g example.c
lldb a.out
>run
I get c code here
gcc -g example1.c example2.c main.c
lldb a.out
>run
I get assembly code here
Can anyone tell me what I'm I missing here?
and how can I get c code in lldb.
Thanks in advance.

When you just run the program you shouldn't be getting code at all.
You will be getting code if the program stops running. Then you need to look at the call stack to make sure you're actually in your own code.
If you're in library code then it will likely not have source available and you'll get assembler code. Go up the call-stack until you reach your own code.

GNU’s documentation for the ‘gcc -g’ says
Produce debugging information in the operating system’s native format (stabs, COFF, XCOFF, or DWARF). GDB can work with this debugging information.
Notice that it makes no mention of either C or assembler.
I imagine that in your first example the error was in your C code; in your second example the error was in a library, such as stdio, for which the debugger doesn’t have C source.
A segmentation fault corresponds to an invalid address. This might mean that you passed invalid data to a library that was expecting a pointer, or you passed a pointer to a buffer but an incorrect length.
A typical error that might cause this is passing a value (v) to a library that is expecting a pointer (&v).

Related

Analysing stack frame of C program in Linux

I'd like to ask if there is any option to gcc for Linux which allows debugging stack frames of given procedure of program written in C?
I know I can compile my program with -ggdb3 gcc parameter and it allows me to find out what are the symbols in this program. But is there any method to find out how the procedures arguments are passed (via stack or registers)?
I've got program which overwrites stack causing SEGV and I'd like to analyse it from the same program. First I'd like to find the problematic procedure and then I'm planning to find the place of the error.
You have a few options. One I prefer is to look at the actual generated code as it tells me exactly what is being executed. You can get this when compiling with gcc or g++. This will create a file with a .S suffix.
For example, gcc -S helloworld.c will also create a file called helloworld.S which contains the assembly code.
If you don't have source you can use tools like objdump to turn the binary code into a disassembly.
Lots of examples if you search for gcc assembly output

How to debug an experimental toolchain producing malformed executables

I am working on cross compiling an experimental GNU free Linux toolchain using clang (instead of gcc), compiler-rt (instead of libgcc), libunwind (available at http://llvm.org/git/libunwind.git) (instead of libgcc_s), lld (instead of GNU ld), libcxx (instead of libstdc++), libcxxabi (instead of not sure, I'm unclear on the GNU distinction between libstdc++ and its ABI) and musl (instead of glibc).
Using a musl based gcc cross compiler and a few patches I've managed to successfully compile all of the above and sucessfully compile and link a simple hello world C program with it. Something seems to have gone wrong, however, as running the hello world program results in a segmentation fault:
$ ./hello
Segmentation fault
$
Normally I would simply debug it with gdb, but herein lies the problem:
$ gdb ./hello
Reading symbols from ./hello...Dwarf Error: Could not find abbrev number 5 in CU at offset 0x52 [in module /home/main/code/main/asm/hello]
(no debugging symbols found)...done.
(gdb) start
Temporary breakpoint 1 at 0x206
Starting program: /hello
During startup program terminated with signal SIGSEGV, Segmentation fault.
(gdb)
I can't seem to step through the program in any way, I'm guessing because the error is occuring somewhere in early C runtime startup. I can't even step through the assembly using layout asm and stepi, so I really don't know how to find out where exactly the error is occuring (to debug my toolchain).
I have confirmed that the problem resides with lld by using a GNU binutils ld to successfully link the hello world object (statically) using the cross compiled libraries and object files, which results in a functional hello world program. Since lld successfully links, however, I can't pinpoint where failure is occuring.
Note I compiled hello as a static executable and used the -v gcc/clang option to verify that all the correct libraries and object files were linked it.
Note online GDB documentation has the following to say about the above error:
On Unix systems, by default, if a shell is available on your target, gdb) uses it to start your program. Arguments of the run command are passed to the shell, which does variable substitution, expands wildcard characters and performs redirection of I/O. In some circumstances, it may be useful to disable such use of a shell, for example, when debugging the shell itself or diagnosing startup failures such as:
(gdb) run
Starting program: ./a.out
During startup program terminated with signal SIGSEGV, Segmentation fault.
which indicates the shell or the wrapper specified with ‘exec-wrapper’ crashed, not your program.
I don't think this is true, considering what I'm working with and that the problem doesn't happen when I use GNU ld, and because the suggested solution (set startup-with-shell off) doesn't work.
The croscompilling means that the compilation is done on a host machine, and the output of the compilation is the binary which shall run on a target machine. Therefore the compiled binary is not compatible with your host CPU. Instead, if your target supports this, you could run the binary there and use the debugger from your toolchain to connect to the running binary remotely if supported. Or alternatively, the debugger may also be available at the target and you can debug the binary already at place.
Just to get more feeling, try to use command file for the compiled binary, and some other binaries of your host to see possible differences.

Side by side C, x86 programs

Is there anywhere I can find side-by-side examples of dead simple C and x86 programs? The examples I've found so far on the Internet seem to jump straight from "here's Hello World in x86" to "write your own operating system!" I'm having trouble internalizing what has to happen when you do things like call a function.
I would recommend a look at GCC's intermediate assembly output, for example call
gcc -S a.c
then look at a.s
Most of the time, smaller and easier to understand assembly is generated by optimizing, so you would rather use
gcc -O -S a.c
If you mean x86 assembly language, use objdump --disassemble myprog (on any GNU system) to show the assembly language generated by your C program. If your system doesn't have objdump, you can use ndisasm.
Assuming you mean x86 assembler then with gcc you can use gcc -S yourhelloworldprogram.c to get assembler output. For Visual Studio you can get assembler output by following this: How do I get the assembler output from a C file in VS2005
I reccommend ddd. You can have the both C sources (if you built with debug symbols) and the machine code showing. You can also step over the code interactively probing register and memory values. A great learning tool.
On gcc you can use the -save-temps -fverbose-asm options which is better than the -S option because it still generates the object file and you get also the preprocessor file. The verbose-asm is also important because it adds comments to the assembly output that make the link between the function and variable names of your program and the generated assembly code. Especially when generating with optimization it often is difficult to make the link between the source C and the assembly.

On debug of c program

I have a C program which throws segfault. However, as I use gdb to find out where the error is thrown. I get following stack info... I dont understand why #1 points to ??(). What is the possible reason for this? Thanks.
#0 __longjmp () at ../sysdeps/i386/__longjmp.S:68
#1 0x43746a57 in ?? ()
In order to debug your program, you need to compile it with debugging symbols included, which you can do by using the -g3 flag if compiling using GCC. When you run the debug version of your program in GDB and execute bt (for "backtrace") you should get a more sensible piece of output.
gdb doesn't know the name of the function so it puts ??.
have you tried compiling with debug symbols?
If longjmp() goes astray as it seems it is, then the problem is likely that you're abusing it - either by passing a jmpbuf that was never initialized by a setjmp() call, or by passing a jmpbuf that was set in a routine that has since returned.
For how to find out more with debugging information, see the other answers and compiling with the -g option.

How do I know which illegal address the program access when a segmentation fault happens

Plus, The program runs on a arm device running Linux, I can print out stack info and register values in the sig-seg handler I assign.
The problem is I can't add -g option to the source file, since the bug may won't reproduce due to performance downgrade.
Compiling with the -g option to gcc does not cause a "performance downgrade". All it does is cause debugging symbols to be included; it does not affect the optimisation or code generation.
If you install your SIGSEGV handler using the sa_sigaction member of the sigaction struct passed to sigaction(), then the si_addr member of the siginfo_t structure passed to your handler contains the faulting address.
I tend to use valgrind which indicates leaks and memory access faults.
This seems to work
http://tlug.up.ac.za/wiki/index.php/Obtaining_a_stack_trace_in_C_upon_SIGSEGV
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
// info->si_addr is the illegal address
}
If you are worried about using -g on the binary that you load on the device, you may be able to use gdbserver on the ARM device with a stripped version of the executable and run arm-gdb on your development machine with the unstripped version of the executable. The stripped version and the unstripped version need to match up to do this, so do this:
# You may add your own optimization flags
arm-gcc -g program.c -o program.debug
arm-strip --strip-debug program.debug -o program
# or
arm-strip --strip-unneeded program.debug -o program
You'll need to read the gdb and gdbserver documentation to figure out how to use them. It's not that difficult, but it isn't as polished as it could be. Mainly it's very easy to accidentally tell gdb to do something that it ends up thinking you meant to do locally, so it will switch out of remote debugging mode.
You may also want to use the backtrace() function if available, that will provide the call stack at the time of the crash. This can be used in order to dump the stack like it happens in an high level programming language when a C program gets a segmentation fault, bus error, or other memory violation error.
backtrace() is available both on Linux and Mac OS X
If the -g option makes the error disappear, then knowing where it crashes is unlikely to be useful anyway. It's probably writing to an uninitialized pointer in function A, and then function B tries to legitimately use that memory, and dies. Memory errors are a pain.

Resources