[8/8] Don't throw exception in dis_asm_memory_error
Commit Message
Hi,
GDB calls some APIs from opcodes to do disassembly and provide some
call backs. This model makes troubles on C++ exception unwinding,
because GDB is a C++ program, and opcodes is still compiled as C.
As we can see, frame #10 and #12 are C++, while #frame 11 is C,
#10 0x0000000000544228 in memory_error (err=TARGET_XFER_E_IO, memaddr=<optimized out>) at ../../binutils-gdb/gdb/corefile.c:237
#11 0x00000000006b0a54 in print_insn_aarch64 (pc=0, info=0xffffffffeeb0) at ../../binutils-gdb/opcodes/aarch64-dis.c:3185
#12 0x0000000000553590 in gdb_pretty_print_insn (gdbarch=gdbarch@entry=0xbbceb0, uiout=uiout@entry=0xbc73d0, di=di@entry=0xffffffffeeb0,
insn=0xffffffffed40, insn@entry=0xffffffffed90, flags=flags@entry=0,
C++ exception unwinder can't go across frame #11 unless it has
unwind table. However, C program on many architectures doesn't
have it in default. As a result, GDB aborts, which is described
in PR 20939.
This is not the first time we see this kind of problem. We've
had a commit 89525768cd086a0798a504c81fdf7ebcd4c904e1
"Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH".
We can fix the disassembly bug in a similar way, this is the option one.
Since opcodes is built with gdb, we fix this problem in a different
way as we did for the same issue with readline. Instead of throwing
exception in dis_asm_memory_error, we record the failed memory
address, and throw exception when GDB returns from opcodes disassemblers.
gdb:
2017-01-10 Yao Qi <yao.qi@linaro.org>
PR gdb/20939
* disasm.c (gdb_disassembler::dis_asm_memory_error): Don't
call memory_error, save memaddr instead.
(gdb_disassembler::print_insn): If gdbarch_print_insn returns
negative, cal memory_error.
* disasm.h (gdb_disassembler) <m_err_memaddr>: New field.
gdb/testsuite:
2017-01-10 Yao Qi <yao.qi@linaro.org>
* gdb.base/all-architectures.exp.in (do_arch_tests): Test
disassemble on address 0.
---
gdb/disasm.c | 12 ++++++++++--
gdb/disasm.h | 1 +
gdb/testsuite/gdb.base/all-architectures.exp.in | 3 +++
3 files changed, 14 insertions(+), 2 deletions(-)
Comments
On 01/10/2017 12:26 PM, Yao Qi wrote:
> --- a/gdb/testsuite/gdb.base/all-architectures.exp.in
> +++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
> @@ -152,6 +152,9 @@ proc print_floats {} {
>
> proc do_arch_tests {} {
> print_floats
> +
> + gdb_test_internal "disassemble 0x0,+4" \
> + "Cannot access memory at address 0x0"
> }
This will fail if you're testing against a non-MMU target,
where you can read address 0. Check is_address_zero_readable?
Thanks,
Pedro Alves
On Thu, Jan 12, 2017 at 4:40 PM, Pedro Alves <palves@redhat.com> wrote:
> On 01/10/2017 12:26 PM, Yao Qi wrote:
>> --- a/gdb/testsuite/gdb.base/all-architectures.exp.in
>> +++ b/gdb/testsuite/gdb.base/all-architectures.exp.in
>> @@ -152,6 +152,9 @@ proc print_floats {} {
>>
>> proc do_arch_tests {} {
>> print_floats
>> +
>> + gdb_test_internal "disassemble 0x0,+4" \
>> + "Cannot access memory at address 0x0"
>> }
>
> This will fail if you're testing against a non-MMU target,
> where you can read address 0. Check is_address_zero_readable?
>
There is no live inferior created in the test, so GDB can't access any
memory. Probably I need a line of comment,
# GDB can't access any memory because there is no live inferior.
@@ -139,7 +139,10 @@ void
gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
struct disassemble_info *info)
{
- memory_error (TARGET_XFER_E_IO, memaddr);
+ gdb_disassembler *self
+ = static_cast<gdb_disassembler *>(info->application_data);
+
+ self->m_err_memaddr = memaddr;
}
/* Like print_address with slightly different parameters. */
@@ -955,7 +958,8 @@ fprintf_disasm (void *stream, const char *format, ...)
gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
struct ui_file *file,
di_read_memory_ftype func)
- : m_gdbarch (gdbarch)
+ : m_gdbarch (gdbarch),
+ m_err_memaddr (0)
{
init_disassemble_info (&m_di, file, fprintf_disasm);
m_di.flavour = bfd_target_unknown_flavour;
@@ -981,8 +985,12 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
int
gdb_disassembler::print_insn (CORE_ADDR memaddr)
{
+ m_err_memaddr = 0;
+
int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+ if (length < 0)
+ memory_error (TARGET_XFER_E_IO, m_err_memaddr);
return length;
}
@@ -65,6 +65,7 @@ protected:
private:
struct gdbarch *m_gdbarch;
+ CORE_ADDR m_err_memaddr;
static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
unsigned int len,
@@ -152,6 +152,9 @@ proc print_floats {} {
proc do_arch_tests {} {
print_floats
+
+ gdb_test_internal "disassemble 0x0,+4" \
+ "Cannot access memory at address 0x0"
}
# Given we can't change arch, osabi, endianness, etc. atomically, we