Say we have program1:
int main(void) {
char *env[2];
env[0] = "PATH=/";
env[1] = NULL;
execve("/program2", NULL, env);
exit(0);
}
We also have program2:
int main(void) {
exit(0);
}
Debugging this, PATH isn't actually modified in the new process (program2) that is executed.
Debugging this, PATH isn't actually modified in the new process
(program2) that is executed.
This is not true. Note that p environ doesn't work, while x 0x8049650 (address environ##GLIBC_2.0, obtained from info var environ) does:
(gdb) p environ
$1 = (char **) 0x0
(gdb) p/x &environ
$2 = 0xf7fbfd44
(gdb) x 0x8049650
0x8049650 : 0xffffdf18
(gdb) x/s **0x8049650
0xffffdfe8: "PATH=/"
Related
Is it possible to UNexpand macros in gdb ?
I've compiled binary with -g3 , and I can see macro definitions:
(gdb) info macro NGX_CORE_MODULE
Defined at /path/src/core/ngx_conf_file.h:70
included at /path/src/core/ngx_core.h:86
included at /path/src/core/ngx_cycle.c:9
#define NGX_CORE_MODULE 0x45524F43
(gdb)
but when i see at the variable, i see numeric value instead of the macro name
(gdb) p/x cycle->modules[0]->type
$17 = 0x45524f43
(gdb)
is it possible to get something like this:
(gdb) p cycle->modules[0]->type
$17 = NGX_CORE_MODULE
(gdb)
I'v tried user-defined function like this:
define expand_module_type_macro
if $arg0 == 0x45524F43
print "NGX_CORE_MODULE"
else
if $arg0 == 0x464E4F43
print "NGX_CONF_MODULE"
else
print $arg0
end
end
end
and it works
(gdb) expand_module_type_macro cycle->modules[0]->type
$18 = "NGX_CORE_MODULE"
(gdb)
but it has no practical use, because i can't use it with complex output:
(gdb) printf "module type=%s\n", expand_module_type_macro cycle->modules[0]->type
No symbol "expand_module_type_macro" in current context.
(gdb) set $m = expand_module_type_macro cycle->modules[0]->type
No symbol "expand_module_type_macro" in current context.
(gdb)
You might get something useful by creating a convenience function in python. I tested using this C program:
int var1 = 1234;
int var2 = 4567;
int
main ()
{
return 0;
}
And using this python script:
class ExpandMacro (gdb.Function):
"""Expand a value to a string, replacing with
macro name where possible."""
def __init__ (self):
super (ExpandMacro, self).__init__ ("expand")
def invoke (self, value):
if (value == 1234):
return "MY_MACRO"
else:
return str (value)
ExpandMacro ()
Then my GDB session:
(gdb) start
# .... snip ....
7 return 0;
(gdb) source lookup.py
(gdb) p $expand (var1)
$1 = "MY_MACRO"
(gdb) p $expand (var2)
$2 = "4567"
(gdb) printf "var1=%s\n", $expand (var1)
var1=MY_MACRO
(gdb) printf "var2=%s\n", $expand (var2)
var2=4567
In order to use the returned value with a %s format inside printf, I always return a string.
I am using (http://linux.die.net/man/3/hsearch) in my source code. I wrote a very basic code to test the hash functionality (did not want to reinvent the wheel by writing my own hash implementation). I see that it crashes with a segmentation fault in the search routine.
Any idea why its crashing?
#include <stdio.h>
#include <search.h>
#include <stdlib.h>
char *data[] = {
"cpe1","cpe2","cpe3","cpe4","cpe5","cpe6","cpe7","cpe8","cpe9","cpe10","cpe11","cpe12","cpe13"};
int main()
{
ENTRY ep, ep1, *ep_ptr, ep2;
int loop;
char *ptr;
char input[100];
hcreate (30);
for (loop=0; loop<13;loop++)
{
ptr = malloc (100);
sprintf (ptr, "%d.%d.%d.%d%c", loop+1, loop*2, loop*3, loop, '\0');
ep.key = data[loop];
ep.data = (void *) ptr;
printf ("%s --> %s\n", ep.key, (char *) ep.data);
ep_ptr = hsearch(ep, ENTER);
}
ep2.data = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
printf("%9.9s -> %9.9s: %s\n", ep2.key,
ep_ptr ? ep_ptr->key : "NULL", ep_ptr ? (char *)(ep_ptr->data) : "NULL");
return 0;
}
OUtput:
(gdb) r
Starting program: /home/globus/code/cpe/a.out
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
cpe1 --> 1.0.0.0
cpe2 --> 2.2.3.1
cpe3 --> 3.4.6.2
cpe4 --> 4.6.9.3
cpe5 --> 5.8.12.4
cpe6 --> 6.10.15.5
cpe7 --> 7.12.18.6
cpe8 --> 8.14.21.7
cpe9 --> 9.16.24.8
cpe10 --> 10.18.27.9
cpe11 --> 11.20.30.10
cpe12 --> 12.22.33.11
cpe13 --> 13.24.36.12
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:32
32 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
(gdb) bt
#0 __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:32
#1 0x00007ffff7b0ba71 in __GI_hsearch_r (item=..., action=FIND, retval=0x7fffffffdfd8,
htab=0x7ffff7dd67d0) at hsearch_r.c:149
#2 0x00007ffff7b0b92e in hsearch (item=..., action=<optimized out>)
at hsearch.c:34
#3 0x00000000004007a0 in main () at hash_test.c:32
(gdb)
While searching you should set ep2.key to search for the entry not ep2.data. So update your code to
//--v
ep2.key = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
As you have not set ep2.key the hsearch() function tries to access uninitialized pointer causing segmentation fault.
ep2.data = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
That first statement there is in error, you need to set the key to what you want to find, not the data.
Because you haven't set the key to anything, it has some arbitrary value in it (it's not static storage duration, so it's not initialised).
Then, hsearch is then running string functions on it (such as strlen) which is why you're getting the crash:
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ...
^^^^^^^^^^^^^
(running string function on non-string).
Your code should instead be:
ep2.key = (void *) "cpe1";
ep_ptr = hsearch(ep2, FIND);
In last printf, ep2.key which is not initialized
i notice a few things.
You are allocating ptr repeatedly within the loop but you are not freeing it. So thats a memory leak right there.
What is the data type for ep.data? Why do you have to convert to (void *)? Then again you are converting it to (char *)!!. Why?? If you data is already of char type then why this need to convert to (void *) repeatedly?
Fix these errors and then give it a try.
That line does not look correct:
ep2.data = (void *) "cpe1";
I found the definition of ENTRY so you'll have a better view of why it does not work as expected:
typedef struct entry {
char *key;
void *data;
} ENTRY;
You need to first allocate both key and data before copying all the bytes in it.
I have a application in C programming which uses jansson library(json library written in C). I'm trying to view value of json_t object in gdb but it just prints
(gdb) p jmsg
$20 = (json_t *) 0x69c350
(gdb) p *jmsg
$21 = {type = JSON_OBJECT, refcount = 1}
How is it possible to view the value of json_t in gdb.?
When in GDB, you can make function calls directly. Jansson library has a json_dumps(json_t *, int flags) API that returns a char* string of the json_t object.
So while in GDB, just simply do:
(gdb) call json_dumps(obj, 0)
GDB will then print the string output of your json object.
I have a C function that takes a parameter of type LPVOID. The values that gets passed in is \0 seperated array of characters. How can I cast the parameter to see the incoming value in visual studio / windbg?
You can do this in a script. Something like the following would work, which assumes char * strings and that the list ends in double NULLs (like a MULTI_SZ):
$$ Print a MULTI_SZ value in the debugger. Note that
$$ this script assume a char* string
$$ Grab the argument to the script
r #$t0 = ${$arg1}
$$ while *str != NULL
.while (by(#$t0) != 0)
{
$$ Print the string
da #$t0
$$ There's no strlen in this language, so find the NULL
.while (by(#$t0) != 0)
{
r #$t0 = #$t0 + 1
}
$$ String points to the NULL. Add one.
r #$t0 = #$t0 + 1
}
Save to a text file and then run the following in WinDBG:
0:000> $$>a<c:\dumps\multisz.txt 0x012210ec
012210ec "Foo"
012210f0 "Bar"
012210f4 "FooBar"
There is no cast that would allow you to observe that in watch windows. For VS you will have to open up a memory window on the address at the beginning of the null separated block.
In WinDbg command db <my_address> dumps raw memory along with ASCII conversion. If block is larger than 128 bytes, then add option l to the command. E.g this will print out first 0x200 bytes for local variable pVoid:
db poi pVoid l200
Simply casting to char* should work.
void f(LPVOID s)
{
char* ss = (char*) s; // put breakpoint here or watch the variable
for(char* r = ss; *r != '\0'; r += (strlen(r)+1)) { // iterate the string
printf("%s \n", r);
}
}
again a very late a answer but dpa in windbg can be leveraged to print the list
lpvoid:\>dir /b
lpvoid.cpp
lpvoid:\>type lpvoid.cpp
#include <stdio.h>
#include <windows.h>
int somefunc(LPVOID blah)
{
printf("%s\n",*(PCHAR *)blah);
return 0;
}
int main (void)
{
PCHAR foo[] = { "yay" , "boy" , "dog" , "cat" , "monkey" , "weedinducedweird
o" };
somefunc( foo);
return 0;
}
lpvoid:\>cl /Zi /nologo lpvoid.cpp
lpvoid.cpp
lpvoid:\>dir /b *.exe
lpvoid.exe
lpvoid:\>lpvoid.exe
yay
set a bp on somefunc or if you do not have symbols on address lik bp 401020
use dpa on the argument (blah here) or use dpa #esp+8
lpvoid:\>cdb -c "bp somefunc \"dpa poi(blah) l?6;q\";g;q" lpvoid.exe | grep -A 6
yay
0013ff60 00417c60 "yay"
0013ff64 00417c64 "boy"
0013ff68 00417c68 "dog"
0013ff6c 00417c6c "cat"
0013ff70 00417c70 "monkey"
0013ff74 00417c78 "weedinducedweirdo"
quit:
assuming no symbols here
lpvoid:\>cdb -c "bp 401020 \"dpa (#esp+8) l?6;q\";g;q" lpvoid.exe | grep -A 6 ya
y
0013ff60 00417c60 "yay"
0013ff64 00417c64 "boy"
0013ff68 00417c68 "dog"
0013ff6c 00417c6c "cat"
0013ff70 00417c70 "monkey"
0013ff74 00417c78 "weedinducedweirdo"
quit:
I have the following c program which launches a Gtk Program on ubuntu:
#include <unistd.h>
int main( int argc, const char* argv[] )
{
char *args[2] = { "testarg", 0 };
char *envp[1] = { 0 };
execve("/home/michael/MyGtkApp",args,envp);
}
I get "Gtk-WARNING **: cannot open display: " and my program is not launched.
I have tried setting char *envp[1] = {"DISPLAY:0.0"}; and execute 'xhost +' , I don't see the 'cannot open display' warning, but my program is still not launched.
Does anyone know how to fix my problem?
Thank you.
char *envp[1] = {"DISPLAY:0.0"};
Very wrong. Separate name and value by =, and terminate the list by NULL like args.
char *envp[2] = {"DISPLAY=:0.0", 0};
or better yet, don't hard-code the display, and use Xauthority too.
char *display = 0, *xauthority = 0;
char *envp[3] = {0};
asprintf(&display, "DISPLAY=%s", getenv("DISPLAY"));
asprintf(&xauthority, "XAUTHORITY=%s", getenv("XAUTHORITY"));
envp[0] = display;
envp[1] = xauthority;
I'm left wondering why you give the program such a sparse environment, though – depending on how you're configured and what you're using, Gtk+ may not be entirely happy with DBUS_SESSION_BUS_ADDRESS,GTK2_RC_FILES,GTK_IM_MODULE,HOME,LANG*,LC_*,PATH,XDG_* etc. environment variables gone. Why don't you just use execv or execvp, and just allow the parent's environment to be inherited?
I tried setting the envp to this, and it tries to launch my application.
char *envp[2] = { (char*)"DISPLAY=:0.0", 0 };
But I end up with a Segmentation Fault (my program runs fine when I launch it via command prompt:
(gdb) bt
#0 0x007e5f4e in g_main_context_prepare () from /lib/libglib-2.0.so.0
#1 0x007e6351 in ?? () from /lib/libglib-2.0.so.0
#2 0x007e6b9f in g_main_loop_run () from /lib/libglib-2.0.so.0
#3 0x0041b419 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#4 0x08049191 in main (argc=1, argv=0xbffffed4)
at main.c:471
If you ended up with a segmentation fault in MyGtkApp, your app is buggy and this has nothing to do with the program you posted.
Some suggestions:
I would never use 0 instead of NULL, it is a pain generator on 64 bit platforms: use at least (void *) 0;
no need to specify the array size if you're initializing it;
the first argument is (by convention) always the program name, so:
char *args[] = { "/home/michael/MyGtkApp", "testarg", (void *) 0 };