I'm debugging the linux kernel using kgdb module and gdb.
when trying to set a breakpoint at some address, gdb sets it at another, wrong address.
(gdb) b *0xffffffff81528690
Breakpoint 1 at 0x81528690
Anyone knows why?
I found what is the issue.
By default running gdb without specifying an executable will force 32-bit mode, that why address were truncated.
After running it on the kernel image, which was built for x86_64 architecture i could break on 64bit long addresses.
Related
I am trying to use Clion IDE to debug various NXP ARM M MCUs using J-link.
In case when program is only in RAM it works fine but but in case of flash targets after program load IDE often slows down for a while and then I will get timeout. Some click on pause button in right moment pauses program somewhere and allows me to debug...
My question is there any way how to see interactions of IDE with armgdb client or armgdb and j-link gdb server?
I tried to capture communication with gdb server using wire shark but it seems to be a binary protocol...
Thank you.
I found there is possibility to let gdb echo commands which showed me what is going on.
Unfortunately in case of Clion the only way is to put it into .gdbinit file in the root of project.
set trace-commands on
It showed me warning
warning: A handler for the OS ABI "Windows" is not built into this configuration
of GDB.
Which leads me to comment of this question gdb-multiarch (MINGW64) cannot determine architecture from executable?
Well I am not sure what caused Clion to hang but having .gdbinit with just set osabi none in it solved it.
I'm learning to write bare-metal ARM Cortex-A7 firmware to run on QEMU with semihosting. I know that ARM GCC has a libc implementation called newlib, which supports semihosting for common libc functions. So I'm trying to get newlib to work as well.
After addressing a lot of issues, the code is finally running correctly on QEMU: https://github.com/iNvEr7/qemu-learn/tree/master/semihosting-newlib
(Note: QEMU 5.2.0 seems to have a bug that would crash newlib's semihosting call to HEAPINFO, so to run my code on QEMU, you have to compile QEMU master, and use make run target to run the code with QEMU in a tmux session)
However I'd like to find some answers to some of the problems I encountered when integrating with newlib.
To my understanding, newlib, as a libc implementation, provides a crt0 routine that initialize the application's memory region, including .bss, .data, heap and stack.
However, from my tests, the crt0 that GCC linked with doesn't initialize the .bss and .data region, and would crash the later crt0 routine because of that.
So I had to write my own initialization code for .bss and .data in order for it to run correctly.
So I want to understand if I'm doing it the right way? Did I missing something that would instead enable newlib to initialize these regions for me? Or is it conventional to do the initialization myself?
Note: I'm using arm-none-eabi-gcc stable 9-2019-q4-major
It seems like I'm hitting a bug in newlib itself, and my current code is running fine because of some random luck.
So I updated my toolchain to gcc-arm-none-eabi-10-2020-q4-major and tried to compile the same code. This time it crashes again.
So I attached GDB and stepped through the ctr0 assembly code trying to figure out why.
It turns out that this line of code is loading the label's address to r1, but it should be loading the content in that label's address, i.e. ldr r1, .LC0 instead of adr r1, .LC0 .
The consequence of this typo is that the returned data from the heapinfo semihosting call is overwriting other data after that label, which contains information about the memory regions. It in turns affected the .bss initialization code later in the crt0 routine. With my previous test using an older toolchain it luckily runs without crashes, but with latest toolchain such error is causing fatal crashes.
I also realized that the 5.2.0 QEMU crash may also be caused by this newlib bug, instead of a QEMU problem. Somehow the master QEMU version behaved differently making the crash to dissapear.
I have submitted a patch to newlib. It surprised me that such a fatal mistake can slip through so many years without notice while it can be revealed by a simple hello world program.
Anyway, it seems my question is also answered by my digging. If newlib was working correctly, it should have initialized .bss section. But there's no code in newlib to initialize .data section, and we have to do that manually for bare-metal.
Plot twist: got back from newlib mailing list. It turns out the newlib's implementation is indeed correctly conforming to the ARM spec:
https://developer.arm.com/documentation/100863/0300/Semihosting-operations/SYS-HEAPINFO--0x16-?lang=en
Where "the PARAMETER REGISTER contains the address of a pointer to a four-field data block."
It's instead QEMU made an misinterpretation and wrote to the wrong address. Will file an issue with QEMU instead.
An application binary is loaded into RAM, which got compiled using GCC
Does this binary get virtual address (VA) starting from 0x0 or some other value?
(When i check the application binary, i couldn't see any VA in application)
I read many articles and found an answer, which could address some of my questions.
GCC uses ELF format to create application binary.
If you do "readelf -a app_binary", then it shows the entry point address of the application.
Application compiled using GCC, uses a starting virtual address 0x400000 in 64-bit and 0x804800 in 32-bit systems.
So, if we try access 0x0-0x3fffff, then segmentation fault will be seen. Since that virtual memory is not defined.
Please correct my answer, if it has any mistakes. :-)
I have multiple questions regarding debugging a Raspberry pi 3 from a linux x64 host using gdb-multiarch, as well as writing bare metal programs in general. We are currently facing a problem where our code appears to not be loaded into memory. When we begin debugging in GDB we start at address 0. 3 instructions down we jump into 0x10000. If I modify my linker script to put the Raspberry pi into either address I get the same result, we jump into 0x10000 and our code isn't loaded there. Instead we get this
We noticed also that GDB is using 32 bit register names here when we're supposed to be debugging 64 bit code.
Again a recap of what we're using:
QEMU with versatile-pb machine.
An aarch64 GCC cross-compiler.
GDB-multiarch.
We've tried on two different hosts: Ubuntu 16.04 x64 Host running in virtualbox. Mint x64 running natively.
We also tried the arm-none-eabi toolchain but were running into problems not having our code compiled as 64 bit.
Help is much appreciated! Thanks!
You don't give your command line, but "versatile-pb" is a 32-bit only board type, so trying to run 64-bit code on it is going to misbehave in confusing ways. You need to tell QEMU to emulate a 64-bit capable board that matches what your bare-metal code is expecting to run on.
In QEMU 2.12 there will be a "raspi3" QEMU board which may be helpful for you; you'd need to try building the latest 2.12 release candidate tarball at the moment if you wanted to experiment with that (2.12 release isn't due for another couple of weeks). Otherwise you could use the "virt" board if you made sure your bare metal code was built to be able to run on that board.
I compiled 32-bit kernel on a 64-bit ubuntu and installed it. But when I tried to boot from it , it gave me an error:
Failed to execute /init
Kernel panic - not syncing: No init found
And also the Caps Lock light kept on blinking.
But when I tried to boot from the original 64-bit kernel it booted successfully. Please tell me reason behind this and a solution to this.
You can't do much with just a kernel. As soon as the kernel is done booting, it calls an external process (called init) which begins starting other services and processes from user space, in order to arrive at a functional system. This includes mounting filesystems, configuring some hot-pluggable devices, launching network services, and, of course, providing a login screen.
A 64-bit operating system can run both 64-bit and 32-bit binaries. A 32-bit operating system can only run 32-bit binaries. And it appears that your system (including init) is a 64-bit system. Therefore, your 32-bit kernel will be unable to do anything after booting, since all the necessary system utilities are compiled in 64-bit mode.
I can't think of any reason one would want to "downgrade" to a 32-bit kernel on a 64-bit distribution, even if it were possible.