Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zcmt table generation results in incorrect branch resolution #55

Closed
simonpcook opened this issue Nov 16, 2022 · 12 comments
Closed

zcmt table generation results in incorrect branch resolution #55

simonpcook opened this issue Nov 16, 2022 · 12 comments
Labels
bug Something isn't working

Comments

@simonpcook
Copy link
Contributor

(This bug was originally found by a downstream user of the zcmt changes, but has been replicated with the CORE-V tools)

Generation of the Zcmt table appears to be resulting in branches being incorrectly resolved (amongst other corruptions).

Using embench-1.0 and my CORE-V toolchain build using these tools, if I build embench with:

./build_all.py --clean --arch riscv32 --board ri5cyverilator --cc riscv32-corev-elf-gcc --chip generic --cflags '-save-temps -c -march=rv32im_zcmt -mabi=ilp32 -mcmodel=medany -static -O2' --ldflags '-march=rv32im_zcmt -mabi=ilp32 -mcmodel=medany -static -nostdlib -nostartfiles'  --user-libs '-lm_nano -lc_nano -lgcc' --verbose

and disassemble nsichneu, looking for the first use of cm.jt, I find the following:

   11b9e:       01cf0463                beq     t5,t3,11ba6 <benchmark_body+0x1af0>
   11ba2:       a062                    cm.jt   24
   11ba4:       02872e03                lw      t3,40(a4)
   11ba8:       03472f03                lw      t5,52(a4)

Noting the branch target of that first branch, 11ba6 is in the middle of the first lw instruction quoted, so cannot be where we are expecting to branch to.

@jeremybennett
Copy link
Collaborator

@linsinan1995 @pz9115 Is this something you could look at?

@jeremybennett jeremybennett added the bug Something isn't working label Nov 16, 2022
@pz9115
Copy link
Contributor

pz9115 commented Nov 17, 2022

Yes, We will take a look at this problem.

@linsinan1995
Copy link
Contributor

linsinan1995 commented Nov 17, 2022

Thanks for pointing out this. The issue is introduced in the assembler where gas tries to relax a conditional branch by flipping the condition bit and setting the offset to a two-instruction-length constant (https://github.com/openhwgroup/corev-binutils-gdb/blob/development/gas/config/tc-riscv.c#L5007-L5022).

relax
    bne	t5,t3,.Lfar_away
to
    beq	t5,t3,8 # a constant value
    j .Lfar_away

Since beq is using a constant, it does not be handled by riscv_relax_delete_bytes during relaxation. To solve this issue, we could replace the destination of beq with a new label instead of a constant. I have some ongoing work on zcmt and can submit a fix later this week.

@linsinan1995
Copy link
Contributor

linsinan1995 commented Nov 17, 2022

btw, I thought the branch relaxation is a rare case, but it looks quite frequently when I look at the assembly code. The linker is able to convert beq + j back to bne if the range of bne is valid, which is the more ideal solution for both size and performance(reduce an unconditional jump). However, this part is missing in the ld riscv backend.

linsinan1995 added a commit to linsinan1995/corev-binutils-gdb that referenced this issue Nov 20, 2022
GAS tries to relax a conditional branch by flipping the condition bit
and setting the offset to a two-instruction-length constant.

relax
    bne	t5,t3,.Lfar_away
to
    beq	t5,t3,8 # a constant value
    j .Lfar_away

To solve this issue, we add a local symbol right after the `j`
instruction, and then the linker can help adjust bytes during
linker relaxation.
linsinan1995 added a commit to linsinan1995/corev-binutils-gdb that referenced this issue Nov 20, 2022
GAS tries to relax a conditional branch by flipping the condition bit
and setting the offset to a two-instruction-length constant.

relax
    bne	t5,t3,.Lfar_away
to
    beq	t5,t3,8 # a constant value
    j .Lfar_away

To solve this issue, we add a local symbol right after the `j`
instruction, and then the linker can help adjust bytes during
linker relaxation.
jeremybennett pushed a commit that referenced this issue Nov 25, 2022
GAS tries to relax a conditional branch by flipping the condition bit
and setting the offset to a two-instruction-length constant.

relax
    bne	t5,t3,.Lfar_away
to
    beq	t5,t3,8 # a constant value
    j .Lfar_away

To solve this issue, we add a local symbol right after the `j`
instruction, and then the linker can help adjust bytes during
linker relaxation.
@linsinan1995
Copy link
Contributor

Hi @simonpcook. It is expected to be fixed by #56, can you have a look at it?

@silabs-hfegran
Copy link

I tried the latest build with these fixes included as I am working on some zcmt-tests; and I noticed that certain jump instructions are replaced by cm.jt/cm.jalt without the table being generated. With --zcmt-force-table-jump it appears to work correctly.

@jeremybennett
Copy link
Collaborator

@silabs-hfegran Do you have a specific reproducer, so we can dig into this?

@silabs-hfegran
Copy link

@silabs-hfegran Do you have a specific reproducer, so we can dig into this?

@jeremybennett Sorry for the delayed response, I had some issues reproducing this without pulling in a lot of core-v-verif code, but this hello world example should exhibit the issue I mentioned:

https://github.com/silabs-hfegran/debug/tree/hf_dev_zcmt_issue
Run make all with the corev-openhw-gcc-centos7-20221213 toolchain and you should have a binary file that have tablejump instructions generated without generating the actual table

@silabs-hfegran
Copy link

Additionally, the naming for the tablejump section appears to be changed, as well as its location
(details in this PR: riscv-non-isa/riscv-elf-psabi-doc#349 )
.text.tbljal -> .riscv.jvt

@abukharmeh
Copy link

abukharmeh commented Jan 18, 2023

Yes it would be really really helpful if we can update to reflect the changes in riscv-non-isa/riscv-elf-psabi-doc#349 as that's currently the last item before ratification.

@linsinan1995
Copy link
Contributor

linsinan1995 commented Jan 18, 2023

@silabs-hfegran Do you have a specific reproducer, so we can dig into this?

@jeremybennett Sorry for the delayed response, I had some issues reproducing this without pulling in a lot of core-v-verif code, but this hello world example should exhibit the issue I mentioned:

https://github.com/silabs-hfegran/debug/tree/hf_dev_zcmt_issue Run make all with the corev-openhw-gcc-centos7-20221213 toolchain and you should have a binary file that have tablejump instructions generated without generating the actual table

Thanks for the feedback. I will take a look at it after my vacation. the test cases related to ZCMT are very inadequate, and this is something We need to work on afterwards.

Yes it would be really really helpful if we can update to reflect the changes in riscv-non-isa/riscv-elf-psabi-doc#349 as that's currently the last item before freezing.

The current ZC* version in corev toolchain is 0.70, so I think we can update the implementation to 1.0.0 in the meantime. There are not supposed to be many changes between these two versions. CC @pz9115

@jeremybennett
Copy link
Collaborator

This is fixed.

MaryBennett pushed a commit to MaryBennett/corev-binutils-gdb that referenced this issue Feb 22, 2023
GAS tries to relax a conditional branch by flipping the condition bit
and setting the offset to a two-instruction-length constant.

relax
    bne	t5,t3,.Lfar_away
to
    beq	t5,t3,8 # a constant value
    j .Lfar_away

To solve this issue, we add a local symbol right after the `j`
instruction, and then the linker can help adjust bytes during
linker relaxation.
edward-jones pushed a commit to edward-jones/corev-binutils-gdb that referenced this issue Jul 21, 2023
GAS tries to relax a conditional branch by flipping the condition bit
and setting the offset to a two-instruction-length constant.

relax
    bne	t5,t3,.Lfar_away
to
    beq	t5,t3,8 # a constant value
    j .Lfar_away

To solve this issue, we add a local symbol right after the `j`
instruction, and then the linker can help adjust bytes during
linker relaxation.
edward-jones pushed a commit to edward-jones/corev-binutils-gdb that referenced this issue Jul 31, 2023
zcmt: fix assembly error

  Fixed bug that permitted use of invalid operands for cm.jt

Zcmt: add jvt csr

Add zcmt tests

Update csr tests to account for jvt.

ZC: fix issue openhwgroup#55.

  GAS tries to relax a conditional branch by flipping the condition bit
  and setting the offset to a two-instruction-length constant.

  relax
      bne	t5,t3,.Lfar_away
  to
      beq	t5,t3,8 # a constant value
      j .Lfar_away

To solve this issue, we add a local symbol right after the `j`
instruction, and then the linker can help adjust bytes during
linker relaxation.
edward-jones pushed a commit to edward-jones/corev-binutils-gdb that referenced this issue Jul 31, 2023
zcmt: fix assembly error

  Fixed bug that permitted use of invalid operands for cm.jt

Zcmt: add jvt csr

Add zcmt tests

Update csr tests to account for jvt.

ZC: fix issue openhwgroup#55.

  GAS tries to relax a conditional branch by flipping the condition bit
  and setting the offset to a two-instruction-length constant.

  relax
      bne	t5,t3,.Lfar_away
  to
      beq	t5,t3,8 # a constant value
      j .Lfar_away

  To solve this issue, we add a local symbol right after the `j`
  instruction, and then the linker can help adjust bytes during
  linker relaxation.

ZC: add R_RISCV_RELAX to jal when zcmt is used.

  Table jump instructions will follow the routine of the linker
  relaxation, and thus the jal target should be bound with
  R_RISCV_RELAXi and the old ugly workaround code should be removed.

RISC-V: update match_func of cm.jt/cm.jalt to spec 1.0

  opcodes/ChangeLog:

          * riscv-opc.c (match_cm_jt): Update valid index range for cm.jt.
          (match_cm_jalt): Ditto.
edward-jones pushed a commit to edward-jones/corev-binutils-gdb that referenced this issue Jul 31, 2023
zcmt: fix assembly error

  Fixed bug that permitted use of invalid operands for cm.jt

Zcmt: add jvt csr

Add zcmt tests

Update csr tests to account for jvt.

ZC: fix issue openhwgroup#55.

  GAS tries to relax a conditional branch by flipping the condition bit
  and setting the offset to a two-instruction-length constant.

  relax
      bne	t5,t3,.Lfar_away
  to
      beq	t5,t3,8 # a constant value
      j .Lfar_away

  To solve this issue, we add a local symbol right after the `j`
  instruction, and then the linker can help adjust bytes during
  linker relaxation.

ZC: add R_RISCV_RELAX to jal when zcmt is used.

  Table jump instructions will follow the routine of the linker
  relaxation, and thus the jal target should be bound with
  R_RISCV_RELAXi and the old ugly workaround code should be removed.

RISC-V: update match_func of cm.jt/cm.jalt to spec 1.0

  opcodes/ChangeLog:

          * riscv-opc.c (match_cm_jt): Update valid index range for cm.jt.
          (match_cm_jalt): Ditto.
MaryBennett pushed a commit that referenced this issue Oct 5, 2023
…s_debug_type}

With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp
and target board debug-types, I run into:
...
(gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
==================
WARNING: ThreadSanitizer: data race (pid=9654)
  Write of size 1 at 0x7b200000420d by main thread:
    #0 dwarf2_per_cu_data::get_header() const gdb/dwarf2/read.c:21513 (gdb+0x8d1eee)
    #1 dwarf2_per_cu_data::addr_size() const gdb/dwarf2/read.c:21524 (gdb+0x8d1f4e)
    #2 dwarf2_cu::addr_type() const gdb/dwarf2/cu.c:112 (gdb+0x806327)
    #3 set_die_type gdb/dwarf2/read.c:21932 (gdb+0x8d3870)
    #4 read_base_type gdb/dwarf2/read.c:15448 (gdb+0x8bcacb)
    #5 read_type_die_1 gdb/dwarf2/read.c:19832 (gdb+0x8cc0a5)
    #6 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d)
    #7 lookup_die_type gdb/dwarf2/read.c:19739 (gdb+0x8cbdc7)
    #8 die_type gdb/dwarf2/read.c:19593 (gdb+0x8cb68a)
    #9 read_subroutine_type gdb/dwarf2/read.c:14648 (gdb+0x8b998e)
    #10 read_type_die_1 gdb/dwarf2/read.c:19792 (gdb+0x8cbf2f)
    #11 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d)
    #12 read_func_scope gdb/dwarf2/read.c:10154 (gdb+0x8a4f36)
    #13 process_die gdb/dwarf2/read.c:6667 (gdb+0x898daa)
    #14 read_file_scope gdb/dwarf2/read.c:7682 (gdb+0x89bad8)
    #15 process_die gdb/dwarf2/read.c:6654 (gdb+0x898ced)
    #16 process_full_comp_unit gdb/dwarf2/read.c:6418 (gdb+0x8981de)
    #17 process_queue gdb/dwarf2/read.c:5690 (gdb+0x894433)
    #18 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1770 (gdb+0x88623a)
    #19 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x886300)
    #20 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88b1f1)
    #21 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16917 (gdb+0x8c228e)
    #22 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf39055)
    #23 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66ab7)
    #24 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf6711b)
    #25 operator() gdb/symtab.c:2562 (gdb+0xf67272)
    #26 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf776b1)
    #27 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77708)
    #28 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3fc97)
    #29 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xecae47)
    #30 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
    #31 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf674fb)
    #32 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf67780)
    #33 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf66d6e)
    #34 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf65cb3)
    #35 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf64dab)
    #36 set_initial_language() gdb/symfile.c:1708 (gdb+0xf43074)
    #37 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf41608)
    #38 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf42faf)
    #39 file_command gdb/exec.c:554 (gdb+0x94ff29)
    #40 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
    #41 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
    #42 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff379c)
    #43 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94b5bc)
    #44 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94bc79)
    #45 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x1034efc)
    #46 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94ab61)
    #47 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11be4ef)
    #48 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a960)
    #49 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94aa21)
    #50 stdin_event_handler gdb/ui.c:155 (gdb+0x10751a0)
    #51 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d95bac)
    #52 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d962e4)
    #53 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d946d0)
    #54 start_event_loop gdb/main.c:412 (gdb+0xb5ab52)
    #55 captured_command_loop gdb/main.c:476 (gdb+0xb5ad41)
    #56 captured_main gdb/main.c:1320 (gdb+0xb5cec1)
    #57 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5cf70)
    #58 main gdb/gdb.c:32 (gdb+0x416776)

  Previous read of size 1 at 0x7b200000420d by thread T11:
    #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x831630)
    #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x832897)
    #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x82db8d)
    #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:645 (gdb+0x7f1d49)
    #4 operator() gdb/dwarf2/cooked-index.c:474 (gdb+0x7f0f31)
    #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2a13)
    #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
    #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
    #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
    #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
    #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660)
    #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c)
    #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
    #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf)
    #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f)
    #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5)
    #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
    #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
    #19 pthread_once <null> (libtsan.so.0+0x4457c)
    #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
    #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224)
    #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852)
    #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
    #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dad25a)
    #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dacb7c)
    #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dadc2b)
    #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dad05c)
    #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1db038e)
    #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1db0319)
    #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1db02ce)
    #31 <null> <null> (libstdc++.so.6+0xdcac2)
  ...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:21513 in dwarf2_per_cu_data::get_header() const
...

The race happens when issuing the "file $exec" command.

The race is between:
- a worker thread writing the index cache, and in the process reading
   dwarf2_per_cu_data::is_debug_type, and
- the main thread writing to dwarf2_per_cu_data::m_header_read_in.

The two bitfields dwarf2_per_cu_data::m_header_read_in and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.

Fix this by making dwarf2_per_cu_data::m_header_read_in a packed<bool, 1>.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30392
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants