diff options
| author | Miguel Ojeda <ojeda@kernel.org> | 2026-08-16 15:32:33 +0200 |
|---|---|---|
| committer | Miguel Ojeda <ojeda@kernel.org> | 2026-08-23 21:27:17 +0200 |
| commit | 5febf432df1cfa5b25d99b54c32103fafbdd0eb9 (patch) | |
| tree | 93a1ed1d337bc53adf1e572c2586d347703b286e /drivers/acpi/acpica/dsdebug.c | |
| download | linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.tar.gz linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.zip | |
kbuild: rust: keep Rust objects out of Clang LTO with inline helpersgrafted
Under `CONFIG_LTO_CLANG` + `CONFIG_RUST_INLINE_HELPERS`, one may hit
`objtool` errors such as:
vmlinux.o: error: objtool: _R..._3Gsp4boot+0xd6a:
can't find jump dest instruction at .text._R..._3Gsp4boot+0x1dfd
The reason is that in such builds, the Clang invocation that compiles
the combined Rust plus helpers bitcode emits LLVM bitcode (again) --
the final code generation happens in the linker's LTO step, which the
`-mllvm` trap options passed to Clang do not reach.
This, in turn, means that unreachable traps are missing, and the
impossible paths do not merely fallthrough to the next symbol, but past
the end of their own section, since LTO builds place each function in
its own section.
Thus filter `CC_FLAGS_LTO` out of the Clang invocation, so that it always
emits machine code directly, with the traps in place.
Assisted-by: LLM
Cc: Gary Guo <gary@garyguo.net>
Cc: Boqun Feng <boqun@kernel.org>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Matthew Maurer <mmaurer@google.com>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Fixes: 3a2486cc1da5 ("kbuild: rust: provide an option to inline C helpers into Rust")
Acked-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260816133233.197500-2-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'drivers/acpi/acpica/dsdebug.c')
| -rw-r--r-- | drivers/acpi/acpica/dsdebug.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c new file mode 100644 index 000000000..691c00159 --- /dev/null +++ b/drivers/acpi/acpica/dsdebug.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/****************************************************************************** + * + * Module Name: dsdebug - Parser/Interpreter interface - debugging + * + * Copyright (C) 2000 - 2026, Intel Corp. + * + *****************************************************************************/ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#ifdef ACPI_DISASSEMBLER +#include "acdisasm.h" +#endif +#include "acinterp.h" + +#define _COMPONENT ACPI_DISPATCHER +ACPI_MODULE_NAME("dsdebug") + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* Local prototypes */ +static void +acpi_ds_print_node_pathname(struct acpi_namespace_node *node, + const char *message); + +/******************************************************************************* + * + * FUNCTION: acpi_ds_print_node_pathname + * + * PARAMETERS: node - Object + * message - Prefix message + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +static void +acpi_ds_print_node_pathname(struct acpi_namespace_node *node, + const char *message) +{ + struct acpi_buffer buffer; + acpi_status status; + + ACPI_FUNCTION_TRACE(ds_print_node_pathname); + + if (!node) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]")); + return_VOID; + } + + /* Convert handle to full pathname and print it (with supplied message) */ + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); + if (ACPI_SUCCESS(status)) { + if (message) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ", + message)); + } + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)", + (char *)buffer.pointer, node)); + ACPI_FREE(buffer.pointer); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_dump_method_stack + * + * PARAMETERS: status - Method execution status + * walk_state - Current state of the parse tree walk + * op - Executing parse op + * + * RETURN: None + * + * DESCRIPTION: Called when a method has been aborted because of an error. + * Dumps the method execution stack. + * + ******************************************************************************/ + +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + union acpi_parse_object *next; + struct acpi_thread_state *thread; + struct acpi_walk_state *next_walk_state; + struct acpi_namespace_node *previous_method = NULL; + union acpi_operand_object *method_desc; + + ACPI_FUNCTION_TRACE(ds_dump_method_stack); + + /* Ignore control codes, they are not errors */ + + if (ACPI_CNTL_EXCEPTION(status)) { + return_VOID; + } + + /* We may be executing a deferred opcode */ + + if (walk_state->deferred_node) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Executing subtree for Buffer/Package/Region\n")); + return_VOID; + } + + /* + * If there is no Thread, we are not actually executing a method. + * This can happen when the iASL compiler calls the interpreter + * to perform constant folding. + */ + thread = walk_state->thread; + if (!thread) { + return_VOID; + } + + /* Display exception and method name */ + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "\n**** Exception %s during execution of method ", + acpi_format_exception(status))); + + acpi_ds_print_node_pathname(walk_state->method_node, NULL); + + /* Display stack of executing methods */ + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, + "\n\nMethod Execution Stack:\n")); + next_walk_state = thread->walk_state_list; + + /* Walk list of linked walk states */ + + while (next_walk_state) { + method_desc = next_walk_state->method_desc; + if (method_desc) { + acpi_ex_stop_trace_method((struct acpi_namespace_node *) + method_desc->method.node, + method_desc, walk_state); + } + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + " Method [%4.4s] executing: ", + acpi_ut_get_node_name(next_walk_state-> + method_node))); + + /* First method is the currently executing method */ + + if (next_walk_state == walk_state) { + if (op) { + + /* Display currently executing ASL statement */ + + next = op->common.next; + op->common.next = NULL; + +#ifdef ACPI_DISASSEMBLER + if (walk_state->method_node != + acpi_gbl_root_node) { + + /* More verbose if not module-level code */ + + acpi_os_printf("Failed at "); + acpi_dm_disassemble(next_walk_state, op, + ACPI_UINT32_MAX); + } +#endif + op->common.next = next; + } + } else { + /* + * This method has called another method + * NOTE: the method call parse subtree is already deleted at + * this point, so we cannot disassemble the method invocation. + */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, + "Call to method ")); + acpi_ds_print_node_pathname(previous_method, NULL); + } + + previous_method = next_walk_state->method_node; + next_walk_state = next_walk_state->next; + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n")); + } + + return_VOID; +} + +#else +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + return; +} + +#endif |
