2014-06-04 15:47:15 +00:00
|
|
|
//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2014-06-04 15:47:15 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2014-06-07 19:23:07 +00:00
|
|
|
// Windows on ARM uses a series of serialised data structures (RuntimeFunction)
|
|
|
|
// to create a table of information for unwinding. In order to conserve space,
|
|
|
|
// there are two different ways that this data is represented.
|
|
|
|
//
|
|
|
|
// For functions with canonical forms for the prologue and epilogue, the data
|
|
|
|
// can be stored in a "packed" form. In this case, the data is packed into the
|
|
|
|
// RuntimeFunction's remaining 30-bits and can fully describe the entire frame.
|
|
|
|
//
|
|
|
|
// +---------------------------------------+
|
|
|
|
// | Function Entry Address |
|
|
|
|
// +---------------------------------------+
|
|
|
|
// | Packed Form Data |
|
|
|
|
// +---------------------------------------+
|
|
|
|
//
|
|
|
|
// This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is
|
|
|
|
// associated with such a frame as they can be derived from the provided data.
|
|
|
|
// The decoder does not synthesize this data as it is unnecessary for the
|
|
|
|
// purposes of validation, with the synthesis being required only by a proper
|
|
|
|
// unwinder.
|
|
|
|
//
|
|
|
|
// For functions that are large or do not match canonical forms, the data is
|
|
|
|
// split up into two portions, with the actual data residing in the "exception
|
|
|
|
// data" table (.xdata) with a reference to the entry from the "procedure data"
|
|
|
|
// (.pdata) entry.
|
|
|
|
//
|
|
|
|
// The exception data contains information about the frame setup, all of the
|
2018-03-29 21:59:04 +00:00
|
|
|
// epilogue scopes (for functions for which there are multiple exit points) and
|
2014-06-07 19:23:07 +00:00
|
|
|
// the associated exception handler. Additionally, the entry contains byte-code
|
|
|
|
// describing how to unwind the function (c.f. Decoder::decodeOpcodes).
|
|
|
|
//
|
|
|
|
// +---------------------------------------+
|
|
|
|
// | Function Entry Address |
|
|
|
|
// +---------------------------------------+
|
|
|
|
// | Exception Data Entry Address |
|
|
|
|
// +---------------------------------------+
|
|
|
|
//
|
|
|
|
// This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must
|
|
|
|
// first resolve the exception data entry address. This structure
|
|
|
|
// (ExceptionDataRecord) has a variable sized header
|
|
|
|
// (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as
|
|
|
|
// the packed form. However, because this information is insufficient to
|
|
|
|
// synthesize the unwinding, there are associated unwinding bytecode which make
|
|
|
|
// up the bulk of the Decoder.
|
|
|
|
//
|
|
|
|
// The decoder itself is table-driven, using the first byte to determine the
|
|
|
|
// opcode and dispatching to the associated printing routine. The bytecode
|
|
|
|
// itself is a variable length instruction encoding that can fully describe the
|
|
|
|
// state of the stack and the necessary operations for unwinding to the
|
|
|
|
// beginning of the frame.
|
|
|
|
//
|
|
|
|
// The byte-code maintains a 1-1 instruction mapping, indicating both the width
|
|
|
|
// of the instruction (Thumb2 instructions are variable length, 16 or 32 bits
|
|
|
|
// wide) allowing the program to unwind from any point in the prologue, body, or
|
|
|
|
// epilogue of the function.
|
|
|
|
|
2014-06-04 15:47:15 +00:00
|
|
|
#include "ARMWinEHPrinter.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2015-01-14 11:23:27 +00:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2014-06-04 15:47:15 +00:00
|
|
|
#include "llvm/Support/ARMWinEH.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
|
|
|
using namespace llvm::support;
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) {
|
|
|
|
switch (RT) {
|
|
|
|
case ARM::WinEH::ReturnType::RT_POP:
|
|
|
|
OS << "pop {pc}";
|
|
|
|
break;
|
|
|
|
case ARM::WinEH::ReturnType::RT_B:
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
OS << "bx <reg>";
|
2014-06-04 15:47:15 +00:00
|
|
|
break;
|
|
|
|
case ARM::WinEH::ReturnType::RT_BW:
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
OS << "b.w <target>";
|
2014-06-04 15:47:15 +00:00
|
|
|
break;
|
|
|
|
case ARM::WinEH::ReturnType::RT_NoEpilogue:
|
|
|
|
OS << "(no epilogue)";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string formatSymbol(StringRef Name, uint64_t Address,
|
|
|
|
uint64_t Offset = 0) {
|
2014-06-26 22:52:05 +00:00
|
|
|
std::string Buffer;
|
|
|
|
raw_string_ostream OS(Buffer);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
if (!Name.empty())
|
|
|
|
OS << Name << " ";
|
|
|
|
|
|
|
|
if (Offset)
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
OS << format("+0x%" PRIX64 " (0x%" PRIX64 ")", Offset, Address);
|
2014-06-04 15:47:15 +00:00
|
|
|
else if (!Name.empty())
|
|
|
|
OS << format("(0x%" PRIX64 ")", Address);
|
|
|
|
else
|
|
|
|
OS << format("0x%" PRIX64, Address);
|
|
|
|
|
2024-09-13 06:22:59 -04:00
|
|
|
return Buffer;
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace ARM {
|
|
|
|
namespace WinEH {
|
|
|
|
const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction);
|
|
|
|
|
2014-06-07 19:23:07 +00:00
|
|
|
// TODO name the uops more appropriately
|
2014-06-04 15:47:15 +00:00
|
|
|
const Decoder::RingEntry Decoder::Ring[] = {
|
2018-10-24 00:03:34 +00:00
|
|
|
{ 0x80, 0x00, 1, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit)
|
|
|
|
{ 0xc0, 0x80, 2, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit)
|
|
|
|
{ 0xf0, 0xc0, 1, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit)
|
|
|
|
{ 0xf8, 0xd0, 1, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit)
|
|
|
|
{ 0xf8, 0xd8, 1, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit)
|
|
|
|
{ 0xf8, 0xe0, 1, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit)
|
|
|
|
{ 0xfc, 0xe8, 2, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit)
|
|
|
|
{ 0xfe, 0xec, 2, &Decoder::opcode_1110110L }, // UOP_POP (16-bit)
|
|
|
|
{ 0xff, 0xee, 2, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit)
|
2014-06-07 19:23:07 +00:00
|
|
|
// UOP_PUSH_MACHINE_FRAME
|
|
|
|
// UOP_PUSH_CONTEXT
|
|
|
|
// UOP_PUSH_TRAP_FRAME
|
|
|
|
// UOP_REDZONE_RESTORE_LR
|
2018-10-24 00:03:34 +00:00
|
|
|
{ 0xff, 0xef, 2, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit)
|
|
|
|
{ 0xff, 0xf5, 2, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit)
|
|
|
|
{ 0xff, 0xf6, 2, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit)
|
|
|
|
{ 0xff, 0xf7, 3, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit)
|
|
|
|
{ 0xff, 0xf8, 4, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit)
|
|
|
|
{ 0xff, 0xf9, 3, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit)
|
|
|
|
{ 0xff, 0xfa, 4, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit)
|
|
|
|
{ 0xff, 0xfb, 1, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit)
|
|
|
|
{ 0xff, 0xfc, 1, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit)
|
|
|
|
{ 0xff, 0xfd, 1, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END
|
|
|
|
{ 0xff, 0xfe, 1, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END
|
|
|
|
{ 0xff, 0xff, 1, &Decoder::opcode_11111111 }, // UOP_END
|
|
|
|
};
|
|
|
|
|
|
|
|
// Unwind opcodes for ARM64.
|
|
|
|
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
|
|
|
const Decoder::RingEntry Decoder::Ring64[] = {
|
2022-10-04 18:55:01 -07:00
|
|
|
{0xe0, 0x00, 1, &Decoder::opcode_alloc_s},
|
|
|
|
{0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x},
|
|
|
|
{0xc0, 0x40, 1, &Decoder::opcode_save_fplr},
|
|
|
|
{0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x},
|
|
|
|
{0xf8, 0xc0, 2, &Decoder::opcode_alloc_m},
|
|
|
|
{0xfc, 0xc8, 2, &Decoder::opcode_save_regp},
|
|
|
|
{0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x},
|
|
|
|
{0xfc, 0xd0, 2, &Decoder::opcode_save_reg},
|
|
|
|
{0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x},
|
|
|
|
{0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair},
|
|
|
|
{0xfe, 0xd8, 2, &Decoder::opcode_save_fregp},
|
|
|
|
{0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x},
|
|
|
|
{0xfe, 0xdc, 2, &Decoder::opcode_save_freg},
|
|
|
|
{0xff, 0xde, 2, &Decoder::opcode_save_freg_x},
|
|
|
|
{0xff, 0xe0, 4, &Decoder::opcode_alloc_l},
|
|
|
|
{0xff, 0xe1, 1, &Decoder::opcode_setfp},
|
|
|
|
{0xff, 0xe2, 2, &Decoder::opcode_addfp},
|
|
|
|
{0xff, 0xe3, 1, &Decoder::opcode_nop},
|
|
|
|
{0xff, 0xe4, 1, &Decoder::opcode_end},
|
|
|
|
{0xff, 0xe5, 1, &Decoder::opcode_end_c},
|
|
|
|
{0xff, 0xe6, 1, &Decoder::opcode_save_next},
|
|
|
|
{0xff, 0xe7, 3, &Decoder::opcode_save_any_reg},
|
|
|
|
{0xff, 0xe8, 1, &Decoder::opcode_trap_frame},
|
|
|
|
{0xff, 0xe9, 1, &Decoder::opcode_machine_frame},
|
|
|
|
{0xff, 0xea, 1, &Decoder::opcode_context},
|
2023-11-16 03:19:34 -08:00
|
|
|
{0xff, 0xeb, 1, &Decoder::opcode_ec_context},
|
2022-10-04 18:55:01 -07:00
|
|
|
{0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call},
|
2022-10-12 14:27:22 +03:00
|
|
|
{0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr},
|
2014-06-04 15:47:15 +00:00
|
|
|
};
|
|
|
|
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First,
|
|
|
|
unsigned Last, char Letter) {
|
|
|
|
if (First == Last)
|
|
|
|
OS << LS << Letter << First;
|
|
|
|
else
|
|
|
|
OS << LS << Letter << First << "-" << Letter << Last;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printRange(raw_ostream &OS, uint32_t Mask, ListSeparator &LS,
|
|
|
|
unsigned Start, unsigned End, char Letter) {
|
|
|
|
int First = -1;
|
|
|
|
for (unsigned RI = Start; RI <= End; ++RI) {
|
|
|
|
if (Mask & (1 << RI)) {
|
|
|
|
if (First < 0)
|
|
|
|
First = RI;
|
|
|
|
} else {
|
|
|
|
if (First >= 0) {
|
|
|
|
printRange(OS, LS, First, RI - 1, Letter);
|
|
|
|
First = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (First >= 0)
|
|
|
|
printRange(OS, LS, First, End, Letter);
|
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
|
2021-11-22 14:13:01 +02:00
|
|
|
void Decoder::printGPRMask(uint16_t GPRMask) {
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '{';
|
2021-03-01 23:40:31 -08:00
|
|
|
ListSeparator LS;
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
printRange(OS, GPRMask, LS, 0, 12, 'r');
|
|
|
|
if (GPRMask & (1 << 14))
|
|
|
|
OS << LS << "lr";
|
|
|
|
if (GPRMask & (1 << 15))
|
|
|
|
OS << LS << "pc";
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '}';
|
|
|
|
}
|
|
|
|
|
2021-11-22 14:13:01 +02:00
|
|
|
void Decoder::printVFPMask(uint32_t VFPMask) {
|
|
|
|
OS << '{';
|
|
|
|
ListSeparator LS;
|
|
|
|
printRange(OS, VFPMask, LS, 0, 31, 'd');
|
|
|
|
OS << '}';
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:47:15 +00:00
|
|
|
ErrorOr<object::SectionRef>
|
|
|
|
Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) {
|
|
|
|
for (const auto &Section : COFF.sections()) {
|
2014-10-08 15:28:58 +00:00
|
|
|
uint64_t Address = Section.getAddress();
|
|
|
|
uint64_t Size = Section.getSize();
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
if (VA >= Address && (VA - Address) <= Size)
|
|
|
|
return Section;
|
|
|
|
}
|
2020-08-28 12:18:19 +03:00
|
|
|
return inconvertibleErrorCode();
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF,
|
|
|
|
uint64_t VA, bool FunctionOnly) {
|
|
|
|
for (const auto &Symbol : COFF.symbols()) {
|
2016-05-02 20:28:12 +00:00
|
|
|
Expected<SymbolRef::Type> Type = Symbol.getType();
|
|
|
|
if (!Type)
|
|
|
|
return errorToErrorCode(Type.takeError());
|
2016-03-23 20:27:00 +00:00
|
|
|
if (FunctionOnly && *Type != SymbolRef::ST_Function)
|
2015-06-26 12:18:49 +00:00
|
|
|
continue;
|
2014-06-04 15:47:15 +00:00
|
|
|
|
2016-06-24 18:24:42 +00:00
|
|
|
Expected<uint64_t> Address = Symbol.getAddress();
|
|
|
|
if (!Address)
|
|
|
|
return errorToErrorCode(Address.takeError());
|
2015-07-03 18:19:00 +00:00
|
|
|
if (*Address == VA)
|
2014-06-04 15:47:15 +00:00
|
|
|
return Symbol;
|
|
|
|
}
|
2020-08-28 12:18:19 +03:00
|
|
|
return inconvertibleErrorCode();
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &,
|
|
|
|
const SectionRef &Section,
|
|
|
|
uint64_t Offset) {
|
|
|
|
for (const auto &Relocation : Section.relocations()) {
|
2015-06-29 23:29:12 +00:00
|
|
|
uint64_t RelocationOffset = Relocation.getOffset();
|
2014-06-04 15:47:15 +00:00
|
|
|
if (RelocationOffset == Offset)
|
|
|
|
return *Relocation.getSymbol();
|
|
|
|
}
|
2020-08-28 12:18:19 +03:00
|
|
|
return inconvertibleErrorCode();
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
2021-09-06 15:30:37 +03:00
|
|
|
SymbolRef Decoder::getPreferredSymbol(const COFFObjectFile &COFF, SymbolRef Sym,
|
|
|
|
uint64_t &SymbolOffset) {
|
2021-04-12 14:13:32 +03:00
|
|
|
// The symbol resolved by getRelocatedSymbol can be any internal
|
|
|
|
// nondescriptive symbol; try to resolve a more descriptive one.
|
|
|
|
COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Sym);
|
2021-09-06 15:30:37 +03:00
|
|
|
if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL &&
|
|
|
|
CoffSym.getSectionDefinition() == nullptr)
|
2021-04-12 14:13:32 +03:00
|
|
|
return Sym;
|
|
|
|
for (const auto &S : COFF.symbols()) {
|
|
|
|
COFFSymbolRef CS = COFF.getCOFFSymbol(S);
|
|
|
|
if (CS.getSectionNumber() == CoffSym.getSectionNumber() &&
|
2021-09-06 15:30:37 +03:00
|
|
|
CS.getValue() <= CoffSym.getValue() + SymbolOffset &&
|
|
|
|
CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL &&
|
|
|
|
CS.getSectionDefinition() == nullptr) {
|
|
|
|
uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue();
|
|
|
|
if (Offset <= SymbolOffset) {
|
|
|
|
SymbolOffset = Offset;
|
2021-04-12 14:13:32 +03:00
|
|
|
Sym = S;
|
|
|
|
CoffSym = CS;
|
2021-09-06 15:30:37 +03:00
|
|
|
if (CS.isExternal() && SymbolOffset == 0)
|
|
|
|
return Sym;
|
2021-04-12 14:13:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Sym;
|
|
|
|
}
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
ErrorOr<SymbolRef> Decoder::getSymbolForLocation(
|
|
|
|
const COFFObjectFile &COFF, const SectionRef &Section,
|
|
|
|
uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress,
|
|
|
|
uint64_t &SymbolOffset, bool FunctionOnly) {
|
|
|
|
// Try to locate a relocation that points at the offset in the section
|
|
|
|
ErrorOr<SymbolRef> SymOrErr =
|
|
|
|
getRelocatedSymbol(COFF, Section, OffsetInSection);
|
|
|
|
if (SymOrErr) {
|
|
|
|
// We found a relocation symbol; the immediate offset needs to be added
|
|
|
|
// to the symbol address.
|
|
|
|
SymbolOffset = ImmediateOffset;
|
|
|
|
|
|
|
|
Expected<uint64_t> AddressOrErr = SymOrErr->getAddress();
|
|
|
|
if (!AddressOrErr) {
|
|
|
|
std::string Buf;
|
|
|
|
llvm::raw_string_ostream OS(Buf);
|
|
|
|
logAllUnhandledErrors(AddressOrErr.takeError(), OS);
|
2024-09-13 06:22:59 -04:00
|
|
|
report_fatal_error(Twine(Buf));
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
}
|
|
|
|
// We apply SymbolOffset here directly. We return it separately to allow
|
|
|
|
// the caller to print it as an offset on the symbol name.
|
|
|
|
SymbolAddress = *AddressOrErr + SymbolOffset;
|
2021-09-06 15:30:37 +03:00
|
|
|
|
|
|
|
if (FunctionOnly) // Resolve label/section symbols into function names.
|
|
|
|
SymOrErr = getPreferredSymbol(COFF, *SymOrErr, SymbolOffset);
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
} else {
|
|
|
|
// No matching relocation found; operating on a linked image. Try to
|
|
|
|
// find a descriptive symbol if possible. The immediate offset contains
|
|
|
|
// the image relative address, and we shouldn't add any offset to the
|
|
|
|
// symbol.
|
|
|
|
SymbolAddress = COFF.getImageBase() + ImmediateOffset;
|
|
|
|
SymbolOffset = 0;
|
|
|
|
SymOrErr = getSymbol(COFF, SymbolAddress, FunctionOnly);
|
|
|
|
}
|
|
|
|
return SymOrErr;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint8_t Imm = OC[Offset] & 0x7f;
|
|
|
|
SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n",
|
|
|
|
OC[Offset],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"),
|
|
|
|
Imm);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
unsigned Link = (OC[Offset] & 0x20) >> 5;
|
|
|
|
uint16_t RegisterMask = (Link << (Prologue ? 14 : 15))
|
|
|
|
| ((OC[Offset + 0] & 0x1f) << 8)
|
|
|
|
| ((OC[Offset + 1] & 0xff) << 0);
|
|
|
|
assert((~RegisterMask & (1 << 13)) && "sp must not be set");
|
|
|
|
assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set");
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; %s.w ",
|
|
|
|
OC[Offset + 0], OC[Offset + 1],
|
|
|
|
Prologue ? "push" : "pop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printGPRMask(RegisterMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format("0x%02x ; mov r%u, sp\n",
|
|
|
|
OC[Offset], OC[Offset] & 0xf);
|
|
|
|
else
|
|
|
|
SW.startLine() << format("0x%02x ; mov sp, r%u\n",
|
|
|
|
OC[Offset], OC[Offset] & 0xf);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
unsigned Link = (OC[Offset] & 0x4) >> 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Count = (OC[Offset] & 0x3);
|
|
|
|
|
|
|
|
uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
|
|
|
|
| (((1 << (Count + 1)) - 1) << 4);
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x ; %s ", OC[Offset],
|
|
|
|
Prologue ? "push" : "pop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printGPRMask(GPRMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
unsigned Link = (OC[Offset] & 0x4) >> 2;
|
|
|
|
unsigned Count = (OC[Offset] & 0x3) + 4;
|
|
|
|
|
|
|
|
uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
|
|
|
|
| (((1 << (Count + 1)) - 1) << 4);
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x ; %s.w ", OC[Offset],
|
|
|
|
Prologue ? "push" : "pop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printGPRMask(GPRMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
unsigned High = (OC[Offset] & 0x7);
|
|
|
|
uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8);
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x ; %s ", OC[Offset],
|
|
|
|
Prologue ? "vpush" : "vpop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printVFPMask(VFPMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0);
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"),
|
|
|
|
Imm);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
uint16_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15))
|
|
|
|
| ((OC[Offset + 1] & 0xff) << 0);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],
|
|
|
|
OC[Offset + 1], Prologue ? "push" : "pop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printGPRMask(GPRMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
assert(!Prologue && "may not be used in prologue");
|
|
|
|
|
|
|
|
if (OC[Offset + 1] & 0xf0)
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; reserved\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1]);
|
|
|
|
else
|
|
|
|
SW.startLine()
|
|
|
|
<< format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
if (OC[Offset + 1] & 0xf0)
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; reserved\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1]);
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
else if (Prologue)
|
|
|
|
SW.startLine()
|
|
|
|
<< format("0x%02x 0x%02x ; str.w lr, [sp, #-%u]!\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);
|
2014-06-04 15:47:15 +00:00
|
|
|
else
|
|
|
|
SW.startLine()
|
|
|
|
<< format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
|
|
|
|
unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << Start;
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],
|
|
|
|
OC[Offset + 1], Prologue ? "vpush" : "vpop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printVFPMask(VFPMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
|
|
|
|
unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << (16 + Start);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],
|
|
|
|
OC[Offset + 1], Prologue ? "vpush" : "vpop");
|
2021-11-22 14:13:01 +02:00
|
|
|
printVFPMask(VFPMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
OS << '\n';
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 2;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"),
|
|
|
|
Imm);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 3;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Imm = (OC[Offset + 1] << 16)
|
|
|
|
| (OC[Offset + 2] << 8)
|
|
|
|
| (OC[Offset + 3] << 0);
|
|
|
|
|
|
|
|
SW.startLine()
|
|
|
|
<< format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 4;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
|
|
|
|
|
|
|
|
SW.startLine()
|
|
|
|
<< format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 3;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Imm = (OC[Offset + 1] << 16)
|
|
|
|
| (OC[Offset + 2] << 8)
|
|
|
|
| (OC[Offset + 3] << 0);
|
|
|
|
|
|
|
|
SW.startLine()
|
|
|
|
<< format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",
|
|
|
|
OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
|
|
|
|
|
2016-02-18 22:09:30 +00:00
|
|
|
Offset += 4;
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; nop\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
SW.startLine() << format("0x%02x ; bx <reg>\n", OC[Offset]);
|
2014-06-04 15:47:15 +00:00
|
|
|
++Offset;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
SW.startLine() << format("0x%02x ; b.w <target>\n", OC[Offset]);
|
2014-06-04 15:47:15 +00:00
|
|
|
++Offset;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
++Offset;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-10-24 00:03:34 +00:00
|
|
|
// ARM64 unwind codes start here.
|
|
|
|
bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t NumBytes = (OC[Offset] & 0x1F) << 4;
|
|
|
|
SW.startLine() << format("0x%02x ; %s sp, #%u\n", OC[Offset],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"),
|
|
|
|
NumBytes);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Off = (OC[Offset] & 0x1F) << 3;
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off);
|
|
|
|
else
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Off = (OC[Offset] & 0x3F) << 3;
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x ; %s x29, x30, [sp, #%u]\n", OC[Offset],
|
|
|
|
static_cast<const char *>(Prologue ? "stp" : "ldp"), Off);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3;
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off);
|
|
|
|
else
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t NumBytes = ((OC[Offset] & 0x07) << 8);
|
|
|
|
NumBytes |= (OC[Offset + 1] & 0xFF);
|
|
|
|
NumBytes <<= 4;
|
|
|
|
SW.startLine() << format("0x%02x%02x ; %s sp, #%u\n",
|
|
|
|
OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"),
|
|
|
|
NumBytes);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = ((OC[Offset] & 0x03) << 8);
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg += 19;
|
|
|
|
uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; %s x%u, x%u, [sp, #%u]\n",
|
|
|
|
OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = ((OC[Offset] & 0x03) << 8);
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg += 19;
|
|
|
|
uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; stp x%u, x%u, [sp, #-%u]!\n",
|
|
|
|
OC[Offset], OC[Offset + 1], Reg,
|
|
|
|
Reg + 1, Off);
|
|
|
|
else
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; ldp x%u, x%u, [sp], #%u\n",
|
|
|
|
OC[Offset], OC[Offset + 1], Reg,
|
|
|
|
Reg + 1, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = (OC[Offset] & 0x03) << 8;
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg += 19;
|
|
|
|
uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
|
|
|
|
SW.startLine() << format("0x%02x%02x ; %s x%u, [sp, #%u]\n",
|
|
|
|
OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "str" : "ldr"),
|
|
|
|
Reg, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = (OC[Offset] & 0x01) << 8;
|
|
|
|
Reg |= (OC[Offset + 1] & 0xE0);
|
|
|
|
Reg >>= 5;
|
|
|
|
Reg += 19;
|
|
|
|
uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;
|
|
|
|
if (Prologue)
|
2020-08-24 12:29:56 +03:00
|
|
|
SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #-%u]!\n",
|
2018-10-24 00:03:34 +00:00
|
|
|
OC[Offset], OC[Offset + 1], Reg, Off);
|
|
|
|
else
|
|
|
|
SW.startLine() << format("0x%02x%02x ; ldr x%u, [sp], #%u\n",
|
|
|
|
OC[Offset], OC[Offset + 1], Reg, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = (OC[Offset] & 0x01) << 8;
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg *= 2;
|
|
|
|
Reg += 19;
|
|
|
|
uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
|
|
|
|
SW.startLine() << format("0x%02x%02x ; %s x%u, lr, [sp, #%u]\n",
|
|
|
|
OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "stp" : "ldp"),
|
|
|
|
Reg, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = (OC[Offset] & 0x01) << 8;
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg += 8;
|
|
|
|
uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
|
|
|
|
SW.startLine() << format("0x%02x%02x ; %s d%u, d%u, [sp, #%u]\n",
|
|
|
|
OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "stp" : "ldp"),
|
|
|
|
Reg, Reg + 1, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = (OC[Offset] & 0x01) << 8;
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg += 8;
|
|
|
|
uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset],
|
|
|
|
OC[Offset + 1], Reg, Reg + 1, Off);
|
|
|
|
else
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; ldp d%u, d%u, [sp], #%u\n", OC[Offset],
|
|
|
|
OC[Offset + 1], Reg, Reg + 1, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = (OC[Offset] & 0x01) << 8;
|
|
|
|
Reg |= (OC[Offset + 1] & 0xC0);
|
|
|
|
Reg >>= 6;
|
|
|
|
Reg += 8;
|
|
|
|
uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
|
2020-08-24 12:29:56 +03:00
|
|
|
SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n",
|
2018-10-24 00:03:34 +00:00
|
|
|
OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "str" : "ldr"),
|
|
|
|
Reg, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8;
|
|
|
|
uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; str d%u, [sp, #-%u]!\n", OC[Offset],
|
|
|
|
OC[Offset + 1], Reg, Off);
|
|
|
|
else
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; ldr d%u, [sp], #%u\n", OC[Offset],
|
|
|
|
OC[Offset + 1], Reg, Off);
|
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
unsigned Off =
|
|
|
|
(OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0);
|
|
|
|
Off <<= 4;
|
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x%02x%02x ; %s sp, #%u\n", OC[Offset], OC[Offset + 1],
|
|
|
|
OC[Offset + 2], OC[Offset + 3],
|
|
|
|
static_cast<const char *>(Prologue ? "sub" : "add"), Off);
|
|
|
|
Offset += 4;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length,
|
|
|
|
bool Prologue) {
|
2020-09-08 09:56:45 +03:00
|
|
|
SW.startLine() << format("0x%02x ; mov %s, %s\n", OC[Offset],
|
|
|
|
static_cast<const char *>(Prologue ? "fp" : "sp"),
|
|
|
|
static_cast<const char *>(Prologue ? "sp" : "fp"));
|
2018-10-24 00:03:34 +00:00
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length,
|
|
|
|
bool Prologue) {
|
|
|
|
unsigned NumBytes = OC[Offset + 1] << 3;
|
2020-09-08 09:56:45 +03:00
|
|
|
SW.startLine() << format(
|
|
|
|
"0x%02x%02x ; %s %s, %s, #%u\n", OC[Offset], OC[Offset + 1],
|
|
|
|
static_cast<const char *>(Prologue ? "add" : "sub"),
|
|
|
|
static_cast<const char *>(Prologue ? "fp" : "sp"),
|
|
|
|
static_cast<const char *>(Prologue ? "sp" : "fp"), NumBytes);
|
2018-10-24 00:03:34 +00:00
|
|
|
Offset += 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length,
|
|
|
|
bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; nop\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length,
|
|
|
|
bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; end\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length,
|
|
|
|
bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; end_c\n", OC[Offset]);
|
|
|
|
++Offset;
|
2022-07-08 11:48:44 -07:00
|
|
|
return false;
|
2018-10-24 00:03:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-16 00:26:24 +03:00
|
|
|
bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format("0x%02x ; save next\n", OC[Offset]);
|
|
|
|
else
|
|
|
|
SW.startLine() << format("0x%02x ; restore next\n",
|
|
|
|
OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-04 18:55:01 -07:00
|
|
|
bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
// Whether the instruction has writeback
|
|
|
|
bool Writeback = (OC[Offset + 1] & 0x20) == 0x20;
|
|
|
|
// Whether the instruction is paired. (Paired instructions are required
|
|
|
|
// to save/restore adjacent registers.)
|
|
|
|
bool Paired = (OC[Offset + 1] & 0x40) == 0x40;
|
|
|
|
// The kind of register saved:
|
|
|
|
// - 0 is an x register
|
|
|
|
// - 1 is the low half of a q register
|
|
|
|
// - 2 is a whole q register
|
|
|
|
int RegKind = (OC[Offset + 2] & 0xC0) >> 6;
|
|
|
|
// Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.)
|
|
|
|
int Reg = OC[Offset + 1] & 0x1F;
|
|
|
|
// Encoded stack offset of load/store instruction; decoding varies by mode.
|
|
|
|
int StackOffset = OC[Offset + 2] & 0x3F;
|
|
|
|
if (Writeback)
|
|
|
|
StackOffset++;
|
|
|
|
if (!Writeback && !Paired && RegKind != 2)
|
|
|
|
StackOffset *= 8;
|
|
|
|
else
|
|
|
|
StackOffset *= 16;
|
|
|
|
|
|
|
|
SW.startLine() << format("0x%02x%02x%02x ; ", OC[Offset],
|
|
|
|
OC[Offset + 1], OC[Offset + 2]);
|
|
|
|
|
|
|
|
// Verify the encoding is in a form we understand. The high bit of the first
|
|
|
|
// byte, and mode 3 for the register kind are apparently reserved. The
|
|
|
|
// encoded register must refer to a valid register.
|
|
|
|
int MaxReg = 0x1F;
|
|
|
|
if (Paired)
|
|
|
|
--MaxReg;
|
|
|
|
if (RegKind == 0)
|
|
|
|
--MaxReg;
|
|
|
|
if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) {
|
|
|
|
SW.getOStream() << "invalid save_any_reg encoding\n";
|
|
|
|
Offset += 3;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Paired) {
|
|
|
|
if (Prologue)
|
|
|
|
SW.getOStream() << "stp ";
|
|
|
|
else
|
|
|
|
SW.getOStream() << "ldp ";
|
|
|
|
} else {
|
|
|
|
if (Prologue)
|
|
|
|
SW.getOStream() << "str ";
|
|
|
|
else
|
|
|
|
SW.getOStream() << "ldr ";
|
|
|
|
}
|
|
|
|
|
|
|
|
char RegChar = 'x';
|
|
|
|
if (RegKind == 1) {
|
|
|
|
RegChar = 'd';
|
|
|
|
} else if (RegKind == 2) {
|
|
|
|
RegChar = 'q';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Paired)
|
|
|
|
SW.getOStream() << format("%c%d, %c%d, ", RegChar, Reg, RegChar, Reg + 1);
|
|
|
|
else
|
|
|
|
SW.getOStream() << format("%c%d, ", RegChar, Reg);
|
|
|
|
|
|
|
|
if (Writeback) {
|
|
|
|
if (Prologue)
|
|
|
|
SW.getOStream() << format("[sp, #-%d]!\n", StackOffset);
|
|
|
|
else
|
|
|
|
SW.getOStream() << format("[sp], #%d\n", StackOffset);
|
|
|
|
} else {
|
|
|
|
SW.getOStream() << format("[sp, #%d]\n", StackOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
Offset += 3;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-16 00:26:24 +03:00
|
|
|
bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; machine frame\n",
|
|
|
|
OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; context\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-11-16 03:19:34 -08:00
|
|
|
bool Decoder::opcode_ec_context(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; EC context\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-16 00:26:24 +03:00
|
|
|
bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
|
|
|
SW.startLine() << format("0x%02x ; clear unwound to call\n",
|
|
|
|
OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-12 14:27:22 +03:00
|
|
|
bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset,
|
|
|
|
unsigned Length, bool Prologue) {
|
2022-10-05 12:04:02 +03:00
|
|
|
if (Prologue)
|
|
|
|
SW.startLine() << format("0x%02x ; pacibsp\n", OC[Offset]);
|
|
|
|
else
|
|
|
|
SW.startLine() << format("0x%02x ; autibsp\n", OC[Offset]);
|
|
|
|
++Offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-11 21:46:33 +00:00
|
|
|
void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
|
2014-06-04 15:47:15 +00:00
|
|
|
bool Prologue) {
|
2014-06-04 16:03:20 +00:00
|
|
|
assert((!Prologue || Offset == 0) && "prologue should always use offset 0");
|
2018-10-24 00:03:34 +00:00
|
|
|
const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring;
|
2014-06-04 15:47:15 +00:00
|
|
|
bool Terminated = false;
|
|
|
|
for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) {
|
2014-07-01 14:46:44 +00:00
|
|
|
for (unsigned DI = 0;; ++DI) {
|
2022-09-06 18:06:58 -06:00
|
|
|
if ((isAArch64 && (DI >= std::size(Ring64))) ||
|
|
|
|
(!isAArch64 && (DI >= std::size(Ring)))) {
|
2018-10-24 00:03:34 +00:00
|
|
|
SW.startLine() << format("0x%02x ; Bad opcode!\n",
|
2018-11-02 19:59:08 +00:00
|
|
|
Opcodes.data()[OI]);
|
2018-10-24 00:03:34 +00:00
|
|
|
++OI;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) {
|
|
|
|
if (OI + DecodeRing[DI].Length > OE) {
|
|
|
|
SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n",
|
|
|
|
Opcodes[OI]);
|
|
|
|
OI += DecodeRing[DI].Length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Terminated =
|
|
|
|
(this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue);
|
2014-06-04 15:47:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,
|
|
|
|
const SectionRef &Section,
|
|
|
|
uint64_t FunctionAddress, uint64_t VA) {
|
|
|
|
ArrayRef<uint8_t> Contents;
|
|
|
|
if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
|
|
|
|
return false;
|
|
|
|
|
2014-10-08 15:28:58 +00:00
|
|
|
uint64_t SectionVA = Section.getAddress();
|
2014-06-04 15:47:15 +00:00
|
|
|
uint64_t Offset = VA - SectionVA;
|
|
|
|
const ulittle32_t *Data =
|
|
|
|
reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
|
|
|
|
|
2018-10-24 00:03:34 +00:00
|
|
|
// Sanity check to ensure that the .xdata header is present.
|
|
|
|
// A header is one or two words, followed by at least one word to describe
|
|
|
|
// the unwind codes. Applicable to both ARM and AArch64.
|
|
|
|
if (Contents.size() - Offset < 8)
|
|
|
|
report_fatal_error(".xdata must be at least 8 bytes in size");
|
|
|
|
|
|
|
|
const ExceptionDataRecord XData(Data, isAArch64);
|
2014-06-04 15:47:15 +00:00
|
|
|
DictScope XRS(SW, "ExceptionData");
|
2018-10-24 00:03:34 +00:00
|
|
|
SW.printNumber("FunctionLength",
|
|
|
|
isAArch64 ? XData.FunctionLengthInBytesAArch64() :
|
|
|
|
XData.FunctionLengthInBytesARM());
|
2014-06-04 15:47:15 +00:00
|
|
|
SW.printNumber("Version", XData.Vers());
|
|
|
|
SW.printBoolean("ExceptionData", XData.X());
|
|
|
|
SW.printBoolean("EpiloguePacked", XData.E());
|
2018-10-24 00:03:34 +00:00
|
|
|
if (!isAArch64)
|
|
|
|
SW.printBoolean("Fragment", XData.F());
|
2014-06-04 15:47:15 +00:00
|
|
|
SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes",
|
|
|
|
XData.EpilogueCount());
|
2018-10-24 00:03:34 +00:00
|
|
|
uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t);
|
|
|
|
SW.printNumber("ByteCodeLength", ByteCodeLength);
|
|
|
|
|
|
|
|
if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) -
|
|
|
|
(XData.E() ? 0 : XData.EpilogueCount() * 4) -
|
2019-09-20 06:33:03 +00:00
|
|
|
(XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) {
|
|
|
|
SW.flush();
|
2018-10-24 00:03:34 +00:00
|
|
|
report_fatal_error("Malformed unwind data");
|
2019-09-20 06:33:03 +00:00
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
if (XData.E()) {
|
2014-09-11 21:46:33 +00:00
|
|
|
ArrayRef<uint8_t> UC = XData.UnwindByteCode();
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
{
|
2014-06-04 15:47:15 +00:00
|
|
|
ListScope PS(SW, "Prologue");
|
|
|
|
decodeOpcodes(UC, 0, /*Prologue=*/true);
|
|
|
|
}
|
|
|
|
if (XData.EpilogueCount()) {
|
|
|
|
ListScope ES(SW, "Epilogue");
|
|
|
|
decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false);
|
|
|
|
}
|
|
|
|
} else {
|
2018-10-24 00:03:34 +00:00
|
|
|
{
|
|
|
|
ListScope PS(SW, "Prologue");
|
|
|
|
decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true);
|
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes();
|
|
|
|
ListScope ESS(SW, "EpilogueScopes");
|
|
|
|
for (const EpilogueScope ES : EpilogueScopes) {
|
|
|
|
DictScope ESES(SW, "EpilogueScope");
|
|
|
|
SW.printNumber("StartOffset", ES.EpilogueStartOffset());
|
2018-10-24 00:03:34 +00:00
|
|
|
if (!isAArch64)
|
|
|
|
SW.printNumber("Condition", ES.Condition());
|
|
|
|
SW.printNumber("EpilogueStartIndex",
|
|
|
|
isAArch64 ? ES.EpilogueStartIndexAArch64()
|
|
|
|
: ES.EpilogueStartIndexARM());
|
[llvm-readobj] Fix printing of Windows ARM unwind opcodes, add tests
The existing code was essentially untested; in some cases, it used
too narrow variable types to fit all the bits, in some cases the
bit manipulation operations were incorrect.
For the "ldr lr, [sp], #x" opcode, there's nothing in the documentation
that says it cannot be used in a prologue. (In practice, it would
probably seldom be used there, but technically there's nothing
stopping it from being used.) The documentation only specifies the
operation to replay for unwinding it, but the corresponding mirror
instruction to be printed for a prologue is "str lr, [sp, #-x]!".
Also improve printing of register masks, by aggregating registers
into ranges where possible, and make the printing of the terminating
branches clearer, as "bx <reg>" and "b.w <target>".
Differential Revision: https://reviews.llvm.org/D125643
2021-11-23 00:44:58 +02:00
|
|
|
unsigned ReservedMask = isAArch64 ? 0xF : 0x3;
|
|
|
|
if ((ES.ES >> 18) & ReservedMask)
|
|
|
|
SW.printNumber("ReservedBits", (ES.ES >> 18) & ReservedMask);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
ListScope Opcodes(SW, "Opcodes");
|
2018-10-24 00:03:34 +00:00
|
|
|
decodeOpcodes(XData.UnwindByteCode(),
|
|
|
|
isAArch64 ? ES.EpilogueStartIndexAArch64()
|
|
|
|
: ES.EpilogueStartIndexARM(),
|
2014-06-04 15:47:15 +00:00
|
|
|
/*Prologue=*/false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (XData.X()) {
|
|
|
|
const uint32_t Parameter = XData.ExceptionHandlerParameter();
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
const size_t HandlerOffset = HeaderWords(XData) +
|
|
|
|
(XData.E() ? 0 : XData.EpilogueCount()) +
|
|
|
|
XData.CodeWords();
|
|
|
|
|
|
|
|
uint64_t Address, SymbolOffset;
|
|
|
|
ErrorOr<SymbolRef> Symbol = getSymbolForLocation(
|
|
|
|
COFF, Section, Offset + HandlerOffset * sizeof(uint32_t),
|
|
|
|
XData.ExceptionHandlerRVA(), Address, SymbolOffset,
|
|
|
|
/*FunctionOnly=*/true);
|
2018-11-02 19:59:08 +00:00
|
|
|
if (!Symbol) {
|
|
|
|
ListScope EHS(SW, "ExceptionHandler");
|
2019-11-25 15:26:13 +02:00
|
|
|
SW.printHex("Routine", Address);
|
|
|
|
SW.printHex("Parameter", Parameter);
|
2018-11-02 19:59:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
|
2016-04-20 21:24:34 +00:00
|
|
|
Expected<StringRef> Name = Symbol->getName();
|
|
|
|
if (!Name) {
|
|
|
|
std::string Buf;
|
|
|
|
llvm::raw_string_ostream OS(Buf);
|
2018-11-11 01:46:03 +00:00
|
|
|
logAllUnhandledErrors(Name.takeError(), OS);
|
2024-09-13 06:22:59 -04:00
|
|
|
report_fatal_error(Twine(Buf));
|
2016-04-20 21:24:34 +00:00
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
ListScope EHS(SW, "ExceptionHandler");
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
SW.printString("Routine", formatSymbol(*Name, Address, SymbolOffset));
|
2014-06-04 15:47:15 +00:00
|
|
|
SW.printHex("Parameter", Parameter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
|
|
|
|
const SectionRef Section, uint64_t Offset,
|
|
|
|
unsigned Index, const RuntimeFunction &RF) {
|
|
|
|
assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
|
|
|
|
"packed entry cannot be treated as an unpacked entry");
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
uint64_t FunctionAddress, FunctionOffset;
|
|
|
|
ErrorOr<SymbolRef> Function = getSymbolForLocation(
|
|
|
|
COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,
|
|
|
|
/*FunctionOnly=*/true);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
uint64_t XDataAddress, XDataOffset;
|
|
|
|
ErrorOr<SymbolRef> XDataRecord = getSymbolForLocation(
|
|
|
|
COFF, Section, Offset + 4, RF.ExceptionInformationRVA(), XDataAddress,
|
|
|
|
XDataOffset);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
if (!RF.BeginAddress && !Function)
|
|
|
|
return false;
|
|
|
|
if (!RF.UnwindData && !XDataRecord)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
StringRef FunctionName;
|
|
|
|
if (Function) {
|
2016-04-20 21:24:34 +00:00
|
|
|
Expected<StringRef> FunctionNameOrErr = Function->getName();
|
|
|
|
if (!FunctionNameOrErr) {
|
|
|
|
std::string Buf;
|
|
|
|
llvm::raw_string_ostream OS(Buf);
|
2018-11-11 01:46:03 +00:00
|
|
|
logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
|
2024-09-13 06:22:59 -04:00
|
|
|
report_fatal_error(Twine(Buf));
|
2016-04-20 21:24:34 +00:00
|
|
|
}
|
2015-07-02 20:55:21 +00:00
|
|
|
FunctionName = *FunctionNameOrErr;
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
SW.printString("Function",
|
|
|
|
formatSymbol(FunctionName, FunctionAddress, FunctionOffset));
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
if (XDataRecord) {
|
2016-04-20 21:24:34 +00:00
|
|
|
Expected<StringRef> Name = XDataRecord->getName();
|
|
|
|
if (!Name) {
|
|
|
|
std::string Buf;
|
|
|
|
llvm::raw_string_ostream OS(Buf);
|
2018-11-11 01:46:03 +00:00
|
|
|
logAllUnhandledErrors(Name.takeError(), OS);
|
2024-09-13 06:22:59 -04:00
|
|
|
report_fatal_error(Twine(Buf));
|
2016-04-20 21:24:34 +00:00
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
SW.printString("ExceptionRecord",
|
|
|
|
formatSymbol(*Name, XDataAddress, XDataOffset));
|
2014-06-04 15:47:15 +00:00
|
|
|
|
2016-05-02 20:28:12 +00:00
|
|
|
Expected<section_iterator> SIOrErr = XDataRecord->getSection();
|
|
|
|
if (!SIOrErr) {
|
|
|
|
// TODO: Actually report errors helpfully.
|
|
|
|
consumeError(SIOrErr.takeError());
|
2014-06-04 15:47:15 +00:00
|
|
|
return false;
|
2016-05-02 20:28:12 +00:00
|
|
|
}
|
2015-08-07 23:27:14 +00:00
|
|
|
section_iterator SI = *SIOrErr;
|
2014-06-04 15:47:15 +00:00
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
return dumpXDataRecord(COFF, *SI, FunctionAddress, XDataAddress);
|
2014-06-04 15:47:15 +00:00
|
|
|
} else {
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
SW.printString("ExceptionRecord", formatSymbol("", XDataAddress));
|
2014-06-04 15:47:15 +00:00
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
ErrorOr<SectionRef> Section = getSectionContaining(COFF, XDataAddress);
|
2014-06-04 15:47:15 +00:00
|
|
|
if (!Section)
|
|
|
|
return false;
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
return dumpXDataRecord(COFF, *Section, FunctionAddress, XDataAddress);
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
|
|
|
|
const SectionRef Section, uint64_t Offset,
|
|
|
|
unsigned Index, const RuntimeFunction &RF) {
|
|
|
|
assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
|
|
|
|
RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
|
|
|
|
"unpacked entry cannot be treated as a packed entry");
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
uint64_t FunctionAddress, FunctionOffset;
|
|
|
|
ErrorOr<SymbolRef> Function = getSymbolForLocation(
|
|
|
|
COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,
|
|
|
|
/*FunctionOnly=*/true);
|
2014-06-04 15:47:15 +00:00
|
|
|
|
|
|
|
StringRef FunctionName;
|
|
|
|
if (Function) {
|
2016-04-20 21:24:34 +00:00
|
|
|
Expected<StringRef> FunctionNameOrErr = Function->getName();
|
|
|
|
if (!FunctionNameOrErr) {
|
|
|
|
std::string Buf;
|
|
|
|
llvm::raw_string_ostream OS(Buf);
|
2018-11-11 01:46:03 +00:00
|
|
|
logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
|
2024-09-13 06:22:59 -04:00
|
|
|
report_fatal_error(Twine(Buf));
|
2016-04-20 21:24:34 +00:00
|
|
|
}
|
2015-07-02 20:55:21 +00:00
|
|
|
FunctionName = *FunctionNameOrErr;
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
SW.printString("Function",
|
|
|
|
formatSymbol(FunctionName, FunctionAddress, FunctionOffset));
|
2021-11-22 14:13:01 +02:00
|
|
|
SW.printBoolean("Fragment",
|
|
|
|
RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
|
2014-06-04 15:47:15 +00:00
|
|
|
SW.printNumber("FunctionLength", RF.FunctionLength());
|
|
|
|
SW.startLine() << "ReturnType: " << RF.Ret() << '\n';
|
|
|
|
SW.printBoolean("HomedParameters", RF.H());
|
2021-11-22 14:13:01 +02:00
|
|
|
SW.printNumber("Reg", RF.Reg());
|
|
|
|
SW.printNumber("R", RF.R());
|
|
|
|
SW.printBoolean("LinkRegister", RF.L());
|
|
|
|
SW.printBoolean("Chaining", RF.C());
|
2014-06-04 15:47:15 +00:00
|
|
|
SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2);
|
|
|
|
|
2021-11-22 14:13:01 +02:00
|
|
|
{
|
|
|
|
ListScope PS(SW, "Prologue");
|
|
|
|
|
|
|
|
uint16_t GPRMask, VFPMask;
|
|
|
|
std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true);
|
|
|
|
|
|
|
|
if (StackAdjustment(RF) && !PrologueFolding(RF))
|
|
|
|
SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n";
|
|
|
|
if (VFPMask) {
|
|
|
|
SW.startLine() << "vpush ";
|
|
|
|
printVFPMask(VFPMask);
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
if (RF.C()) {
|
|
|
|
// Count the number of registers pushed below R11
|
2023-01-22 12:48:51 -08:00
|
|
|
int FpOffset = 4 * llvm::popcount(GPRMask & ((1U << 11) - 1));
|
2021-11-22 14:13:01 +02:00
|
|
|
if (FpOffset)
|
|
|
|
SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n";
|
|
|
|
else
|
|
|
|
SW.startLine() << "mov r11, sp\n";
|
|
|
|
}
|
|
|
|
if (GPRMask) {
|
|
|
|
SW.startLine() << "push ";
|
|
|
|
printGPRMask(GPRMask);
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
if (RF.H())
|
|
|
|
SW.startLine() << "push {r0-r3}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RF.Ret() != ReturnType::RT_NoEpilogue) {
|
|
|
|
ListScope PS(SW, "Epilogue");
|
|
|
|
|
|
|
|
uint16_t GPRMask, VFPMask;
|
|
|
|
std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false);
|
|
|
|
|
|
|
|
if (StackAdjustment(RF) && !EpilogueFolding(RF))
|
|
|
|
SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n";
|
|
|
|
if (VFPMask) {
|
|
|
|
SW.startLine() << "vpop ";
|
|
|
|
printVFPMask(VFPMask);
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
if (GPRMask) {
|
|
|
|
SW.startLine() << "pop ";
|
|
|
|
printGPRMask(GPRMask);
|
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
if (RF.H()) {
|
|
|
|
if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP)
|
|
|
|
SW.startLine() << "add sp, sp, #16\n";
|
|
|
|
else
|
|
|
|
SW.startLine() << "ldr pc, [sp], #20\n";
|
|
|
|
}
|
|
|
|
if (RF.Ret() != ReturnType::RT_POP)
|
|
|
|
SW.startLine() << RF.Ret() << '\n';
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:47:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-04 23:42:22 +03:00
|
|
|
bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF,
|
|
|
|
const SectionRef Section, uint64_t Offset,
|
|
|
|
unsigned Index,
|
|
|
|
const RuntimeFunctionARM64 &RF) {
|
|
|
|
assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
|
|
|
|
RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
|
|
|
|
"unpacked entry cannot be treated as a packed entry");
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
uint64_t FunctionAddress, FunctionOffset;
|
|
|
|
ErrorOr<SymbolRef> Function = getSymbolForLocation(
|
|
|
|
COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,
|
|
|
|
/*FunctionOnly=*/true);
|
2020-09-04 23:42:22 +03:00
|
|
|
|
|
|
|
StringRef FunctionName;
|
|
|
|
if (Function) {
|
|
|
|
Expected<StringRef> FunctionNameOrErr = Function->getName();
|
|
|
|
if (!FunctionNameOrErr) {
|
|
|
|
std::string Buf;
|
|
|
|
llvm::raw_string_ostream OS(Buf);
|
|
|
|
logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
|
2024-09-13 06:22:59 -04:00
|
|
|
report_fatal_error(Twine(Buf));
|
2020-09-04 23:42:22 +03:00
|
|
|
}
|
|
|
|
FunctionName = *FunctionNameOrErr;
|
|
|
|
}
|
|
|
|
|
Reapply [llvm-readobj] [ARMWinEH] Fix handling of relocations and symbol offsets
When looking up data referenced from pdata/xdata structures, the
referenced data can be found in two different ways:
- For an unrelocated object file, it's located via a relocation
- For a relocated, linked image, the data is referenced with an
(image relative) absolute address
For the latter case, the absolute address can optionally be
described with a symbol.
For the case of an object file, there's two offsets involved; one
immediate offset encoded in the data location that is modified by
the relocation, and a section offset in the symbol.
Previously, for the ExceptionRecord field, we printed the offset
from the symbol (only) but used the immediate offset ignoring
the symbol's address (using only the symbol's section) for printing
the exception data.
Add a helper method for doing the lookup and address calculation,
for simplifying the calling code and making all the cases consistent.
This addresses an existing FIXME comment, fixing printing of the
exception data for cases where relocations point at individual
symbols in the xdata section (which is what MSVC generates) instead of
all relocations pointing at the start of the xdata section (which is
what LLVM generates).
This also fixes printing of the function name for packed entries in
linked images.
Relanded with a format string fix in the formatSymbol function; one
can't use %X as format string for an uint64_t. That bug has been
present since this code was added in e6971cab306cd.
Differential Revision: https://reviews.llvm.org/D100305
2021-04-12 12:49:17 +03:00
|
|
|
SW.printString("Function",
|
|
|
|
formatSymbol(FunctionName, FunctionAddress, FunctionOffset));
|
2020-09-04 23:42:22 +03:00
|
|
|
SW.printBoolean("Fragment",
|
|
|
|
RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
|
|
|
|
SW.printNumber("FunctionLength", RF.FunctionLength());
|
|
|
|
SW.printNumber("RegF", RF.RegF());
|
|
|
|
SW.printNumber("RegI", RF.RegI());
|
|
|
|
SW.printBoolean("HomedParameters", RF.H());
|
|
|
|
SW.printNumber("CR", RF.CR());
|
|
|
|
SW.printNumber("FrameSize", RF.FrameSize() << 4);
|
|
|
|
ListScope PS(SW, "Prologue");
|
|
|
|
|
|
|
|
// Synthesize the equivalent prologue according to the documentation
|
|
|
|
// at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling,
|
|
|
|
// printed in reverse order compared to the docs, to match how prologues
|
|
|
|
// are printed for the non-packed case.
|
|
|
|
int IntSZ = 8 * RF.RegI();
|
|
|
|
if (RF.CR() == 1)
|
|
|
|
IntSZ += 8;
|
|
|
|
int FpSZ = 8 * RF.RegF();
|
|
|
|
if (RF.RegF())
|
|
|
|
FpSZ += 8;
|
|
|
|
int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf;
|
|
|
|
int LocSZ = (RF.FrameSize() << 4) - SavSZ;
|
|
|
|
|
2022-10-05 12:04:02 +03:00
|
|
|
if (RF.CR() == 2 || RF.CR() == 3) {
|
2020-09-04 23:42:22 +03:00
|
|
|
SW.startLine() << "mov x29, sp\n";
|
|
|
|
if (LocSZ <= 512) {
|
|
|
|
SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ);
|
|
|
|
} else {
|
|
|
|
SW.startLine() << "stp x29, lr, [sp, #0]\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (LocSZ > 4080) {
|
|
|
|
SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080);
|
|
|
|
SW.startLine() << "sub sp, sp, #4080\n";
|
2022-10-05 12:04:02 +03:00
|
|
|
} else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) {
|
2020-09-04 23:42:22 +03:00
|
|
|
SW.startLine() << format("sub sp, sp, #%d\n", LocSZ);
|
|
|
|
}
|
|
|
|
if (RF.H()) {
|
2022-05-12 14:33:49 +03:00
|
|
|
SW.startLine() << format("stp x6, x7, [sp, #%d]\n", SavSZ - 16);
|
|
|
|
SW.startLine() << format("stp x4, x5, [sp, #%d]\n", SavSZ - 32);
|
|
|
|
SW.startLine() << format("stp x2, x3, [sp, #%d]\n", SavSZ - 48);
|
2020-09-04 23:42:22 +03:00
|
|
|
if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) {
|
2022-05-12 14:33:49 +03:00
|
|
|
SW.startLine() << format("stp x0, x1, [sp, #%d]\n", SavSZ - 64);
|
2020-09-04 23:42:22 +03:00
|
|
|
} else {
|
|
|
|
// This case isn't documented; if neither RegI nor RegF nor CR=1
|
|
|
|
// have decremented the stack pointer by SavSZ, we need to do it here
|
|
|
|
// (as the final stack adjustment of LocSZ excludes SavSZ).
|
|
|
|
SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0;
|
|
|
|
for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) {
|
|
|
|
if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) {
|
|
|
|
// The last register, an odd register without a pair
|
|
|
|
SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I,
|
|
|
|
IntSZ + 16 * I);
|
|
|
|
} else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) {
|
|
|
|
SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I,
|
|
|
|
8 + 2 * I + 1, SavSZ);
|
|
|
|
} else {
|
|
|
|
SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I,
|
|
|
|
8 + 2 * I + 1, IntSZ + 16 * I);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (RF.CR() == 1 && (RF.RegI() % 2) == 0) {
|
|
|
|
if (RF.RegI() == 0)
|
|
|
|
SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ);
|
|
|
|
else
|
|
|
|
SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8);
|
|
|
|
}
|
|
|
|
for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) {
|
|
|
|
if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) {
|
|
|
|
// The last register, an odd register without a pair
|
|
|
|
if (RF.CR() == 1) {
|
2020-11-16 00:28:33 +02:00
|
|
|
if (I == 0) { // If this is the only register pair
|
|
|
|
// CR=1 combined with RegI=1 doesn't map to a documented case;
|
|
|
|
// it doesn't map to any regular unwind info opcode, and the
|
|
|
|
// actual unwinder doesn't support it.
|
|
|
|
SW.startLine() << "INVALID!\n";
|
|
|
|
} else
|
2020-09-04 23:42:22 +03:00
|
|
|
SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I,
|
|
|
|
16 * I);
|
|
|
|
} else {
|
|
|
|
if (I == 0)
|
|
|
|
SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ);
|
|
|
|
else
|
|
|
|
SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I);
|
|
|
|
}
|
|
|
|
} else if (I == 0) {
|
|
|
|
// The first register pair
|
|
|
|
SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ);
|
|
|
|
} else {
|
|
|
|
SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I,
|
|
|
|
19 + 2 * I + 1, 16 * I);
|
|
|
|
}
|
|
|
|
}
|
2022-10-05 12:04:02 +03:00
|
|
|
// CR=2 is yet undocumented, see
|
|
|
|
// https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream
|
|
|
|
// progress on getting it documented.
|
|
|
|
if (RF.CR() == 2)
|
|
|
|
SW.startLine() << "pacibsp\n";
|
2020-09-04 23:42:22 +03:00
|
|
|
SW.startLine() << "end\n";
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:47:15 +00:00
|
|
|
bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
|
|
|
|
const SectionRef Section, unsigned Index,
|
|
|
|
ArrayRef<uint8_t> Contents) {
|
|
|
|
uint64_t Offset = PDataEntrySize * Index;
|
|
|
|
const ulittle32_t *Data =
|
|
|
|
reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
|
|
|
|
|
|
|
|
const RuntimeFunction Entry(Data);
|
|
|
|
DictScope RFS(SW, "RuntimeFunction");
|
|
|
|
if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)
|
|
|
|
return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);
|
2018-10-24 00:03:34 +00:00
|
|
|
if (isAArch64) {
|
2020-09-04 23:42:22 +03:00
|
|
|
const RuntimeFunctionARM64 EntryARM64(Data);
|
|
|
|
return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64);
|
2018-10-24 00:03:34 +00:00
|
|
|
}
|
2014-06-04 15:47:15 +00:00
|
|
|
return dumpPackedEntry(COFF, Section, Offset, Index, Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
|
|
|
|
const SectionRef Section) {
|
|
|
|
ArrayRef<uint8_t> Contents;
|
|
|
|
if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Contents.size() % PDataEntrySize) {
|
|
|
|
errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI)
|
|
|
|
if (!dumpProcedureDataEntry(COFF, Section, EI, Contents))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-05-02 10:32:03 +00:00
|
|
|
Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
|
2014-06-04 15:47:15 +00:00
|
|
|
for (const auto &Section : COFF.sections()) {
|
2019-05-02 10:32:03 +00:00
|
|
|
Expected<StringRef> NameOrErr =
|
|
|
|
COFF.getSectionName(COFF.getCOFFSection(Section));
|
|
|
|
if (!NameOrErr)
|
|
|
|
return NameOrErr.takeError();
|
2014-06-04 15:47:15 +00:00
|
|
|
|
2023-12-11 21:01:36 -08:00
|
|
|
if (NameOrErr->starts_with(".pdata"))
|
2014-06-04 15:47:15 +00:00
|
|
|
dumpProcedureData(COFF, Section);
|
|
|
|
}
|
2019-05-02 10:32:03 +00:00
|
|
|
return Error::success();
|
2014-06-04 15:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|