GDB: Question about relative and absolute paths to files in backtraces - gcc

I have question about gdb or gcc (but not firefox).
I see only absolute paths in gdb when i debugging firefox. Example:
5 0x01bb0c52 in nsAppShell::ProcessNextNativeEvent
(this=0xb7232ba0, mayWait=1)
at
/media/25b7639d-9a70-42ca-aaa7-28f4d1f417fd/firefox-dev/mozilla-central/widget/src/gtk2/nsAppShell.cpp:144
It's uncomfortable for reading such backtraces.
If i try to compile and debug tiny test program i see such backtrace (with relative paths to files):
0 main () at prog.c:5
How can i see only relative paths in backtraces when debugging firefox?
P.S. gcc 4.4.1; gdb 7.0.

GDB will show absolute or relative path depending on how the program was compiled. Consider:
$ cd /tmp
$ cat t.c
int main() { return 0; }
$ gcc -g t.c && gdb -q -ex start -ex quit ./a.out
Reading symbols from /tmp/a.out...done.
Temporary breakpoint 1 at 0x4004c8: file t.c, line 1.
Temporary breakpoint 1, main () at t.c:1
1 int main() { return 0; }
Now the same, but compile source via absolute path:
$ gcc -g /tmp/t.c && gdb -q -ex start -ex quit ./a.out
Reading symbols from /tmp/a.out...done.
Temporary breakpoint 1 at 0x4004c8: file /tmp/t.c, line 1.
Temporary breakpoint 1, main () at /tmp/t.c:1
1 int main() { return 0; }
And again, this time with relative path that includes directory prefix:
$ cd /
$ gcc -g tmp/t.c -o tmp/a.out && gdb -q -ex start -ex quit tmp/a.out
Reading symbols from /tmp/a.out...done.
Temporary breakpoint 1 at 0x4004c8: file tmp/t.c, line 1.
Temporary breakpoint 1, main () at tmp/t.c:1
1 int main() { return 0; }
So, you can get gdb to show relative path if you change the way firefox is built. That may prove to be a very non-trivial proposition.

Related

Bash builtins also available as separate executables

I wanted to understand bash builtins. Hence the following questions:
When I think of the term builtin I am thinking that the bash executable has a function defined in its symbol table that other parts of the executable can access without actually having to fork. Is this what builtin means?
I also see that some builtins have a separate executable. For instance type [ returns [ is a shell builtin. But then I also see an executable named /usr/bin/[. Is it correct to say that the same code is available through two executables: one through bash program and another through /usr/bin/[?
Loosely speaking, the program version of the built-ins is used when the shell interpreter is not available or not needed. Let's explain it in more details...
When you run a shell script, the interpreter recognizes the built-ins and will not fork/exec but merely call the function corresponding to the built-in. Even if you call them from an C/C++ executable through system(), the latter launches a shell first and then makes the spawn shell run the built-in.
Here is an example program, which runs echo message thanks to system() library service:
#include <stdlib.h>
int main(void)
{
system("echo message");
return 0;
}
Compile it and run it:
$ gcc msg.c -o msg
$ ./msg
message
Running the latter under strace with the -f option shows the involved processes. The main program is executed:
$ strace -f ./msg
execve("./msg", ["./msg"], 0x7ffef5c99838 /* 58 vars */) = 0
Then, system() triggers a fork() which is actually a clone() system call. The child process#5185 is launched:
clone(child_stack=0x7f7e6d6cbff0, flags=CLONE_VM|CLONE_VFORK|SIGCHLD
strace: Process 5185 attached
<unfinished ...>
The child process executes /bin/sh -c "echo message". The latter shell calls the echo built-in to display the message on the screen (write() system call):
[pid 5185] execve("/bin/sh", ["sh", "-c", "echo message"], 0x7ffdd0fafe28 /* 58 vars */ <unfinished ...>
[...]
[pid 5185] write(1, "message\n", 8message
) = 8
[...]
+++ exited with 0 +++
The program version of the built-ins is useful when you need them from a C/C++ executable without an intermediate shell for the sake of the performances. For instance, when you call them through execv() function.
Here is an example program which does the same thing as the preceding example but with execv() instead of system():
#include <unistd.h>
int main(void)
{
char *av[3];
av[0] = "/bin/echo";
av[1] = "message";
av[2] = NULL;
execv(av[0], av);
return 0;
}
Compile and run it to see that we get the same result:
$ gcc msg1.c -o msg1
$ ./msg1
message
Let's run it under strace to get the details. The output is shorter because no sub-process is involved to execute an intermediate shell. The actual /bin/echo program is executed instead:
$ strace -f ./msg1
execve("./msg1", ["./msg1"], 0x7fffd5b22ec8 /* 58 vars */) = 0
[...]
execve("/bin/echo", ["/bin/echo", "message"], 0x7fff6562fbf8 /* 58 vars */) = 0
[...]
write(1, "message \1\n", 10message
) = 10
[...]
exit_group(0) = ?
+++ exited with 0 +++
Of course, if the program is supposed to do additional things, a simple call to execv() is not sufficient as it overwrites itself by the /bin/echo program. A more elaborated program would fork and execute the latter program but without the need to run an intermediate shell:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
if (fork() == 0) {
char *av[3];
av[0] = "/bin/echo";
av[1] = "message";
av[2] = NULL;
execv(av[0], av);
}
wait(NULL);
// Make additional things before ending
return 0;
}
Compile and run it under strace to see that the intermediate child process executes the /bin/echo program without the need of an intermediate shell:
$ gcc msg2.c -o msg2
$ ./msg2
message
$ strace -f ./msg2
execve("./msg2", ["./msg2"], 0x7ffc11a5e228 /* 58 vars */) = 0
[...]
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLDstrace: Process 5703 attached
, child_tidptr=0x7f8e0b6e0810) = 5703
[pid 5703] execve("/bin/echo", ["/bin/echo", "message"], 0x7ffe656a9d08 /* 58 vars */ <unfinished ...>
[...]
[pid 5703] write(1, "message\n", 8message
) = 8
[...]
[pid 5703] +++ exited with 0 +++
<... wait4 resumed>NULL, 0, NULL) = 5703
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5703, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
exit_group(0) = ?
+++ exited with 0 +++
the bash executable has a function defined in its symbol table
There are builtins that are included inside Bash executable. You can load builtins dynamically from a separate shared library on runtime.
can access without actually having to fork
Yes.
Is it correct to say that the same code is available through two executables: one through bash executable and another through /usr/bin/[?
No, it's a different source code. One is a Bash builtin and the other is a program. It will be a different source code. There is also different behavior in grey areas.
$ printf "%q\n" '*'
\*
$ /bin/printf "%q\n" '*'
'*'
$ time echo 1
1
real 0m0.000s
user 0m0.000s
sys 0m0.000s
$ /bin/time echo 1
1
0.00user 0.00system 0:00.00elapsed 50%CPU (0avgtext+0avgdata 2392maxresident)k
64inputs+0outputs (1major+134minor)pagefaults 0swaps
$ [ -v a ]
$ /bin/[ -v a ]
/bin/[: ‘-v’: unary operator expected

Retrieve const string value from .elf binary via variable name using command line utility?

Consider the following main.c:
#include <stdio.h>
const char greeting[] = "hello world";
int main() {
printf("%s!\n", greeting);
return 0;
}
I compiled this in Ubuntu with:
gcc -g main.c -o main.exe
I would like to retrieve the value of the variable named greeting; considering it is const, it won't change, so it should be possible to retrieve the value "hello world" from the executable.
Basically, I can see the variable name in the binary using:
$ readelf -p .rodata main.exe | grep hello
[ 8] hello world
... and I can see the value using:
$ readelf -s main.exe | grep greeting
59: 0000000000002008 12 OBJECT GLOBAL DEFAULT 18 greeting
I could try parsing the output of readelf -s and readelf -p to get what I want (retrieve the value of the variable named greeting), but I'm pretty sure I'll mess it up.
So is there some combination of switches of bintools utilities (or any command line program, really), which would perform the equivalent of the following pseudocode:
$ [tool] --get-value-of-variable-name greeting --program=main.exe
"hello world"
or even:
$ [tool] --verbose --get-value-of-variable-name greeting --program=main.exe
The constant value of the variable "greeting" in `main.exe` is:
is there some combination of switches of bintools utilities (or any command line program, really), which would perform the equivalent of the following pseudocode:
Sure:
you need to find the section in which the symbol resides, and the address within that section, and the length of data, and
you need to find where in the file the section itself starts, and
you need to dump length bytes from the right offset in the file.
Getting this all together (my file has slightly different data from yours):
readelf -Ws main.exe | grep greeting
29: 0000000000002008 12 OBJECT GLOBAL DEFAULT 17 greeting
readelf -WS main.exe | grep '\[17\]'
[17] .rodata PROGBITS 0000000000002000 002000 000019 00 A 0 0 8
This tells me that I need to dump 12 bytes (actually 11, since I don't want the terminating \0), starting of offset 0x2000 + (0x2008 (symbol address) - 0x2000 (section address)).
dd if=main.exe bs=1 skip=$((0x2008)) count=11 2>/dev/null
hello world
Now, parsing this data out from readelf output is more trouble than it's worth -- it's much easier to write a simple C++ program to produce the desired output. Using ELFIO should make this very easy.

Trying to understand behavior of `test <command>` in Bash

Suppose I have this simple C program (test.c):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
exit (1);
}
Obviously, the exit code of this program is 1:
$ gcc test.c
$ ./a.out
$ echo $?
1
But when I run test ./a.out, the result of the test doesn't match the exit code:
$ test ./a.out
$ echo $?
0
So what is actually being tested? Why is the result of the test 0?
test is a Bash built-in, often invoked by the alternative name [.
The last command (test ./a.out) exits with status 0 indicating success because test ./a.out checks whether ./a.out as a string has one or more characters in it (is not an empty string), and because it isn't an empty string, returns success or 0. The test ./a.out command line does not execute your a.out program — as you could see by printing something from within your program.
As written, your program doesn't need the <stdio.h> header or the arguments to main() — it should be int main(void). You could lose <stdlib.h> too if you use return 1; instead of exit(1);:
int main(void)
{
return 1;
}
To use the exit status in an if condition in the shell, just use it directly:
if ./a.out ; then
echo Success
else
echo Failure
fi
Rule of Thumb: Don't call C programs test because you will be confused sooner or later — usually sooner rather than later.
Your C program returns "1" to the shell (I'd prefer"return()" over exit()", but...)
If you wanted to actually run "a.out" in conjunction with the "*nix" test command, you'd use syntax like:
`./a.out` # classic *nix
or
$(./a.out) # Bash
If you did that, however, "test" would read the value printed to "stdout", and NOT the value returned by your program on exit.
You can read more about test here:
test(1) - Linux man page
The classic test command: Bash hackers wiki
Understanding exit codes and how to use them in Bash scripts
Here is an example:
C program:
#include <stdio.h>
int main (int argc, char *argv[]) {
printf("%d\n", argc);
return 2;
}
Shell script:
echo "Assign RETVAL the return value of a.out:"
./a.out RETVAL=$? echo " " RETVAL=$RETVAL
echo "Assign RETVAL the value printed to stdout by a.out:"
RETVAL=$(./a.out) echo " " RETVAL=$RETVAL
echo "Turn an 'trace' and run a.out with 'test':"
set -x
if [ $(./a.out) -eq 1 ]; then
echo "One"
else
echo "Not One"
fi
Example output:
paulsm#vps2:~$ ./tmp.sh
Assign RETVAL the return value of a.out:
1
RETVAL=2
Assign RETVAL the value printed to stdout by a.out:
RETVAL=1
Turn an 'trace' and run a.out with 'test':
+++ ./a.out
++ '[' 1 -eq 1 ']'
++ echo One
One
ALSO:
A couple of points that have already been mentioned:
a. return 1 is generally a better choice than exit (1).
b. "test" is probably a poor name for your executable - because it collides with the built-in "test" command. Something like "test_return" might be a better choice.

Why `build` with ldflag `-X` works only when the filename is specified?

I have the file playground.go:
package main
import (
"fmt"
)
var GitCommit string
func main() {
fmt.Printf("Hello world, version: %s\n", GitCommit)
}
why the behavior of the build ldflag -X depends on specifying the source filename?:
# CASE 1
$ go build -ldflags "-X main.GitCommit=abc" && ./go_playground
Hello world, version:
$ go tool nm go_playground
52a900 D main.GitCommit
# CASE 2
$ go build -ldflags "-X main.GitCommit=abc" playground.go && ./playground
Hello world, version: abc
$ go tool nm playground
5242f0 D main.GitCommit
4c5678 R main.GitCommit.str
EDIT: it seems that the problem happens when case 1 is executed from a symlinked directory; when case 1 is executed from the original directory, the variable is passed. I'm not sure if this is expected, or it's a bug.

Proper way to install bash 4.2 on OS X 10.9 Mavericks from source, without getting "abort trap: 6" and segfaults

I tried to install bash 4.2 from source (not homebrew). It sort of runs, sort of fails. When I make it my default login shell, I can run many commands, but often basic commands such as cd /System kill the shell.
I downloaded the master updated tarball, and I basically installed it with the equivalent of this:
./configure && make && sudo make install
sudo ln -s /usr/local/bin/bash /bin/bash4
sudo bash -c "echo /bin/bash4 >> /private/etc/shells"
chsh -s /usr/local/bin/bash # A
...and I also went to System Prefs -> Users and Groups -> (me) -> Advanced Options and changed the default shell to /bin/bash4.
Homebrew seems to install readline and require that, as well as add an additional flag for -DSSH_SOURCE_BASHRC to the environment (which shouldn't be a problem for what I'm doing)
workaround: change \w to \W in PS1.
the problem seems to be this line when t_string does not start with $HOME.
(parse.y:5278)
strcpy (t_string, polite_directory_format (t_string));
a quick and dirty fix:
diff --git i/general.c w/general.c
index 491a7ea267ab..ec9b6271015d 100644
--- i/general.c
+++ w/general.c
## -700,10 +700,11 ## polite_directory_format (name)
strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
tdir[0] = '~';
tdir[sizeof(tdir) - 1] = '\0';
- return (tdir);
}
else
- return (name);
+ strcpy (tdir, name);
+
+ return (tdir);
}
/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to
it boils down to this test case that compiles and runs with gcc but fails with clang/llvm:
#include <stdio.h>
#include <string.h>
char *foo(char *buf) {
return(buf);
}
int main(int argc, char *argv[]) {
char buf[1024];
strcpy(buf, "buffer");
strcpy(buf, foo(buf));
printf("%s\n", buf);
}
.
> gcc -o test test.c
> ./test
buffer
> cc -o test test.c
> ./test
Abort trap: 6

Resources