Re: [PATCH] Fix call functions command bug in 64-bit programs for AIX

Aditya Kamath1 via Gdb-patches
2022-11-14T17:32:59Z

Hi Ulrich,

>Did you actually verify any of this information?
>I.e. by debugging GDB itself, or by adding debug print
>statements to store_register?

>I'm asking because if the above is all true, then your patch
>to store_register is a complete no-op for this case:

I understand. No problem. Let me make it easier. So, consider a program with a function num2print () which print the number we pass prefixed with a R. For example, if we pass 2, it prints R2, 3 it will print R3. Please find the program at the bottom of this email.

I have added a print statement for what we get in *addr via raw_supply and what we copy in long buf that will go in the ptrace. Also, I print the regno. As a fact register number R3 to R10 are reserved for function parameters.

So, the GDB output for the program below is as follows:_

(gdb) b main

Breakpoint 1 at 0x100007e4: file /home/XYZ/gdb_tests.c, line 22.

(gdb) r

Starting program: /home/XYZ/gdb_tests

BFD: /usr/lib/libc.a(/usr/lib/libc.a(shr_64.o)): wrong auxtype 0xff for storage class 0x2

BFD: /usr/lib/libc.a(/usr/lib/libc.a(shr_64.o)): wrong auxtype 0xff for storage class 0x6b

Breakpoint 1, main (argc=1, argv=0xffffffffffffad0)

at /home/XYZ/gdb_tests:22

22 printf("Hi Bangalore %x\n",num2print(27, 16, 13, 9.9));

(gdb) call num2print

$1 = {int (int, float, int, int)} 0x1000006a0 <num2print>

(gdb) call num2print (2, 3, 4, 5)

val in regno 3 via buf is 0 and *addr is 2

val in regno 4 via buf is 0 and *addr is 1077936128

val in regno 5 via buf is 0 and *addr is 4

val in regno 6 via buf is 0 and *addr is 5

val in regno 1 via buf is -1696 and *addr is 268435455

val in regno 67 via buf is 1152 and *addr is 1

R0

$2 = 0

(gdb) info reg

r0 0x1000004f4 4294968564

r1 0xffffffffffff9e0 1152921504606845408

r2 0x1100002e0 4563403488

r3 0x1 1

r4 0xffffffffffffad0 1152921504606845648

r5 0xffffffffffffae0 1152921504606845664

r6 0x800000000000d032 9223372036854829106

r7 0xfffffffffffffe0 1152921504606846944

r8 0x0 0

r9 0x1 1

r10 0x0 0

r11 0x1030 4144

r12 0xf1000600005901d8 17365886760216232408

r13 0xbadc0ffee0ddf00d 13464654573299691533

Clearly from the GDB output the buffer value getting copied is 0 but *addr is 2.. So

memcpy (&buf, addr, 8);

has not copied the values properly and hence we don't get the desired value.. Kindly note these programs are run-in 64-bit mode only and in 32-bit mode we are good.

Now let's change the case. Let's make one of the parameters in the num2print function as long. The output for the same is as below in 64-bit mode..

(gdb) b main

Breakpoint 1 at 0x100007dc: file /home/XYZ/gdb_tests.c, line 22.

(gdb) r

Starting program: /home/XYZ/gdb_tests

BFD: /usr/lib/libc.a(/usr/lib/libc.a(shr_64.o)): wrong auxtype 0xff for storage class 0x2

BFD: /usr/lib/libc.a(/usr/lib/libc.a(shr_64.o)): wrong auxtype 0xff for storage class 0x6b

Breakpoint 1, main (argc=1, argv=0xffffffffffffad0)

at /home/XYZ/gdb_tests.c:22

22 printf("Hi Bangalore %x\n",num2print(27, 16, 13, 9.9));

(gdb) call num2print

$1 = {int (long, float, int, int)} 0x1000006a0 <num2print>

(gdb) call num2print (2, 3, 4, 5)

val in regno 3 via buf is 2 and *addr is 0

val in regno 4 via buf is 0 and *addr is 1077936128

val in regno 5 via buf is 0 and *addr is 4

val in regno 6 via buf is 0 and *addr is 5

R2

R3.000000

R0

R0

$2 = 2

So, my first parameter is long, and rest are int, except the second.. Check this out..

The first parameter is pointing to 0 in *addr but is copied properly in buf which long and is 2.. This is beause *addr is pointing to higher 32 bits 0 and lower is 2 but somehow memcpy copied properly into the buf.
Our integer friends in regno 5 and 6 [parameter 3 and 4] are taken correctly in *addr but is horribly wrong after memcpy and what goes in buf..

So, the conclusions are long is fine, but int are gone for a toss. Also note our *addr is int..

(gdb) info reg

r0 0x1000004f4 4294968564

r1 0xffffffffffff9e0 1152921504606845408

r2 0x1100002d0 4563403472

r3 0x1 1

r4 0xffffffffffffad0 1152921504606845648

r5 0xffffffffffffae0 1152921504606845664

r6 0x800000000000d032 9223372036854829106

what has gone in registers as a result of all this is garbage values.

I do not want to handle things in integer as then aliging integer becomes a mess in 64 bit mode. Now let's take int addr as long addr64[64] of what I have done in my patch [attached in my previous mail]. I am going to use the same program but will print byte by byte on what comes in my *addr64. Since it is long, I print lower 32 bits first and then higher 32 bits via my patch variable val..

The output is as follows after applying my patch:-

(gdb) b main

Breakpoint 1 at 0x100007dc: file /home/XYZ/gdb_tests.c, line 22.

(gdb) r

Starting program: /home/XYZ/gdb_tests

BFD: /usr/lib/libc.a(/usr/lib/libc.a(shr_64.o)): wrong auxtype 0xff for storage class 0x2

BFD: /usr/lib/libc.a(/usr/lib/libc.a(shr_64.o)): wrong auxtype 0xff for storage class 0x6b

Breakpoint 1, main (argc=1, argv=0xffffffffffffad0)

at /home/XYZ/gdb_tests.c:22

22 printf("Hi Bangalore %x\n",num2print(27, 16, 13, 9.9));

(gdb) call num2print

$1 = {int (long, float, int, int)} 0x1000006a0 <num2print>

(gdb) call num2print (2, 3, 4, 5)

val = 0 in regno 3

val = 2 in regno 3

val = 0 in regno 33

val = 2 in regno 33

val = 1077936128 in regno 4

val = 0 in regno 4

val = 4 in regno 5

val = 0 in regno 5

val = 5 in regno 6

val = 0 in regno 6

R2

R3.000000

R4

R5

$2 = 2

Check the above output. I have printed my val byte by byte with higher bytes first and then lower bytes.

The first parameter was 2. The *addr64 which is a pointer of long type, is pointing to 0 which is higher 32 bits and then if we increment addr64 it is pointing to 2 which lower 32 bits.

The second parameter being float used FPR number 33 and GPR 4..

The third parameter being int is aligned correctly by addr64 of long type pointer. Lower bits pointing first which is 4 and higher bits pointing at addr64++ address. Technically this is how even the first parameter should have been aligned but it is in reverse.

Similarly, to the fourth parameter things align well.

So, this is what I am trying to convince that using int addr[64] isn't allowing memcpy to copy values into the buffer correctly. We rather use a long and align this correctly.

Let me know what you think. If you feel I can solve this in a better way, let me know. I appreciate your patience to read the email and wish to seek your guidance on the same.

Have a nice day ahead.

Thanks and regards,
Aditya.

---------------------------------------------------------------

PROGRAM

#include "stdio.h"

int num2print(int num, float num2, int num3, int num4) {

if (num == 0) {

printf("R0\n");

return 0;

}

if (num == 1) {

printf("R1\n");

return 1;

}

printf("R%d\n",num);

printf("R%f\n",num2);

printf("R%d\n",num3);

printf("R%d\n",num4);

return num;

}

int main(int argc, char** argv)

{

printf("Hi Bangalore %x\n",num2print(27, 16, 13, 9.9));

return 0;

}

----------------------------------------------------------------------

________________________________
From: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Sent: 14 November 2022 21:24
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>; Aditya Kamath1 <Aditya.Kamath1@ibm.com>; simon.marchi@efficios.com <simon.marchi@efficios.com>
Cc: Sangamesh Mallayya <sangamesh.swamy@in.ibm.com>
Subject: Re: [PATCH] Fix call functions command bug in 64-bit programs for AIX

Aditya Kamath1 <Aditya.Kamath1@ibm.com> wrote:

>>- what does ARCH64() return?
>True in 64 bit mode and false in 32 bit mode
>> - what does register_size(...) return for those registers?
>8 in 64 bit mode, 4 in 32 bit mode
> (for GPRs with a 64-bit inferior it should return 8, if
> it doesn't that's probably the root cause of the problem)
>> - what value does ptrace return in your case?
>It returns the data parameter value that is passed as the calls are successful.

Did you actually verify any of this information?
I.e. by debugging GDB itself, or by adding debug print
statements to store_register?

I'm asking because if the above is all true, then your patch
to store_register is a complete no-op for this case:

Before your patch, you have:
int addr[PPC_MAX_REGISTER_SIZE];
[...]
memcpy (addr, &buf, 8);
[...]
regcache->raw_supply (regno, (char *) addr);

After your patch, you have:
long long addr64[PPC_MAX_REGISTER_SIZE];
[...]
memcpy (addr64, &buf, 8);
[...]
regcache->raw_supply (regno, (char *) addr64);

which is exactly the same! Note that both the place
that stores into addr[64] and the place that uses it
cast to (char *), so whether you declare the array
as int or long long does not make any difference
whatsoever.

Therefore, I believe that something else must be
going on that is actually causing the problem
you're seeing. You really need to debug the
actual behavior in store_register to understand
what is in fact going on here.

Bye,
Ulrich