drgn/libdrgn/orc_info.h
Omar Sandoval 91ede0c6a4 libdrgn: orc_info: handle ORC changes in Linux 6.3 and 6.4
The ORC format changed twice recently:

- Linux kernel commit ffb1b4a41016 ("x86/unwind/orc: Add 'signal' field
  to ORC metadata") (in v6.3).
- Linux kernel commit fb799447ae29 ("x86,objtool: Split
  UNWIND_HINT_EMPTY in two") (in v6.4).

The former went unnoticed because the change was subtle, and the latter
completely broke x86-64 kernel stack traces.

To handle this, let's "upgrade" the format to the latest version when we
load and sort the ORC information. This is more work upfront but avoids
needing to handle the version differences every time we use ORC to
unwind.

Unfortunately, ORC currently doesn't have any sort of versioning, so we
have to break the rule of not checking kernel versions. However, I have
a kernel patch pending merging that should fix this for the future.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-06-22 15:27:39 -07:00

78 lines
1.7 KiB
C

// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
/**
* @file
*
* ORC unwinder support.
*
* See @ref DebugInfo.
*/
#ifndef DRGN_ORC_INFO_H
#define DRGN_ORC_INFO_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "cfi.h"
struct drgn_module;
/**
* @ingroup DebugInfo
*
* @{
*/
/** ORC unwinder data for a @ref drgn_module. */
struct drgn_module_orc_info {
/**
* Base for calculating program counter corresponding to an ORC unwinder
* entry.
*
* This is the address of the `.orc_unwind_ip` ELF section.
*
* @sa drgn_module_orc_info::entries
*/
uint64_t pc_base;
/**
* Offsets for calculating program counter corresponding to an ORC
* unwinder entry.
*
* This is the contents of the `.orc_unwind_ip` ELF section, byte
* swapped to the host's byte order if necessary.
*
* @sa drgn_module_orc_info::entries
*/
int32_t *pc_offsets;
/**
* ORC unwinder entries.
*
* This is the contents of the `.orc_unwind` ELF section, byte swapped
* to the host's byte order and normalized to the latest version of the
* format if necessary.
*
* Entry `i` specifies how to unwind the stack if
* `orc_pc(i) <= PC < orc_pc(i + 1)`, where
* `orc_pc(i) = pc_base + 4 * i + pc_offsets[i]`.
*/
struct drgn_orc_entry *entries;
/** Number of ORC unwinder entries. */
unsigned int num_entries;
/** Version of the ORC format. See @ref orc.h. */
int version;
};
void drgn_module_orc_info_deinit(struct drgn_module *module);
struct drgn_error *
drgn_module_find_orc_cfi(struct drgn_module *module, uint64_t pc,
struct drgn_cfi_row **row_ret, bool *interrupted_ret,
drgn_register_number *ret_addr_regno_ret);
/** @} */
#endif /* DRGN_ORC_INFO_H */