gdb: debug line by line with pipe - c

If I want to debug my program I call it like this:
gdb ./myprog
$ run < input.txt
But now I want to execute it line by line, but how can I do this? I know the step command but I can only call it, if the run command was called before. Do I have to stop the execution directly after the run command?

Gdb has a start command, which takes the same arguments as the run command. After starting the program, it stops as soon as possible, usually at the start of the main function. After that, you can use the step command and any other commands that require a live process.
Reference: Debugging with GDB: Starting your Program

Related

Both GDB and LLDB failing to reliably execute breakpoint commands in simple C file

As part of a research project, I am trying to write a gdb command file that outputs certain information on every line of code in arbitrary C source files until the program terminates. This seems easily accomplished with a while loop, outputting whatever data I want within the loop, and then calling "next" at the end of the loop. (I know I would want "step" to enter function calls; I'm not concerned about that at the moment.)
However, in addition to the data I output on every line, I also want to execute special commands at certain breakpoints. This seems easily accomplished with "command". However, I'm encountering a problem where the while loop and breakpoint commands won't both work.
Here is the extremely simple C file I'm working with for testing purposes:
int global;
int main() {
int x;
x=-1;
global = 5;
return(0);
}
I compile it with gcc -g -o simple simple.c. Then I run gdb -x commands.txt. If the contents of commands.txt are the following:
set confirm off
exec-file simple
file simple
set logging file gdb_output.txt
set logging on
set pagination off
#Special commands I want to execute on certain breakpoints
break 5
command
echo COMMAND 1 ACTIVATED\n
end
break 6
command
echo COMMAND 2 ACTIVATED\n
end
break 7
command
echo COMMAND 3 ACTIVATED\n
end
run
next
next
next
continue
quit
...then the contents of gdb_output.txt are the following, as expected:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
COMMAND 2 ACTIVATED
Breakpoint 3, main () at simple.c:7
7 return(0);
COMMAND 3 ACTIVATED
8 }
[Inferior 1 (process 29631) exited normally]
However, if I edit the command file to try to execute as a loop, replacing
next
next
next
continue
with
while true
next
end
but leaving the rest of the script exactly the same, then the commands I specified for the breakpoints on lines 6&7 never execute, as evidenced by the contents of gdb_output.txt after running the modified command file:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
Breakpoint 3, main () at simple.c:7
7 return(0);
8 }
__libc_start_main (main=0x4004d6 <main()>, argc=1, argv=0x7fffffffe128, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe118) at ../csu/libc-start.c:325
325 ../csu/libc-start.c: No such file or directory.
[Inferior 1 (process 29652) exited normally]
commands.txt:30: Error in sourced command file:
The program is not being run.
I know that the loop in its current form is problematic in that it will just keep calling "next" until the program terminates (so it never reaches "quit" at the bottom of the script), but that doesn't seem like it should stop the breakpoint commands from being run -- yet that is what appears to be happening. (If the breakpoint commands were being executed, I could condition my while loop to terminate once it hit breakpoints set before the C program's exit points.)
Is this a bug in GDB, or am I misunderstanding something? If this construction fundamentally won't work, then is there a way to execute a canned series of GDB commands on every step of a program run until the program terminates, while also executing commands specified at certain breakpoints -- or is this fundamentally impossible with a GDB script?
(My gdb version is 7.11.1 and if it matters, my OS is Linux.)
UPDATE
I decided to give lldb a shot and ran into some more perplexing issues (using the same C file as above, compiled with the same command). Here is my lldb script:
target create --no-dependents --arch x86_64 simple
breakpoint set --file simple.c --line 5
breakpoint command add
script print "COMMAND 1 ACTIVATED"
DONE
breakpoint set --file simple.c --line 6
breakpoint command add
script print "COMMAND 2 ACTIVATED"
DONE
breakpoint set --file simple.c --line 7
breakpoint command add
script print "COMMAND 3 ACTIVATED"
DONE
run
frame variable x
continue
frame variable x
continue
frame variable x
continue
quit
This is exhibiting rather strange behavior. The above version hits the first breakpoint, executes the associated command, then ignores all the following breakpoints. If I comment out just the second breakpoint, its associated command, and the corresponding frame variable x, continue, then breakpoints 1 and 3 both get hit and their corresponding commands are executed. Commenting out only the 1st or 3rd breakpoint and its associated command and frame variable x, continue results in just the first uncommented breakpoint getting hit, and its associated command run. In short, it appears that having breakpoints on two consecutive lines of code causes all breakpoints after the first to be ignored.
Does anyone know what is going on here? Is there a way I can have a breakpoint on every line and have them all get hit? And is this problem in any way related to the gdb issues described above?
I still haven't figured out why gdb and lldb were acting the way they were, but I did devise an alternative approach to accomplish what I want. I wrote a script to communicate with lldb using two named pipes whereby the script's stdout is linked to lldb's stdin and vice-versa, so the script can send lldb commands (frame variable -L, bt, step, etc.) then get lldb's output and parse it. The script can of course loop all it wants, so this bypasses the problem where I couldn't get gdb or lldb command files to loop properly.

what exit codes does gdb return on executing the next program line after one types the 'next' command?

In a linux terminal, I typed the command why (this command does not exist), and got this response
No command 'why'found, did you mean:
....
why: command not found
to get the exit code, this is what I typed in:
$?
and got the response:
127: command not found
I am assuming that when most of the commands run, they return codes.
Now with gdb, after it executes the next line of the C program being debugged, does it return any codes? And if so, how do I get those codes (a command like $? in gdb? - I haven't found a documentation in man gdb pages of such a command.
*In any case, gdb should know (and probably log) whether the line executed successfully and if not, what went wrong.
There's no such thing as a line of code executing successfully, at least not in same way that commands given to the shell do.
When you're at the shell, you're inputting either the name of an internal shell command or an external program. In the case of an external program, the value of $? is the value the program passed to the exit system call. If the shell can't find a program or command with that name, it gives you the error message you described.
In a compiled C program, there are no "codes" returned after a statement runs. There is only a state change in the program. For example, if a statement is i = i + 1;, then the value of i is 1 greater than its value prior to the statement running.
Unix processes always return a value: their exit code; named such because most of programs terminate with a call to exit (there is other possibilities but with no importance here). Beware that all processes return such a code, not most of them. Shells interpret user typed lines and transform them into processes. When a process terminates, the shel let you know the value of the return code of the last process that it controlled. In bash this variable is $?. If you want to print it, you can use echo $?. If you type $? it will interpret it as a command but 127 (the exit value of the last command) is not a command. The standard is to have a return value of 0 for correctly terminated processes, and any non nul value to signal that an error occurred somewhere in the logic of the program.
gdb also launch processes (to control them) but, executing a single line of code, is not running a process, so there is no exit code after executing one step of a program code. When you execute, in gdb, something that terminates the process its exit code is available in a internal gdb variable $_exitcode.

Linux, How to wait some seconds before run the c code in GDB

I am using the following command to load the c file program and run it in GDB from terminal in one click:
gdb --eval-command='file c.out' --eval-command='c'
I want to sleep some seconds after loading the program but before starting the program in GDB, some thing like:
gdb --eval-command='file c.out' --eval-command='<sleep 5>' --eval-command='c'
One way to give gdb a command-line option that will make it pause for 5 seconds is to tell it to run the "sleep 5" command in a shell:
--eval-command="shell sleep 5"

Cannot execute binary file when calling Java from Bash

I'm using Ubuntu 14.04.
There are 4 files involved: 'compile.sh', 'execute.sh', 'work.c', 'tester.sh'.
In 'compile.sh', it compiles the 'work.c' file and outputs an executable file called 'execute.sh'. In my own testing process, I do ./compile.sh, then ./execute.sh to run my C program. This works.
Now, the 'tester.sh' is a script that calls a Java program and this Java program does the same thing. It will run my 'compile.sh' first and then excute 'execute.sh'. It checks the correctness of my program outputs.
The problem is that when I do ./tester.sh, I get the error below
Reading first line from program...
./execute.sh: ./execute.sh: cannot execute binary file
First line of execution should match: Created \d heaps of sizes .+
Failed to execute (error executing ./execute.sh)
You can ignore the third line "First line of execution...."; it tries to check whether my output matches exactly with the tester. Since the binary file cannot be executed, then the first line does not match for sure.
So why does it say "cannot execute binary file"?
Content in compile.sh
#!/bin/bash
gcc -Wall work.c -o execute.sh
Content in tester.sh
#!/bin/bash
java -cp bin/tester.jar edu.ssu.cs153.work1.Tester
(bin/tester.jar is in my local machine; we can assume there is nothing wrong with the tester script.)
Diagnosis
It is weird, but not disallowed, to name an executable with the .sh extension. Your problem is that the Java code is trying to run it as a shell script (e.g. bash ./execute.sh), and it isn't a shell script so it fails. You need to change the Java to run the .sh file as an executable instead of as a shell script. Or, better (since you probably can't fix the Java), fix the compilation so that it produces an executable with a different name (e.g. work), and have execute.sh execute ./work.
File execute.sh is just an output file from compiling the work.c file. It is just like a.out by default from gcc. I can run ./execute.sh from the terminal and see all the correct outputs.
The trouble is, when you run it, you do ./execute.sh and the shell executes directly. The Java is running it as bash ./execute.sh, and that generates the error. Try it at the command line.
Prescription
On the face of it, you need to change compile.sh, perhaps like this (generating a program work from work.c):
#!/bin/bash
gcc -o work -Wall work.c
And you write a shell script called executable.sh that reads:
#!/bin/bash
exec ./work "$#"
This script runs your program with any command line arguments it is given. The exec means the shell replaces itself with your program; there are minor advantages to doing it that way, though it'll be OK if you omit the exec from the script.

Opening a new terminal window & executing a command

I've been trying to open a new terminal window from my application and execute a command on this second window as specified by the user. I've built some debugging software and I would like to execute the user's program on a separate window so my debugging output doesn't get intermixed with the programs output.
I am using fork() and exec(). The command I am executing is gnome-terminal -e 'the program to be executed'.
I have 2 questions:
Calling gnome-terminal means the user has to be running a gnome graphical environment. Is there a more cross-platform command to use (I am only interested in Linux machines though)?
After the command finishes executing the second terminal also finishes executing and closes. Is there any way to pause it, or just let it continue normal operation by waiting for input?
You probably want something like xterm -hold.
1) gnome-terminal should work reasonably also without the whole gnome environonment, anyway the old plain "xterm" is enough.
2) you can execute a short bash script that launch your program and at the end reads a line:
bash -c 'my program ... ; read a'
(or also 'xterm -e ...')

Resources