Why do I get the wrong address when referencing a global variable? - c++

I am trying to write a basic OS to better understand OS fundamentals and I am running into a strange problem. After switching to protected mode I jump into my kernel. In my kernel.cpp file I declare the following global variables (where IdtPointer_t and IdtEntry_t are both structs.)
IdtPointer_t idtPtr;
IdtEntry_t idtEntries[256];
This creates the idtPtr and idtEntries variables in the bss section.
Then later in my code when I do the following
IdtEntry_t* entry = &idtEntries[0];
the value returned by &idtEntries[0] isn't the correct address. Using GDB I have done the following
p &idtEntries[0]
(IdtEntry_t *) 0x87a0 <idtEntries>
p entry
(IdtEntry_t *) 0x87e0 <idtEntries+64>
There is a 64 byte difference between the locations of the two variables. Why does referencing the variable return a different address than where the variable is stored in memory?
Also, I am running this using the qemu i386 emulator.

Why does referencing the variable return a different address than where the variable is stored in memory? It does not. I strongly suspect that what GDB is displaying is not what you think it is displaying (although I'm no GDB expert).
Assuming you are developing this on a linux system, I suggest supplementing your observations with the output of 'nm' (or it's cross-compiler relative).
nm -n <elf file>
This will reliably give you a list of all the symbols in your kernel/OS and their addresses (sorted by numerical order). Then compare the addresses of 'idtEntries' and 'entry' against what you got in GDB.

Related

Trace32 CMM script : understanding the Data.Set command

What does the following command mean?
sYmbol.NEW _VectorTable 0x34000000
sYmbol.NEW _ResetVector 0x34000020
sYmbol.NEW _InitialSP 0x34000100
Data.Set EAXI:_VectorTable %Long _InitialSP _ResetVector+1
The command Data.Set writes data values to your target's memory. The syntax of the command is
Data.Set <address>|<address_range> [<access_width>] {value(s)}
The <address> to which the data is written to has the form:
<access_class>:<address_offset>
A full address, just the address offset and the values (you want to write), can also be represented by debug symbols. These symbols are usually the variables, function names and labels defined in your target application and are declared to the debugger, by loading the target application's ELF file.
In this case however the symbols are declared in the debugger manually by the command sYmbol.NEW.
Anyway: By replacing the symbols with their value in the command Data.Set EAXI:_VectorTable %Long _InitialSP _ResetVector+1 we get the command
Data.Set EAXI:0x34000000 %Long 0x34000100 0x34000021
So what does this command actually do?
The access-width specifier %Long indicate that 32-bit values should be written. As a result the address will increment automatically by 4 for each specified data value.
The value 0x34000100 is written to address EAXI:0x34000000
The value 0x34000021 is written to address EAXI:0x34000004
The <access_class> "EAXI" indicates that the debugger should access the address 0x34000000 directly via the AXI bus (Advanced eXtensible Interface). By writing directly to the AXI bus, you bypass your target's CPU core (bypassing any MMU, MPU or caches). The leading 'E' of the access class EAXI indicates that the write operation may also performed while the CPU core is running (or considered to be running (e.g. in Prepare mode)). The description of all possible access classes is specific to the target's core-architecture and thus, you can find the description in the debugger's "Target Architecture Manual".
And what does this exactly mean for your target and the application running on it?
Well, I don't know you chip or SoC (nor do I know your application).
But from the data I see, I guess that you are debugging a chip with an ARM architecture - probably Cortex-M. Your chip's Boot-ROM seems to start at address 0x34000000, while your actual application's start-up code starts at 0x34000020 (maybe with symbol _start).
For Cortex-M cores you have to program at offset 0 of your vector table (in the boot ROM) the initial value of the stack-pointer, while at offset 4 you have to write the initial value of the program counter. In your case the program counter should be initialized with 0x34000021. Why 0x34000021 and not 0x34000020? Because your start-up code is probably encoded in ARM Thumb. (Cortex-M can only execute Thumb code). By setting the least significant bit of the initial value for the program counters to 1, the core knows, that it should start decoding Thumb instructions. (Not setting the least significant bit to 1 on a Cortex-M will cause an exception).

gdb backtrace mechanism

The mechanism that allows gdb to perform backtrace 1 is well explained.
Starting from the current frame, look at the return address
Look for a function whose code section contains that address.
Theoretically, there might be hundreds of thousands of functions to consider.
I was wondering if there are any inherent limitations that prevent gdb
from creating a lookup table with return address -> function name.
What makes you think GDB does a straight search through all functions? This isn't what happens. GDB organises symbols into a couple of different data structures that allow for more efficient mapping between addresses and the enclosing function.
A good place to start might be here: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/blockframe.c;h=d9c28e0a0176a1d91fec1df089fdc4aa382e8672;hb=HEAD#l118
The mechanism that allows gdb to perform backtrace 1 is well explained.
This isn't at all how GDB performs a backtrace.
The address stored in the rip register points to the current instruction, and has nothing to do with return address.
The return address is stored on the stack, or possibly in another register. To find where it is stored (on x86_64, and assuming e.g. Linux/ELF/DWARF file format), GDB looks up unwind descriptor that covers the current value of RIP. The unwind descriptor also tells GDB how to restore other registers to the state they were just before the current function was called.
You can see unwind descriptors with e.g. readelf -wf a.out command.
Once GDB knows how to find return address and restore registers, it can effectively perform an up command, stepping from current (called) frame into previous (caller) frame.
Now this process repeats, until either GDB finds a special unwind descriptor which says "I am the last, don't try to unwind past me", or some error occurs (e.g. restored RIP is 0).
Notably, nowhere in this process does GDB have to consider thousands of functions.

Find out the source file (line number) where a global variable was initialized?

I have pretty large C++ code base of a shared library which is messed up with complicated conditional macro spaghetti so IDE has troubles with that. I examined it with GDB to find the initial value of a global variable as follows:
$ gdb libcomplex.so
(gdb) p some_global_var
$1 = 1024
So I figured out the value the variable was initialized with.
QUESTION: Is it possible to find out which source file (and maybe line number) it was initialized at with GDB?
I tried list some_global_var, but it simply prints nothing:
(gdb) list some_global_var
(gdb)
So on x86 you can put a limited number of hardware watchpoints on that variable being changed:
If you are lucky, on a global you can get away with
watch some_global_var
But the debugger may still decide that is not a fixed address, and do a software watchpoint.
So you need to get the address, and watch exactly that:
p &some_global_var
(int*)0x000123456789ABC
watch (int*)0x000123456789ABC
Now, when you restart, the debugger should pop out when the value is first initialised, perhaps to zero, and/or when it is initialised to the unexpected value. If you are lucky, listing the associated source code will tell you how it came to be initialised. As others have stated you may then need to deduce why that line of code generated that value, which can be a pain with complex macros.
If that doesn't help you, or it stops many times unexpectedly during startup, then you should initially disable the watchpoint, then starti to restart you program and stop as soon as possible. Then p your global, and if it does not yet have the magic value, enable the watchpoint and continue. Hopefully this will skip the irrelevant startup and zoom in on the problem value.
You could use rr (https://rr-project.org/) to record a trace of the program, then you could reverse-execute to find the location. E.g.:
rr replay
(gdb) continue
...
(gdb) watch -l some_global_var
(gdb) reverse-continue

How do I get an accurate stack base address on OS X?

pthread_attr_getstackaddr gives me a value like 0xfffffffffff80000 which doesn't seem like a valid base address.
pthread_get_stackaddr_np, such as documented in this answer and appears to be undocumented and non-portable, gives me a value like 0x00007fff5fc00000 which seems more sensible. However when I place a random breakpoint in my program (with either gdb or lldb) and print the stackpointer I get addresses that are below the one returned above (such as 0x00007fff5fbfe7e0).
All operations are done on pthread_self and I never switch threads. Any ideas?
On Mac OS X (and on the x86 family processors in general) the stack grows down, from higher to lower addresses. So the variables are supposed to be below the stack base address.

Access voilation reading location

I am trying to debugg the project on MSVS 2010.
Implementation - c++; when i am degubbing the source code, i get the following failure reported by MSVS.
Failure reported:
"First chance exception at 0x00000013fb5b9ee in unit.exe: 0xc00000005 access voilation reading location 0x00000000000000c."
the problem lies in obtaining address.
int base = (*(abc::g_runc1.m_paulsenderpin.m_lastchunk_p)).xcpp::cxcppoutput::m_baseaddress;
my project is very big to include the source code,
In short it can be described as:
- paul is a module with sender pin connected to c1.
- xcpp is the interface
this source code and the project is correct and works without failure on ARM compiler, but on MSVS it gives access violation error.
On msdn there are some posts about permission set by assembly, and which avoids to read the addressed location. if so, how to change it... ?
or is there any better option to find the problem...?
Any help is appreciated.
Your code is trying to access location that actually isn't owned by it's process. No data of user applications can be located at addresses so close to zero. As your expressions is too long to simply find where is the member containing zero reference, my tip is m_last chunk_p, and the m_baseaddress seems to be member at offset 12.
There is one simple explanation why does your code work fine when it's compiled by something that works with ARM: ARM uses aligned memory access, so class and structure members are aligned to full blocks, although they don't always use whole space allocated for them. Therefore you use bigger pointer or wrong memset parameters somewhere in your code and your pointer gets overwritten.
Problem may also disappear when you compile it with another version of (possibly another) compiler (or non machine with different processor architecture 32/64), as the size of fundamental types isn't always the same.
You should try to check what pointed is actually zero (or possibly 12) in your expression and try to set a watch on it. Be sure you use sizeof properly everywhere.
The Problem lies with the memory addressing, in ARM debugger 32 bits and MSVS10 48 bits of addressing, because of it the MSB byte is lost and so cannot find the correct memory address...!!!