This is the mail archive of the mailing list for the GDB project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[AVR] Wrong breakpoint addresses from literals

Hi folks,

I'm running into problems trying to set breakpoints on AVR using literal
addresses. These addresses get mapped into the 0x800000 address space
that is used for the data memory (AVR has two separate address spaces,
code is mapped at 0x0). The same holds for the disassemble command.

	(gdb) break *0x100
	Breakpoint 1 at 0x800100

	(gdb) disassemble 0x100,0x102
	Dump of assembler code from 0x800100 to 0x800102:

This subject was previously discussed, without resulting in any solution
being implemented:

The root of the problem seems to be that both disassemble_command and
linespec_expression_to_pc (which is used by the break command) do this
to convert the integer value to an address:

	value_as_address (parse_to_comma_and_eval (&p))

As a workaround, I tried casting to a function pointer, which seems to

	(gdb) disassemble (void (*)())0x100,(void(*)())0x102
	Dump of assembler code from 0x100 to 0x102:

	(gdb) break *(void (*)())0x100
	Breakpoint 6 at 0x100

However, the cast crops the address to a 16-bit word address, so
addresses over the 128KiB boundary get their upper bits truncated:

	(gdb) break *(void (*)())0x30100
	Breakpoint 7 at 0x10100

	(gdb) disassemble (void (*)())0x30100,(void(*)())0x30102
	Dump of assembler code from 0x10100 to 0x10102:

IIUC the result of parsing the cast expression should be value of a
function pointer type.  During evaluation of the cast, the actual
pointer value becomes a word address (0x80) instead of the byte address
specified (0x100). This happens through value_cast -> value_from_longest
-> pack_long -> store_typed_address -> gdbarch_address_to_pointer ->
avr_address_to_pointer. This is visible by casting to long:

	(gdb) p/x (long)(void(*)())0x100
	$6 = 0x80

When this is then passed into value_as_address ->>>
avr_pointer_to_address, it gets converted back to a byte value as

Casting to long also shows the truncation happens during the cast to

	(gdb) p/x (long)(void(*)())0x30100
	$8 = 0x8080

In the previous discussion, Joel Brobecker wrote:

> As I understand it, this is a bit of an unfortunate "expected behavior"
> at the moment.
> One possible way to fix it, I think, it to enhance the linespec module
> (used by the "break" command) and the "disassemble" command to
> automatically
> treat integer values as code addresses. For instance, in the case
> of the "disassemble" command, perhaps it would be sufficient to
> simply cast the value obtained after parsing to a code pointer,
> before extracting the value as an address:
>   pc = value_as_address (parse_to_comma_and_eval (&arg));
> After all, the command knows that the address should be code
> addresses, not data addresses.

I suspect that he meant to say that a cast to a code pointer should be
inserted between the call to parse_to_comma_and_eval and the call to

However, things are a bit tricky here: technically the integer specified
is neither a valid pointer (since AVR uses word-addresses for pointers -
avr_pointer_to_address applies a << 1), but it isn't necessarily a valid
(core) address yet either (It just happens that code is mapped at 0x0,
so core address and the literal address are the same, but there could be
architectures where this does not hold?).

I initially thought that casting to a pointer would just leave the
actual value unchanged and just change the type label, but above I
showed that the cast actually changes the value. This seems inconsistent
with what avr-gcc compiles. In C, `(long)(void (*)())0x100` stays 0x100,
but in gdb it gets converted to 0x80. I guess C assumes that when you
cast an int to a function pointer, you'll make sure that it is a word
address already, whereas in gdb we want to be able to cast byte
addresses to pointers? Anyway, this is a bit of assymetry in the casting
that is interesting, but probably not really relevant to the problem at

In any case, applying the cast Joel suggested won't help us - it will
get the adress space right, but also truncate the pointer to 128KiB,
which isn't what we'd want.

I guess that what we essentially need is a way to tell
avr_integer_to_address wether we need a code or data address, without
involving the code pointer type (which ends up truncating). Adding a
parameter there is easy, it is only used in a few places and archs.
However, this would require passing on this value through
value_as_address which is used in a lot more places. Also, I'm not sure
if an extra "data-or-code" flag would not be too architecture-specific?

Going over the uses of value_as_address, it seems most of them concern
data addresses. Some places that might concern code addresses:
 - eval.c: some OBJC message passing related stuff (not sure)
 - valarith.c: value_equal, value_less in implementing comparison between pointers
   and ints. Assuming that the ints are actual values from the target,
   this comparison is broken anyway...
 - dwarf2loc.c: This is _probably_ code-related, but I can't really
 - print_one_vtable passes a function pointer (though it's probably of
   function pointer type, not int, so the problem doesn't show up there,
   printed vtables are correct on avr).
 - infrun.c: process_event_stop_test and
   insert_exception_resume_breakpoint probably use a code address.
 - elfread.c: Uses value_as_address once or twice to convert a (I
   presume) ifunc integer return value to a function address. I'd expect
   this to cause problems, but I can't confirm since ifuncs aren't
   supported on avr.
 - Probably more, I stopped checking halfway...

So, any other ideas on fixing this (easily)?



Attachment: signature.asc
Description: Digital signature

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]