gdb - how to call memset for the array of pointers - c

I debug an example program which defines the array of pointers:
int a = 1, b = 2, c = 3;
int* t[] = {&a, &b, &c};
I would like to set all pointers in the array to NULL during debugging. When I use the following command:
call memset(t, 0x0, sizeof(int*)*3)
I get this output:
$3 = (void *(*)(void *, int, size_t)) 0x7ffff77e7e10 <__memset_avx2_unaligned_erms>
When I print the array pointers are not set to NULL:
(gdb) print t
$4 = {0x7fffffffddc0, 0x7fffffffddc4, 0x7fffffffddc8}
What is wrong ?

I get this output:
You get this output because in your version of GLIBC memset is a GNU indirect function. It doesn't write any memory, it returns an address of the actual implementation (__memset_avx2_unaligned_erms in your case).
You can verify that this is the case:
$ readelf -Ws /lib64/libc.so.6 | grep ' memset'
1233: 00000000000b2df0 241 IFUNC GLOBAL DEFAULT 14 memset##GLIBC_2.2.5
557: 00000000000b2df0 241 FUNC LOCAL DEFAULT 14 memset_ifunc
6000: 00000000000b2df0 241 IFUNC GLOBAL DEFAULT 14 memset
To actually set the memory, you need to call the implementation function, such as __memset_avx2_unaligned_erms.
P.S. To memset an array of 3 pointers, it's easier to simply set each one individually: (gdb) t[0]=0. But I assume the object you actually want to zero out is larger.
For ease of debugging, you may write a trivial local_memset() and call it instead.

Building on Employed Russian's answer, insert () and use
call memset()(t, 0x0, sizeof(int*)*3)
That works because memset() returns the function you actually want to call.

Related

How to break in gdb based on array contents?

I am trying to place a conditional breakpoint on a function that would check the contents of an array. My idea was to use memcmp() in the condition:
typedef struct {
uint8_t arr[4];
} arg_t;
Then in gdb (declaring an array inline):
b func() if memcmp(arg.arr, (uint8_t[]){1, 2, 3, 4}, sizeof(arg.arr)) == 0
However, this does not work:
(gdb) c
Continuing.
Error in testing breakpoint condition:
Too many array elements
I can do it with if arg.arr[0] == 1 && arg.arr[1] == 2 && ... but in my real case access to the array (containing an IPv6 address) is rather convoluted, so it becomes unwieldy rather quickly.
UPDATE: After Mark's comment, I tried the following test program:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(void) {
uint8_t a[] = { 1, 2, 3, 4 };
printf("memcmp returns %d\n", memcmp(a, (uint8_t[4]){1,2,3,4}, sizeof(a)));
return 0;
}
After compiling it, I placed a conditional break on the return using the explicit array size syntax, and it worked but it does not seem to stop as expected:
(gdb) br hello.c:8 if memcmp(a, (uint8_t[4]){1,2,3,4}, sizeof(a)) == 0
Breakpoint 1 at 0x75c: file hello.c, line 8.
(gdb) run
Starting program: /mnt/c/stuff/src/test/hello
memcmp returns 0
[Inferior 1 (process 153) exited normally]
I was trying to evaluate the return value of the function at the break site manually:
(gdb) br hello.c:8
Note: breakpoint 1 also set at pc 0x800075c.
Breakpoint 2 at 0x800075c: file hello.c, line 8.
(gdb) dele 1
(gdb) run
Starting program: /mnt/c/stuff/src/test/hello
memcmp returns 0
Breakpoint 2, main () at hello.c:8
8 return 0;
(gdb) p memcmp(a, (uint8_t[4]){1,2,3,4}, sizeof(a))
$1 = (int (*)(const void *, const void *, size_t)) 0x7fffff18aba0 <__memcmp_avx2_movbe>
I was surprised to see this, I suspect this may be due to memcmp() being a compiler intrinsic to the avx2 instruction, in which case I might need to cast it somehow?
This may not be what you want, but for complex tests, I get the program to help gdb by adding some check routines.
Method 1:
I create a void checkon (void) { if (expr_to_stop_on) badnews(); }
And then have: void badnews { stopme = 1; }
I then instrument the code with calls to checkon
I then tell gdb to do b badnews.
Method 2:
An alternative may be to create: int checkfail(void) { return expr_to_stop_on; }
Then, tell gdb to watch myarray.
This creates a watchpoint (using H/W assist). The watchpoint is like a breakpoint.
You can then do: cond 1 checkfail()
Method 3:
Similar to method 2, but instead of a watchpoint, use a tracepoint [with the same cond command (Actually, you may need to use actions instead).
This essentially single steps the program and allows a set of commands to be executed at every tracepoint.
This can be slow because every line has to do these things.
I think method 2 is probably the best bet.
(Posting my own answer to be able to close this, but credit goes to #mark-plotnick)
It works with the gdb builtin $_memeq instead of using memcmp - suspecting because of the latter not being a real function in my environment but YMMV:
(gdb) br arrbreak.c:8 if $_memeq(a, (uint8_t[4]){1,2,3,4}, sizeof(a))
Breakpoint 2 at 0x800075c: file arrbreak.c, line 8.
(gdb) run
Starting program: /mnt/c/stuff/src/test/arrbreak
memcmp returns 0
Breakpoint 2, main () at arrbreak.c:8
8 return 0;
(gdb) p $_memeq(a, (uint8_t[4]){1,2,3,4}, sizeof(a))
$1 = 1
(gdb) p $_memeq(a, (uint8_t[4]){1,2,3,5}, sizeof(a))
$2 = 0
(gdb)

Segmentation Fault: C-Program migrating from HPUX to Linux

I'm trying to migrate a small c program from hpux to linux. The project compiles fine but crashes at runtime showing me a segmentation fault. I've already tried to see behind the mirror using strace and gdb but still don't understand. The relevant (truncated) parts:
tts_send_2.c
Contains a method
int sequenznummernabgleich(int sockfd, char *snd_id, char *rec_id, int timeout_quit) {
TS_TEL_TAB tel_tab_S01;
int n;
# truncated
}
which is called from within that file like this:
. . .
. . .
switch(sequenznummernabgleich(sockfd,c_snd_id,c_rec_id,c_timeout_quit)) {
/* kritischer Fehler */
case -1:
. . .
. . .
when calling that method I'm presented a segmentation fault (gdb output):
Program received signal SIGSEGV, Segmentation fault.
0x0000000000403226 in sequenznummernabgleich (sockfd=<error reading variable: Cannot access memory at address 0x7fffff62f94c>,
snd_id=<error reading variable: Cannot access memory at address 0x7fffff62f940>, rec_id=<error reading variable: Cannot access memory at address 0x7fffff62f938>,
timeout_quit=<error reading variable: Cannot access memory at address 0x7fffff62f934>) at tts_snd_2.c:498
498 int sequenznummernabgleich(int sockfd, char *snd_id, char *rec_id, int timeout_quit) {
which I just don't understand. When I'm stepping to the line where the method is called using gdb, all the variables are looking fine:
1008 switch(sequenznummernabgleich(sockfd,c_snd_id,c_rec_id,c_timeout_quit)) {
(gdb) p sockfd
$9 = 8
(gdb) p &sockfd
$10 = (int *) 0x611024 <sockfd>
(gdb) p c_snd_id
$11 = "KR", '\000' <repeats 253 times>
(gdb) p &c_snd_id
$12 = (char (*)[256]) 0xfde220 <c_snd_id>
(gdb) p c_rec_id
$13 = "CO", '\000' <repeats 253 times>
(gdb) p &c_rec_id
$14 = (char (*)[256]) 0xfde560 <c_rec_id>
(gdb) p c_timeout_quit
$15 = 20
(gdb) p &c_timeout_quit
$16 = (int *) 0xfde660 <c_timeout_quit>
I've also created an strace output. Here's the last part concerning the code shown above:
strace output
Any ideas ? I've searched the web and of course stackoverflow for hours without finding a really similar case.
Thanks
Kriz
I haven't used an HP/UX in eons but do hazily remember enough for the following suggestions:
Make sure you're initializing variables / struts correctly. Use calloc instead of malloc.
Also don't assume a specific bit pattern order: eg low byte then high byte. Ska endian-ness of the machine. There are usually macros in the compiler that will handle the appropriate ordering for you.
Update 15.10.16
After debugging for even more hours I found the real Problem. On the first line of the Method "sequenznummernabgleich" is a declaration of a struct
TS_TEL_TAB tel_tab_S01;
This is defined as following:
typedef struct {
TS_BOF_REC bof;
TS_REM_REC rem;
TS_EOF_REC eof;
int bof_len;
int rem_len;
int eof_len;
int cnt;
char teltyp[LEN_TELTYP+1];
TS_TEL_ENTRY entries[MAX_TEL];
} TS_TEL_TAB;
and it's embedded struct TS_TEL_ENTRY
typedef struct {
int len;
char tel[MAX_TEL_LEN];
} TS_TEL_ENTRY;
The problem is that the value for MAX_TEL_LEN had been changed from 512 to 1024 and thus the struct almost doubled in size what lead to that the STACK SIZE was not big enough anymore.
SOLUTION
Simply set the stack size from 8Mb to 64Mb. This can be achieved using ulimit command (under linux).
List current stack size: ulimit -s
Set stack size to 64Mb: ulimit -s 65535
Note: Values for stack size are in kB.
For a good short ref on ulimit command have a look # ss64

get size of target array in systemtap

In an answer on a sister site, I'm trying to dump information from the Linux kernel array unix_socket_table#net/unix/af_unix.c which is defined as:
struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
For the moment, I'm hard-coding the size of the array in my stp script:
for (i = 0; i < 512; i++)
How could I avoid that? That information (the size of the array) is stored in the debug information. gdb can tell me it:
$ gdb --batch --ex 'whatis unix_socket_table' "/usr/lib/debug/boot/vmlinux-$(uname -r)"
type = struct hlist_head [512]
$ gdb --batch --ex 'p sizeof(unix_socket_table)/sizeof(*unix_socket_table)' "/usr/lib/debug/boot/vmlinux-$(uname -r)"
$1 = 512
But how would I do it in systemtap? AFAICT, systemtap has no sizeof() operator.
If it were a type, the #cast operator could be used:
size=&#cast(0,"$TYPENAME")[1]
but alas, unix_socket_table isn't a type. So, plan B, use symdata on the variable (in scope of any old kernel function in the vicinity).
probe begin /* kernel.function("*#net/unix/af_unix.c") */ {
println(symdata(& #var("unix_socket_table")))
exit()
}
results here:
unix_socket_table+0x0/0x1000 [kernel]
The second hex number is the symbol size, as computed from the ELF symbol tables at script processing time, equivalent to the 4096 figure here:
% readelf -s /usr/lib/debug/lib/modules/`uname -r`/vmlinux | grep unix_socket_table
71901: ffffffff82023dc0 4096 OBJECT GLOBAL DEFAULT 28 unix_socket_table
You can get the number with for instance:
probe begin {
tokenize(symdata(#var("unix_socket_table#net/unix/af_unix.c")),"/");
printf("%d\n", strtol(tokenize("",""), 16));
exit()
}
Many thanks to #fche for pointing me in the right direction. As he says, systemtap's symdata() function can be used to retrieve symbol information at a given address including the size. So we can write our own sizeof() function that parses it to extract the size as:
function sizeof(address:long) {
tokenize(symdata(address), "/");
return strtol(tokenize("",""),16);
}
If we look at the definition of that symdata() function, we see that it is itself a systemtap function that makes use of the _stp_snprint_addr() C function, itself calling _stp_kallsyms_lookup() to retrieve data. That means we can also define our own sizeof() using stp_kallsyms_lookup() directly:
function sizeof:long (addr:long) %{ /* pure */ /* pragma:symbols */
STAP_RETVALUE = -1;
_stp_kallsyms_lookup(STAP_ARG_addr, (unsigned long*)&(STAP_RETVALUE), NULL, NULL, NULL);
%}
(note that we need -g (guru) here as we're using embedded C).
Now, to get the array size, we need the size of the elements of the arrays. One approach can be to use the address offset between 2 elements of the array. So we could define our array_size() function as:
function array_size(first:long, second:long) {
return sizeof(first) / (second - first);
}
(where sizeof() is one or the other of the functions defined above).
And call it as:
probe begin {
printf("%d\n", array_size(
&#var("unix_socket_table#net/unix/af_unix.c")[0],
&#var("unix_socket_table#net/unix/af_unix.c")[1]));
exit();
}
Which gives us 512 as expected.
For sizeof(), another approach could be to use the C sizeof() operator:
$ sudo stap -ge '
%{ #include <net/af_unix.h> %}
probe begin {
printf("%d\n", %{ sizeof(unix_socket_table)/sizeof(unix_socket_table[0]) %} );
exit();
}'
512
(also needs -g) but then the information is retrieved from the kernel source code (header files), not debug information, so while that would work for kernel arrays that are defined in header files, that approach won't necessary work for all arrays.

pointer return value changes after function call

Code snippets from two C source files:
A.c
Channel *testChannelGet()
{
Channel *ch = channelGet (parser,parserCh);
return ch;
}
B.c
Channel *channelGet(UINT8 parser, UINT16 parserCh)
{
chnl.player = &solPlayer;
return((Channel *)&chnl);
}
I compile both files and create a static and a shared library. Now I call testChannelGet from a sample program. When I link it against the static library, it works perfectly. But if I link it against the shared library, its SEGFAULTing. Debugging tells me that the pointer returned from channelGet is changing the moment it returns. GDB output below.
174 Channel *ch = channelGet (parser,parserCh);
(gdb) s
channelGet (parser=1 '\001', parserCh=1) at B.c:15174
15174 chnl.player = &solPlayer;
(gdb) n
15175 return((Channel *)&chnl);
(gdb) p ((Channel *)&chnl)
$1 = (Channel *) 0x7ffff7fed1a0
(gdb) n
15176 }
(gdb) n
testChannelGet at A.c:175
175 return ch;
(gdb) p ch
$2 = (Channel *) 0xfffffffff7fed1a0
It seems the address value points to a different offset now - 0xfffffffff7fed1a0 vs 0x7ffff7fed1a0 . The last bytes in both addresses are the same.
Any hints? I have tried the -fPIC option to no avail.
Is there a prototype in scope for channelGet() in A.c?
If not, the results you're seeing could be explained as follows:
channelGet() is assumed to return int (due to lack of prototype), so the result is truncated to 0xf7fed1a0
then it is cast to a 64-bit pointer, so gets sign-extended to 0xfffffffff7fed1a0
(You should get complaints about this if you compile with warnings enabled, of course...)
Run your program under valgrind. Find and fix any errors it reports.

How to modify memory contents using GDB?

I know that we can use several commands to access and read memory: for example, print, p, x...
But how can I change the contents of memory at any specific location (while debugging in GDB)?
The easiest is setting a program variable (see GDB: assignment):
(gdb) l
6 {
7 int i;
8 struct file *f, *ftmp;
9
(gdb) set variable i = 10
(gdb) p i
$1 = 10
Or you can just update arbitrary (writable) location by address:
(gdb) set {int}0x83040 = 4
There's more. Read the manual.
As Nikolai has said you can use the gdb 'set' command to change the value of a variable.
You can also use the 'set' command to change memory locations.
eg. Expanding on Nikolai's example:
(gdb) l
6 {
7 int i;
8 struct file *f, *ftmp;
9
(gdb) set variable i = 10
(gdb) p i
$1 = 10
(gdb) p &i
$2 = (int *) 0xbfbb0000
(gdb) set *((int *) 0xbfbb0000) = 20
(gdb) p i
$3 = 20
This should work for any valid pointer, and can be cast to any appropriate data type.
Expanding on the answers provided here.
You can just do set idx = 1 to set a variable, but that syntax is not recommended because the variable name may clash with a set sub-command. As an example set w=1 would not be valid.
This means that you should prefer the syntax: set variable idx = 1 or set var idx = 1.
Last but not least, you can just use your trusty old print command, since it evaluates an expression. The only difference being that he also prints the result of the expression.
(gdb) p idx = 1
$1 = 1
You can read more about gdb here.
Writing memory:
(gdb) set *0x20001234 = 0xABABABAB
Reading memory:
(gdb) x 0x20001234
0x20001234: 0xabababab
One of the most useful things is to change the value of Registers directly.
0x000000000800088e <+67>: lea rdi,[rip+0x118] # 0x80009ad
To change the value of rdi register:
set $rdi = 0x8201010

Resources