gdb and GPS: Cannot set a breakpoint on a function or procedure that is part of a protected type Ada object - gdb

I've got a protected object that presents functions and procedures in its interface.
In gdb, when I set a bp on the first line of one of those, I get odd results.
Here's a snippet from my gdb console:
(gdb)
(gdb) b database-access_manager.adb:20001
Breakpoint 3 at 0x1a10588: file y:/svs/central_switch/controller/database/
database-access_manager.ads, line 20001.
(gdb)
You can see that gdb is confused. I specified a bp at 20001 of the .adb file but gdb responded by saying it had set the bp at 20001 of the corresponding ads file - which doesn't have that many lines.
What gives?

That .ads file wouldn't happen to be defining or using a generic, would it?
I have yet to find a debugger that handles Ada generics very well. The compiler often creates a raft of semi-invisible code that confuses the heck out of debuggers. I suspect C++ templates have the same issue.
Another possibility is that you are looking at a source file that has been modified since your program was compiled.

Running on Windows with GNAT Pro 6.3.1 (I realise this isn't an ideal data point for you!) this worked fine.
I did notice that when I requested a bp on the subprogram specification, GDB effectively set two bps, one in the specification and one at the first statement: so, given
package body Protected_Object is
protected body PO is
procedure Put (V : Integer) is
begin
Value := V;
end Put;
function Get return Integer is
begin
return Value;
end Get;
end PO;
end Protected_Object;
the GDB console says (for Put)
gdb) break protected_object.adb:4
Breakpoint 1 at 0x401729: file protected_object.adb, line 6. (2 locations)
and at run time, sure enough there are 2 breaks:
Breakpoint 1, <protected_object__po__putP> (<_object>=..., v=42) at protected_object.adb:4
(gdb) cont
Breakpoint 1, protected_object.po.put (<_object>=..., v=42) at protected_object.adb:6
Version: GNU gdb (GDB) 7.0.1 for GNAT Pro 6.3.1 (20100112) [rev:158983]

Here's the update on my problem.
I made a protected type with access methods and used it in a small main and found that breakpoints in my example protected type worked fine.
Now I'm trying to understand why, within the context of my company's very large build, the breakpoints don't work.
I'm using the same gdb, GPS, & compiler switches in each case and it works for the small program but not in the large one.
I'll post my results when/if I have any.
Thanks to all the repliers.
Tom

Related

What things can cause GDB to error before hitting main?

I have a program with a large codebase, so I can't share a minimal example. What I've done is removed everything from main so that it looks like this:
int main()
{
std::cout << "here" << std::endl;
return 0;
}
But I'm still including all of the header that I was including before. When I run the debugger (GDB 9.2) it breaks before hitting main (I've a breakpoint set on the std::cout) with the following:
Starting debugger: C:\GameDev\Tools\MSYS2-32\mingw32\bin\gdb.exe -nx -fullname -quiet -args C:/GameDev/Colony/bin/Colony.exe
done
Setting breakpoints
Debugger name and version: GNU gdb (GDB) 9.2
Child process PID: 6840
In ?? () ()
Which I understand means something has happened during initialisation? I looked at this question Debug error before main() using GDB and did as suggested, printed the info file info file and set a breakpoint manually on the entry point and running it again. That doesn't seem to give me any additional info (same as above); or maybe I don't know what I'm looking for and how to retrieve it.
I've tried running the program through Dr Memory but it seems to execute okay in there, up until shutdown at which point after leaving Dr Memory gives me no errors but 2 suspected false positives. Both of these look like they're pointing to MingW hashtable code, which I believe is from my use of std::unordered_map in a few places (the only place where that hashtable code would come in). But none of that code is invoked because main is effectively empty.
None of that code is statically initialised either.
So, what sort of things can cause this error? I can try and track down the offending code if I know what can do it.

Is there a quick way to display the source code at a breakpoint in gdb?

I've set a breakpoint in gdb, and I'd like to see the exact line of source the breakpoint is on, just to confirm it's correct -- is there a quick way to do this?
The "info b" command gives me information about the breakpoints, but it doesn't display source:
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000006c3ba4 in MyClass::foo(bar*)
at /home/user1/src/MyClass.cpp:1021
I can type "list MyClass.cpp:1021" to see the lines around this breakpoint, but I'm wondering if there's a shorter way. Googling and reading the gdb manual didn't turn up anything.
I know that if I'm executing the program and have hit the breakpoint, I can just type "list", but I'm asking specifically about the case where I am not at the breakpoint (the program may not even be running).
You can use the list command to show sources. list takes a "linespec", which is gdb terminology for the kinds of arguments accepted by break. So, you can either pass it whatever argument you used to make the breakpoint in the first place (e.g., list function) or you can pass it the file and line shown by info b (e.g., list mysource.c:75).
I think the closest one can get to this is by turning the history on (set history save on) and then press CTRL-R to do a reverse search for the former list command.
More specifically, change your workflow when setting a breakpoint. After each command like b main GDB shows the source file like path/to/main.cpp, line 12. Immediately use this information in a quick list main.cpp:12. To show this location later press CTRL-R and type "main".
https://sourceware.org/gdb/onlinedocs/gdb/Command-History.html

How to properly debug a binary generated by `go test -c` using GDB?

The go test command has support for the -c flag, described as follows:
-c Compile the test binary to pkg.test but do not run it.
(Where pkg is the last element of the package's import path.)
As far as I understand, generating a binary like this is the way to run it interactively using GDB. However, since the test binary is created by combining the source and test files temporarily in some /tmp/ directory, this is what happens when I run list in gdb:
Loading Go Runtime support.
(gdb) list
42 github.com/<username>/<project>/_test/_testmain.go: No such file or directory.
This means I cannot happily inspect the Go source code in GDB like I'm used to. I know it is possible to force the temporary directory to stay by passing the -work flag to the go test command, but then it is still a huge hassle since the binary is not created in that directory and such. I was wondering if anyone found a clean solution to this problem.
Go 1.5 has been released, and there is still no officially sanctioned Go debugger. I haven't had much success using GDB for effectively debugging Go programs or test binaries. However, I have had success using Delve, a non-official debugger that is still undergoing development: https://github.com/derekparker/delve
To run your test code in the debugger, simply install delve:
go get -u github.com/derekparker/delve/cmd/dlv
... and then start the tests in the debugger from within your workspace:
dlv test
From the debugger prompt, you can single-step, set breakpoints, etc.
Give it a whirl!
Unfortunately, this appears to be a known issue that's not going to be fixed. See this discussion:
https://groups.google.com/forum/#!topic/golang-nuts/nIA09gp3eNU
I've seen two solutions to this problem.
1) create a .gdbinit file with a set substitute-path command to
redirect gdb to the actual location of the source. This file could be
generated by the go tool but you'd risk overwriting someone's custom
.gdbinit file and would tie the go tool to gdb which seems like a bad
idea.
2) Replace the source file paths in the executable (which are pointing
to /tmp/...) with the location they reside on disk. This is
straightforward if the real path is shorter then the /tmp/... path.
This would likely require additional support from the compiler /
linker to make this solution more generic.
It spawned this issue on the Go Google Code issue tracker, to which the decision ended up being:
https://code.google.com/p/go/issues/detail?id=2881
This is annoying, but it is the least of many annoying possibilities.
As a rule, the go tool should not be scribbling in the source
directories, which might not even be writable, and it shouldn't be
leaving files elsewhere after it exits. There is next to nothing
interesting in _testmain.go. People testing with gdb can break on
testing.Main instead.
Russ
Status: Unfortunate
So, in short, it sucks, and while you can work around it and GDB a test executable, the development team is unlikely to make it as easy as it could be for you.
I'm still new to the golang game but for what it's worth basic debugging seems to work.
The list command you're trying to work can be used so long as you're already at a breakpoint somewhere in your code. For example:
(gdb) b aws.go:54
Breakpoint 1 at 0x61841: file /Users/mat/gocode/src/github.com/stellar/deliverator/aws/aws.go, line 54.
(gdb) r
Starting program: /Users/mat/gocode/src/github.com/stellar/deliverator/aws/aws.test
[snip: some arnings about BinaryCache]
Breakpoint 1, github.com/stellar/deliverator/aws.imageIsNewer (latest=0xc2081fe2d0, ami=0xc2081fe3c0, ~r2=false)
at /Users/mat/gocode/src/github.com/stellar/deliverator/aws/aws.go:54
54 layout := "2006-01-02T15:04:05.000Z"
(gdb) list
49 func imageIsNewer(latest *ec2.Image, ami *ec2.Image) bool {
50 if latest == nil {
51 return true
52 }
53
54 layout := "2006-01-02T15:04:05.000Z"
55
56 amiCreationTime, amiErr := time.Parse(layout, *ami.CreationDate)
57 if amiErr != nil {
58 panic(amiErr)
This is just after running the following in the aws subdir of my project:
go test -c
gdb aws.test
As an additional caveat, it does seem very selective about where breakpoints can be placed. Seems like it has to be an expression but that conclusion is only via experimentation.
If you're willing to use tools besides GDB, check out godebug. To use it, first install with:
go get github.com/mailgun/godebug
Next, insert a breakpoint somewhere by adding the following statement to your code:
_ = "breakpoint"
Now run your tests with the godebug test command.
godebug test
It supports many of the parameters from the go test command.
-test.bench string
regular expression per path component to select benchmarks to run
-test.benchmem
print memory allocations for benchmarks
-test.benchtime duration
approximate run time for each benchmark (default 1s)
-test.blockprofile string
write a goroutine blocking profile to the named file after execution
-test.blockprofilerate int
if >= 0, calls runtime.SetBlockProfileRate() (default 1)
-test.count n
run tests and benchmarks n times (default 1)
-test.coverprofile string
write a coverage profile to the named file after execution
-test.cpu string
comma-separated list of number of CPUs to use for each test
-test.cpuprofile string
write a cpu profile to the named file during execution
-test.memprofile string
write a memory profile to the named file after execution
-test.memprofilerate int
if >=0, sets runtime.MemProfileRate
-test.outputdir string
directory in which to write profiles
-test.parallel int
maximum test parallelism (default 4)
-test.run string
regular expression to select tests and examples to run
-test.short
run smaller test suite to save time
-test.timeout duration
if positive, sets an aggregate time limit for all tests
-test.trace string
write an execution trace to the named file after execution
-test.v
verbose: print additional output

How to do a specific action when ANY Unknown Breakpoint gets Hit in GDB

I have read the following SO question:
Do specific action when certain breakpoint hits in gdb
Here, we use 'command' to decide what to do when the SPECIFIED Breakboint Gets Hit.
My Question is:
Suppose I put Breakpoints on ALL the Functions matching a given pattern:
gdb$rbreak func_
=> 100 Breakpoints (say)
When I execute this Code, I want to do the SAME Action - on hitting Each of these functions.
Hence, I cannot define something like:
command break_point_number
// since I don't know how many breakpoints will be there
Can somebody please suggest me:
How can I do a specific action-set when ANY Breakpoint gets Hit in GDB?
Thanks.
With a new enough version of gdb you can use a range:
(gdb) rbreak whatever
... gdb creates breakpoints N, N+1, ..., M
(gdb) commands N-M
> stuff
> end
I forget exactly when this feature went in.
With an older version of gdb, I'm not sure it can easily be done.
It can be done with difficulty: use set logging to write output to a file, then "info break", then "shell" to run scripts to edit the file into gdb commands, then "source". This is very painful.

GDB question - how do I go through disassembled code line by line?

I'd like to go through a binary file my teacher gave me line by line to check addresses on the stack and the contents of different registers, but I'm not extremely familiar with using gdb. Although I have the C code, we're supposed to work entirely from a binary file. Here are the commands I've used so far:
(gdb) file SomeCode
Which gives me this message:
Reading symbols from ../overflow/SomeCode ...(no debugging symbols found)...done.
Then I use :
(gdb) disas main
which gives me all of the assembly. I wanted to set up a break point and use the "next" command, but none of the commands I tried work. Does anyone know the syntax I would use?
try using ni which is nexti. equivalent is si which is step instruction
nexti if you want to jump over function calls.
stepi if you want to enter a function call.
The following documentation is very helpful; it has a list of all the important commands you could use on gdb.
X86-64: http://csapp.cs.cmu.edu/public/docs/gdbnotes-x86-64.pdf
IA32: http://csapp.cs.cmu.edu/public/docs/gdbnotes-ia32.pdf