Reputation: 15
The function inventory take an array of device pointers and call evaluate to find out what the variation is. The inventory function then returns a pointer that has the highest variation.
unsigned short evaluate(Struct Device *thing);
struct Device *inventory(struct Device *things[], int count);
device.h:
struct Device{
char name[20];
short adjustments[8];
short avg;
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "device.h"
/* from device.h, shown here to make it easier to code
struct Device
{
char name[20];
short adjustments[8];
short avg;
};
*/
struct Device things[] =
{
{ "Museum Quality",{ 0, 1, 0, -1, 0, -1, 0, 1}, 1 },
{ "Fell off truck",
{ 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff},
2 },
/* the casts are there since C constants are ints and you can't make
* them shorts and negative numbers look like overflow */
{ "Fell down stairs",
{ 0x7ff0, (unsigned short)0x800f, 0x7ffe, (unsigned short)0x8001,
0x7ffd, (unsigned short)0x8002, 0x7fff, 0x7f00},
3 },
{ "On left side",{ 10, 11, 10, 12, 10, 13, 10, 14}, 4 },
{ "On right side",{ -300, -321, -320, -332, -320, -313, -310, -314}, 5 }
};
/*
struct Device *inventory(struct Device *things[], int count);
*/
int main()
{
struct Device *pointers[1 + sizeof(things) / sizeof(things[0])]
= {NULL};
const int count = sizeof(things) / sizeof(things[0]);
struct Device *worst = NULL;
int i;
for (i=0; i< count; i++)
{
printf("Loading %s into pointers\n", things[i].name);
pointers[i] = &things[i];
}
pointers[i] = NULL;
worst = inventory(pointers, count);
printf("main: The worst is %s\n", worst->name);
return(EXIT_SUCCESS);
}
calibrate.s: # calculates the average and returns the variability
movq %r11, %rax
sarq $3, %rax
movl %eax, 36(%rdi)
subq %rcx, %rdx
movq %rdx, %rax
evaluate.s: # calls calibrate and returns the variability
call calibrate
inventory.s:
rdi is the parameter that holds an array of device pointers, #rbx is a copy of rdi, so it stores array of pointers of devices, #r12 stores count of valid pointers, #r14 stores max variation, #r15 stores the device pointer with the most variation.
movq %rdi, %r15 #r15 stores pointer with most variable
loop:
movq (%rbx,%r12,8), %rdi
call evaluate
cmpq %r14, %rax
jle skipmax
movq %rax, %r14
movq (%rbx, %r12,8), %r15
skipmax:
decq %r12
cmpq $0, %r12
jge loop
movq %r13, %rsi
movq $.LC0, %rdi
movq $0, %rax
call printf
movq %r15, %rdx
movq %r14, %rsi
movq $.LC1, %rdi
movq $0, %rax
call printf
movq %r15, %rax
I run the program, result is: r14 is getting the highest variation correctly, but LC0 prints correct highest variability (r14) but empty name (r15), and the C program that is trying to print the name stored in rax is also empty, the print statement prints:
The maximum variation is 65534 from
instead, it should print:
The maximum variation is 65534 from Fell down stairs
The name is not being printed as you can see from above.
after Further trouble shooting, I found out that r15 has the correct pointer, and its adjustment and avg values are correct, it is just name is empty string, any idea why? maybe since the name is a char array, and it is not being copied correctly?
Thanks!
Upvotes: 1
Views: 460
Reputation: 57922
The bug is movl %eax, 36(%rdi)
at line 38 of calibrate.s
. This is apparently supposed to write to the avg
member of the relevant Device
, but it's a 32-bit store and Device::avg
is a 16-bit short
. So it should be movw %ax, 36(%rdi)
.
Hopefully this will provide some information about what gdb can do and how to use it effectively.
I set a breakpoint at the second printf
in inventory
, at which point I did x/s $rdx
to see what string %rdx
points to:
(gdb) x/s $rdx
0x4040ac <things+76>: ""
Okay, so it is an empty string, but it's at offset 76
within things
, which you could check is the address of things[2].name
. That's not supposed to be an empty string, so let's see what has happened to things
.
(gdb) p things
$4 = {{name = "Museum Quality\000\000\000\000\000", adjustments = {0, 1, 0, -1, 0, -1, 0, 1},
avg = 0}, {name = "\000\000ll off truck\000\000\000\000\000", adjustments = {32767, 32767, 32767,
32767, 32767, 32767, 32767, 32767}, avg = 32767}, {name = "\000\000ll down stairs\000\000\000",
adjustments = {32752, -32753, 32766, -32767, 32765, -32766, 32767, 32512}, avg = 8159}, {
name = "\000\000 left side\000\000\000\000\000\000\000", adjustments = {10, 11, 10, 12, 10, 13,
10, 14}, avg = 11}, {name = "\000\000 right side\000\000\000\000\000\000", adjustments = {-300,
-321, -320, -332, -320, -313, -310, -314}, avg = -317}}
Hmm, the first two bytes of things[2].name
are now null, and for that matter several of the other too. That's not how they were initialized, and the names are not supposed to be modified at all, so how did that happen? A watchpoint will show us which instruction is to blame.
(gdb) watch things[1].name[0]
Hardware watchpoint 3: things[1].name[0]
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
...
Hardware watchpoint 3: things[1].name[0]
Old value = 70 'F'
New value = 0 '\000'
calibrate () at calibrate.s:39
39 subq %rcx, %rdx
Note that this is the instruction after the one that triggered the watchpoint. So we back up to line 38, think for a moment, and there we are.
Upvotes: 3