From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
To: gdb-patches@sourceware.org, Markus Metzger <markus.t.metzger@intel.com>
Subject: [PATCH v3 07/44] gdb, intelgt: add the target-dependent definitions for the Intel GT architecture
Date: Fri, 1 Aug 2025 11:37:09 +0200 [thread overview]
Message-ID: <20250801-upstream-intelgt-mvp-v3-7-59ce0f87075b@intel.com> (raw)
In-Reply-To: <20250801-upstream-intelgt-mvp-v3-0-59ce0f87075b@intel.com>
Introduce gdb/intelgt-tdep.c for the Intel GT target. The target is
defined in a future patch as a gdbserver low target implementation.
Unlike, for example, X86-64, IntelGT does not have a dedicated
breakpoint instruction. Instead, it has a breakpoint bit in each
instruction. Hence, any instruction can be used as a breakpoint
instruction.
It further supports ignoring breakpoints for stepping over or resuming
from a breakpoint. This only works, of course, if we use breakpoint
bits inside the original instruction rather than replacing it with a
fixed breakpoint instruction.
Add gdbarch methods for inserting and removing memory breakpoints by
setting and clearing those breakpoint bits.
We define one pseudo-register, $framedesc, that provides a type alias
for the frame descriptor register in GRF, representing it as a struct.
The value of the $pc register is the $ip register, which is provided
in $cr0.2, offset by $isabase.
A translation function to map the device_id to a gen_version is
provided. This will be useful in various places, in particular to
generate the correct disassembly.
Co-authored-by: Markus Metzger <markus.t.metzger@intel.com>
Co-authored-by: Natalia Saiapova <natalia.saiapova@intel.com>
Co-authored-by: Mihails Strasuns <mihails.strasuns@intel.com>
Co-authored-by: Mohamed Bouhaouel <mohamed.bouhaouel@intel.com>
---
gdb/Makefile.in | 1 +
gdb/configure.tgt | 5 +
gdb/intelgt-tdep.c | 875 ++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/selftest-arch.c | 6 +-
4 files changed, 886 insertions(+), 1 deletion(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8aac71d7057980a45e3cb89be2c583223762a1c7..a6f32b5c02877592ff3072a431b7e229e031ebde 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -762,6 +762,7 @@ ALL_64_TARGET_OBS = \
ia64-linux-tdep.o \
ia64-tdep.o \
ia64-vms-tdep.o \
+ intelgt-tdep.o \
loongarch-linux-tdep.o \
loongarch-tdep.o \
mips-fbsd-tdep.o \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 255c77e9f8c0d642fa1773b54ae7dfaaf25e6ef5..aa0336d874e290dcb4efedfa4af432c1a15293c6 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -357,6 +357,11 @@ ia64-*-*vms*)
gdb_target_obs="ia64-vms-tdep.o"
;;
+intelgt-*-elf)
+ # Target: Intel(R) Graphics Technology graphics processor
+ gdb_target_obs="intelgt-tdep.o arch/intelgt.o"
+ ;;
+
iq2000-*-*)
gdb_target_obs="iq2000-tdep.o"
;;
diff --git a/gdb/intelgt-tdep.c b/gdb/intelgt-tdep.c
new file mode 100644
index 0000000000000000000000000000000000000000..3919947fed44c9e939bef6c14b854ae416ab7c41
--- /dev/null
+++ b/gdb/intelgt-tdep.c
@@ -0,0 +1,875 @@
+/* Target-dependent code for the Intel(R) Graphics Technology architecture.
+
+ Copyright (C) 2019-2025 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "arch-utils.h"
+#include "arch/intelgt.h"
+#include "cli/cli-cmds.h"
+#include "dwarf2/frame.h"
+#include "frame-unwind.h"
+#include "gdbsupport/gdb_obstack.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "target-descriptions.h"
+#include "value.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "user-regs.h"
+#include <algorithm>
+
+/* Global debug flag. */
+static bool intelgt_debug = false;
+
+/* Print an "intelgt" debug statement. */
+
+#define intelgt_debug_printf(fmt, ...) \
+ debug_prefixed_printf_cond (intelgt_debug, "intelgt", fmt, ##__VA_ARGS__)
+
+/* Regnum pair describing the assigned regnum range for a single
+ regset. START is inclusive, END is exclusive. */
+
+struct regnum_range
+{
+ int start;
+ int end;
+};
+
+/* Data specific for this architecture. */
+
+struct intelgt_gdbarch_tdep : gdbarch_tdep_base
+{
+ /* $r0 GRF register number. */
+ int r0_regnum = -1;
+
+ /* $ce register number in the regcache. */
+ int ce_regnum = -1;
+
+ /* Register number for the GRF containing function return value. */
+ int retval_regnum = -1;
+
+ /* Register number for the control register. */
+ int cr0_regnum = -1;
+
+ /* Register number for the state register. */
+ int sr0_regnum = -1;
+
+ /* Register number for the instruction base virtual register. */
+ int isabase_regnum = -1;
+
+ /* Register number for the general state base SBA register. */
+ int genstbase_regnum = -1;
+
+ /* Register number for the DBG0 register. */
+ int dbg0_regnum = -1;
+
+ /* Assigned regnum ranges for DWARF regsets. */
+ regnum_range regset_ranges[intelgt::REGSET_COUNT];
+
+ /* Enabled pseudo-registers for the current target description. */
+ std::vector<std::string> enabled_pseudo_regs;
+
+ /* Cached $framedesc pseudo-register type. */
+ type *framedesc_type = nullptr;
+
+ /* Initialize ranges to -1 as "not-yet-set" indicator. */
+ intelgt_gdbarch_tdep ()
+ {
+ memset (®set_ranges, -1, sizeof regset_ranges);
+ }
+
+ /* Return regnum where frame descriptors are stored. */
+ int framedesc_base_regnum ()
+ {
+ /* For EM_INTELGT frame descriptors are stored at MAX_GRF - 1. */
+ gdb_assert (regset_ranges[intelgt::REGSET_GRF].end > 1);
+ return regset_ranges[intelgt::REGSET_GRF].end - 1;
+ }
+};
+
+/* Per-inferior cached data for the Intelgt target. */
+
+struct intelgt_inferior_data
+{
+ /* Device target id. */
+ uint32_t device_id = 0u;
+};
+
+static const registry<inferior>::key<intelgt_inferior_data>
+ intelgt_inferior_data_handle;
+
+/* Fetch the per-inferior data. */
+
+static intelgt_inferior_data *
+get_intelgt_inferior_data (inferior *inf)
+{
+ intelgt_inferior_data *inf_data = intelgt_inferior_data_handle.get (inf);
+ if (inf_data == nullptr)
+ inf_data = intelgt_inferior_data_handle.emplace (inf);
+
+ return inf_data;
+}
+
+/* Helper function to return the device id using GDBARCH. */
+
+static uint32_t
+get_device_id (gdbarch *gdbarch)
+{
+ const target_desc *tdesc = gdbarch_target_desc (gdbarch);
+ const tdesc_device *device_info = tdesc_device_info (tdesc);
+ if (!device_info->target_id.has_value ())
+ error (_("A target id for the device is required."));
+
+ return *device_info->target_id;
+}
+
+/* Helper function to return the device id using the inferior. */
+
+static uint32_t
+get_device_id (inferior *inferior)
+{
+ intelgt_inferior_data *inf_data = get_intelgt_inferior_data (inferior);
+ if (inf_data->device_id == 0u)
+ inf_data->device_id = get_device_id (inferior->arch ());
+
+ return inf_data->device_id;
+}
+
+/* Read part of REGNUM at OFFSET into BUFFER. The length of data to
+ read is SIZE. Consider using this helper function when reading
+ subregisters of CR0, SR0, and R0. */
+
+static void
+intelgt_read_register_part (readable_regcache *regcache, int regnum,
+ size_t offset,
+ gdb::array_view<gdb_byte> buffer,
+ const char *error_message)
+{
+ if (regnum == -1)
+ error (_("%s Unexpected reg num '-1'."), error_message);
+
+ gdbarch *arch = regcache->arch ();
+ const char *regname = gdbarch_register_name (arch, regnum);
+ int regsize = register_size (arch, regnum);
+
+ if (offset + buffer.size () > regsize)
+ error (_("%s %s[%zu:%zu] is outside the range of %s[%d:0]."),
+ error_message, regname, (offset + buffer.size () - 1), offset,
+ regname, (regsize - 1));
+
+ register_status reg_status
+ = regcache->cooked_read_part (regnum, offset, buffer);
+
+ if (reg_status == REG_UNAVAILABLE)
+ throw_error (NOT_AVAILABLE_ERROR,
+ _("%s Register %s (%d) is not available."),
+ error_message, regname, regnum);
+
+ if (reg_status == REG_UNKNOWN)
+ error (_("%s Register %s (%d) is unknown."), error_message,
+ regname, regnum);
+}
+
+/* Utility function to look up the pseudo-register number by name. Exact
+ amount of pseudo-registers may differ and thus fixed constants can't be
+ used for this. */
+
+static int
+intelgt_pseudo_register_num (gdbarch *arch, const char *name)
+{
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+ auto iter = std::find (data->enabled_pseudo_regs.begin (),
+ data->enabled_pseudo_regs.end (), name);
+ gdb_assert (iter != data->enabled_pseudo_regs.end ());
+ return gdbarch_num_regs (arch) + (iter - data->enabled_pseudo_regs.begin ());
+}
+
+/* Convert a DWARF register number to a GDB register number. This
+ function requires the register listing in the target description to
+ be in the same order in each regset as the intended DWARF numbering
+ order. Currently this always holds true when gdbserver generates
+ the target description. */
+
+static int
+intelgt_dwarf_reg_to_regnum (gdbarch *gdbarch, int num)
+{
+ constexpr int ip = 0;
+ constexpr int ce = 1;
+
+ /* Register sets follow this format: [START, END), where START is
+ inclusive and END is exclusive. */
+ constexpr regnum_range dwarf_nums[intelgt::REGSET_COUNT] = {
+ [intelgt::REGSET_SBA] = { 5, 12 },
+ [intelgt::REGSET_GRF] = { 16, 272 },
+ [intelgt::REGSET_ADDR] = { 272, 288 },
+ [intelgt::REGSET_FLAG] = { 288, 304 },
+ [intelgt::REGSET_ACC] = { 304, 320 },
+ [intelgt::REGSET_MME] = { 320, 336 },
+ };
+
+ /* Number of SBA registers. */
+ constexpr size_t sba_dwarf_len = dwarf_nums[intelgt::REGSET_SBA].end
+ - dwarf_nums[intelgt::REGSET_SBA].start;
+
+ /* Map the DWARF register numbers of SBA registers to their names.
+ Base number is dwarf_nums[intelgt::REGSET_SBA].start. */
+ constexpr const char* sba_dwarf_reg_order[sba_dwarf_len] {
+ "btbase",
+ "scrbase",
+ "genstbase",
+ "sustbase",
+ "blsustbase",
+ "blsastbase",
+ "scrbase2"
+ };
+
+ intelgt_gdbarch_tdep *data
+ = gdbarch_tdep<intelgt_gdbarch_tdep> (gdbarch);
+
+ if (num == ip)
+ return intelgt_pseudo_register_num (gdbarch, "ip");
+ if (num == ce)
+ return data->ce_regnum;
+
+ for (int regset = 0; regset < intelgt::REGSET_COUNT; ++regset)
+ if (num >= dwarf_nums[regset].start && num < dwarf_nums[regset].end)
+ {
+ if (regset == intelgt::REGSET_SBA)
+ {
+ /* For SBA registers we first find out the name of the
+ register out of DWARF register number and then find the
+ register number corresponding to the name. */
+ int sba_num = num - dwarf_nums[intelgt::REGSET_SBA].start;
+ const char* name = sba_dwarf_reg_order [sba_num];
+
+ return user_reg_map_name_to_regnum (gdbarch, name, -1);
+ }
+ else
+ {
+ int candidate = data->regset_ranges[regset].start + num
+ - dwarf_nums[regset].start;
+
+ if (candidate < data->regset_ranges[regset].end)
+ return candidate;
+ }
+ }
+
+ return -1;
+}
+
+/* Return the PC of the first real instruction. */
+
+static CORE_ADDR
+intelgt_skip_prologue (gdbarch *gdbarch, CORE_ADDR start_pc)
+{
+ intelgt_debug_printf ("start_pc: %s", paddress (gdbarch, start_pc));
+ CORE_ADDR func_addr;
+
+ if (find_pc_partial_function (start_pc, nullptr, &func_addr, nullptr))
+ {
+ CORE_ADDR post_prologue_pc
+ = skip_prologue_using_sal (gdbarch, func_addr);
+
+ intelgt_debug_printf ("post prologue pc: %s",
+ paddress (gdbarch, post_prologue_pc));
+
+ if (post_prologue_pc != 0)
+ return post_prologue_pc;
+ }
+
+ /* Could not find the end of prologue using SAL. */
+ return start_pc;
+}
+
+/* Implementation of gdbarch's return_value method. */
+
+static enum return_value_convention
+intelgt_return_value_as_value (gdbarch *gdbarch, value *function,
+ type *valtype, regcache *regcache,
+ value **read_value, const gdb_byte *writebuf)
+{
+ gdb_assert_not_reached ("intelgt_return_value_as_value is to be "
+ "implemented later.");
+}
+
+/* Callback function to unwind the $framedesc register. */
+
+static value *
+intelgt_dwarf2_prev_framedesc (const frame_info_ptr &this_frame,
+ void **this_cache, int regnum)
+{
+ gdbarch *gdbarch = get_frame_arch (this_frame);
+ intelgt_gdbarch_tdep *data
+ = gdbarch_tdep<intelgt_gdbarch_tdep> (gdbarch);
+
+ int actual_regnum = data->framedesc_base_regnum ();
+
+ /* Unwind the actual GRF register. */
+ return frame_unwind_register_value (this_frame, actual_regnum);
+}
+
+/* Architecture-specific register state initialization. */
+
+static void
+intelgt_init_reg (gdbarch *gdbarch, int regnum, dwarf2_frame_state_reg *reg,
+ const frame_info_ptr &this_frame)
+{
+ int ip_regnum = intelgt_pseudo_register_num (gdbarch, "ip");
+ int framedesc_regnum = intelgt_pseudo_register_num (gdbarch, "framedesc");
+
+ if (regnum == ip_regnum)
+ reg->how = DWARF2_FRAME_REG_RA;
+ else if (regnum == gdbarch_sp_regnum (gdbarch))
+ reg->how = DWARF2_FRAME_REG_CFA;
+ /* We use a special function to unwind the $framedesc register. */
+ else if (regnum == framedesc_regnum)
+ {
+ reg->how = DWARF2_FRAME_REG_FN;
+ reg->loc.fn = intelgt_dwarf2_prev_framedesc;
+ }
+}
+
+/* A helper function that returns the value of the ISABASE register. */
+
+static CORE_ADDR
+intelgt_get_isabase (readable_regcache *regcache)
+{
+ gdbarch *gdbarch = regcache->arch ();
+ intelgt_gdbarch_tdep *data
+ = gdbarch_tdep<intelgt_gdbarch_tdep> (gdbarch);
+ gdb_assert (data->isabase_regnum != -1);
+
+ uint64_t isabase = 0;
+ if (regcache->cooked_read (data->isabase_regnum, &isabase) != REG_VALID)
+ throw_error (NOT_AVAILABLE_ERROR,
+ _("Register %d (isabase) is not available"),
+ data->isabase_regnum);
+ return isabase;
+}
+
+/* The 'unwind_pc' gdbarch method. */
+
+static CORE_ADDR
+intelgt_unwind_pc (gdbarch *gdbarch, const frame_info_ptr &next_frame)
+{
+ /* Use ip register here, as IGC uses 32bit values (pc is 64bit). */
+ int ip_regnum = intelgt_pseudo_register_num (gdbarch, "ip");
+ CORE_ADDR prev_ip = frame_unwind_register_unsigned (next_frame,
+ ip_regnum);
+ intelgt_debug_printf ("prev_ip: %s", paddress (gdbarch, prev_ip));
+
+ /* Program counter is $ip + $isabase. Read directly from the
+ regcache instead of unwinding, as the frame unwind info may
+ simply be unavailable. The isabase register does not change
+ during kernel execution, so this must be safe. */
+ regcache *regcache = get_thread_regcache (inferior_thread ());
+ CORE_ADDR isabase = intelgt_get_isabase (regcache);
+
+ return isabase + prev_ip;
+}
+
+/* Frame unwinding. */
+
+static void
+intelgt_frame_this_id (const frame_info_ptr &this_frame,
+ void **this_prologue_cache, frame_id *this_id)
+{
+ /* FIXME: Assembly-level unwinding for intelgt is not available at
+ the moment. Stop at the first frame. */
+ *this_id = outer_frame_id;
+}
+
+/* This is a "bare minimum" unwinder that avoids crashing GDB
+ if debugging a program without debug info. */
+
+static const frame_unwind_legacy intelgt_frame_unwind (
+ "intelgt prologue",
+ NORMAL_FRAME, /* type */
+ FRAME_UNWIND_ARCH, /* class */
+ default_frame_unwind_stop_reason, /* stop_reason */
+ intelgt_frame_this_id, /* this_id */
+ nullptr, /* prev_register */
+ nullptr, /* unwind_data */
+ default_frame_sniffer /* sniffer */
+);
+
+/* The memory_insert_breakpoint gdbarch method. */
+
+static int
+intelgt_memory_insert_breakpoint (gdbarch *gdbarch, bp_target_info *bp)
+{
+ intelgt_debug_printf ("req ip: %s", paddress (gdbarch,
+ bp->reqstd_address));
+
+ /* Ensure that we have enough space in the breakpoint. */
+ static_assert (intelgt::MAX_INST_LENGTH <= BREAKPOINT_MAX);
+
+ gdb_byte inst[intelgt::MAX_INST_LENGTH];
+ int err = target_read_memory (bp->reqstd_address, inst,
+ intelgt::MAX_INST_LENGTH);
+ if (err != 0)
+ {
+ /* We could fall back to reading a full and then a compacted
+ instruction but I think we should rather allow short reads than
+ having the caller try smaller and smaller sizes. */
+ intelgt_debug_printf ("Failed to read memory at %s (%s).",
+ paddress (gdbarch, bp->reqstd_address),
+ strerror (err));
+ return err;
+ }
+
+ bp->placed_address = bp->reqstd_address;
+ uint32_t device_id = get_device_id (current_inferior ());
+ bp->shadow_len = intelgt::inst_length (inst, device_id);
+
+ /* Make a copy before we set the breakpoint so we can restore the
+ original instruction when removing the breakpoint again.
+
+ This isn't strictly necessary but it saves one target access. */
+ memcpy (bp->shadow_contents, inst, bp->shadow_len);
+
+ const bool already = intelgt::set_breakpoint (inst, device_id);
+ if (already)
+ {
+ /* Warn if the breakpoint bit is already set.
+
+ There is still a breakpoint, probably hard-coded, and it should
+ still trigger and we're still able to step over it. It's just
+ not our breakpoint. */
+ warning (_("Using permanent breakpoint at %s."),
+ paddress (gdbarch, bp->placed_address));
+
+ /* There's no need to write the unmodified instruction back. */
+ return 0;
+ }
+
+ err = target_write_raw_memory (bp->placed_address, inst, bp->shadow_len);
+ if (err != 0)
+ intelgt_debug_printf ("Failed to insert breakpoint at %s (%s).",
+ paddress (gdbarch, bp->placed_address),
+ strerror (err));
+
+ return err;
+}
+
+/* The memory_remove_breakpoint gdbarch method. */
+
+static int
+intelgt_memory_remove_breakpoint (gdbarch *gdbarch, struct bp_target_info *bp)
+{
+ intelgt_debug_printf ("req ip: %s, placed ip: %s",
+ paddress (gdbarch, bp->reqstd_address),
+ paddress (gdbarch, bp->placed_address));
+
+ /* Warn if we're inserting a permanent breakpoint. */
+ uint32_t device_id = get_device_id (current_inferior ());
+ if (intelgt::has_breakpoint (bp->shadow_contents, device_id))
+ warning (_("Re-inserting permanent breakpoint at %s."),
+ paddress (gdbarch, bp->placed_address));
+
+ int err = target_write_raw_memory (bp->placed_address, bp->shadow_contents,
+ bp->shadow_len);
+ if (err != 0)
+ intelgt_debug_printf ("Failed to remove breakpoint at %s (%s).",
+ paddress (gdbarch, bp->placed_address),
+ strerror (err));
+
+ return err;
+}
+
+/* The program_breakpoint_here_p gdbarch method. */
+
+static bool
+intelgt_program_breakpoint_here_p (gdbarch *gdbarch, CORE_ADDR pc)
+{
+ intelgt_debug_printf ("pc: %s", paddress (gdbarch, pc));
+
+ gdb_byte inst[intelgt::MAX_INST_LENGTH];
+ int err = target_read_memory (pc, inst, intelgt::MAX_INST_LENGTH);
+ if (err != 0)
+ {
+ /* We could fall back to reading a full and then a compacted
+ instruction but I think we should rather allow short reads than
+ having the caller try smaller and smaller sizes. */
+ intelgt_debug_printf ("Failed to read memory at %s (%s).",
+ paddress (gdbarch, pc), strerror (err));
+ return err;
+ }
+
+ uint32_t device_id = get_device_id (current_inferior ());
+ const bool is_bkpt = intelgt::has_breakpoint (inst, device_id);
+
+ intelgt_debug_printf ("%sbreakpoint found.", is_bkpt ? "" : "no ");
+
+ return is_bkpt;
+}
+
+/* The 'breakpoint_kind_from_pc' gdbarch method.
+ This is a required gdbarch function. */
+
+static int
+intelgt_breakpoint_kind_from_pc (gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+ intelgt_debug_printf ("*pcptr: %s", paddress (gdbarch, *pcptr));
+
+ return intelgt::BP_INSTRUCTION;
+}
+
+/* The 'sw_breakpoint_from_kind' gdbarch method. */
+
+static const gdb_byte *
+intelgt_sw_breakpoint_from_kind (gdbarch *gdbarch, int kind, int *size)
+{
+ intelgt_debug_printf ("kind: %d", kind);
+
+ /* We do not support breakpoint instructions.
+
+ We use breakpoint bits in instructions, instead. See
+ intelgt_memory_insert_breakpoint. */
+ *size = 0;
+ return nullptr;
+}
+
+/* Print one instruction from MEMADDR on INFO->STREAM. */
+
+static int
+intelgt_print_insn (bfd_vma memaddr, struct disassemble_info *info)
+{
+ /* Disassembler is to be added in a later patch. */
+ return -1;
+}
+
+/* The "read_pc" gdbarch method. */
+
+static CORE_ADDR
+intelgt_read_pc (readable_regcache *regcache)
+{
+ gdbarch *arch = regcache->arch ();
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+
+ /* Instruction pointer is stored in CR0.2. */
+ uint32_t ip;
+ intelgt_read_register_part (regcache, data->cr0_regnum,
+ sizeof (uint32_t) * 2,
+ gdb::make_array_view ((gdb_byte *) &ip,
+ sizeof (uint32_t)),
+ _("Cannot compute PC."));
+
+ /* Program counter is $ip + $isabase. */
+ CORE_ADDR isabase = intelgt_get_isabase (regcache);
+ return isabase + ip;
+}
+
+/* The "write_pc" gdbarch method. */
+
+static void
+intelgt_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+ gdbarch *arch = regcache->arch ();
+ /* Program counter is $ip + $isabase, can only modify $ip. Need
+ to ensure that the new value fits within $ip modification range
+ and propagate the write accordingly. */
+ CORE_ADDR isabase = intelgt_get_isabase (regcache);
+ if (pc < isabase || pc > isabase + UINT32_MAX)
+ error (_("Can't update $pc to value %s, out of range"),
+ paddress (arch, pc));
+
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+
+ /* Instruction pointer is stored in CR0.2. */
+ uint32_t ip = pc - isabase;
+ regcache->cooked_write_part (data->cr0_regnum, sizeof (uint32_t) * 2,
+ gdb::make_array_view ((gdb_byte *) &ip,
+ sizeof (uint32_t)));
+}
+
+/* Return the name of pseudo-register REGNUM. */
+
+static const char *
+intelgt_pseudo_register_name (gdbarch *arch, int regnum)
+{
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+ int base_num = gdbarch_num_regs (arch);
+ if (regnum < base_num
+ || regnum >= base_num + data->enabled_pseudo_regs.size ())
+ error (_("Invalid pseudo-register regnum %d"), regnum);
+ return data->enabled_pseudo_regs[regnum - base_num].c_str ();
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ pseudo-register REGNUM. */
+
+static type *
+intelgt_pseudo_register_type (gdbarch *arch, int regnum)
+{
+ const char *name = intelgt_pseudo_register_name (arch, regnum);
+ const struct builtin_type *bt = builtin_type (arch);
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+
+ if (strcmp (name, "framedesc") == 0)
+ {
+ if (data->framedesc_type != nullptr)
+ return data->framedesc_type;
+ type *frame = arch_composite_type (arch, "frame_desc", TYPE_CODE_STRUCT);
+ append_composite_type_field (frame, "return_ip", bt->builtin_uint32);
+ append_composite_type_field (frame, "return_callmask",
+ bt->builtin_uint32);
+ append_composite_type_field (frame, "be_sp", bt->builtin_uint32);
+ append_composite_type_field (frame, "be_fp", bt->builtin_uint32);
+ append_composite_type_field (frame, "fe_fp", bt->builtin_data_ptr);
+ append_composite_type_field (frame, "fe_sp", bt->builtin_data_ptr);
+ data->framedesc_type = frame;
+ return frame;
+ }
+ else if (strcmp (name, "ip") == 0)
+ return bt->builtin_uint32;
+
+ return nullptr;
+}
+
+/* Read the value of a pseudo-register REGNUM. */
+
+static struct value *
+intelgt_pseudo_register_read_value (gdbarch *arch,
+ const frame_info_ptr &next_frame,
+ int pseudo_regnum)
+{
+ const char *name = intelgt_pseudo_register_name (arch, pseudo_regnum);
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+
+ if (strcmp (name, "framedesc") == 0)
+ {
+ int grf_num = data->framedesc_base_regnum ();
+ return pseudo_from_raw_part (next_frame, pseudo_regnum, grf_num, 0);
+ }
+ else if (strcmp (name, "ip") == 0)
+ {
+ int regsize = register_size (arch, pseudo_regnum);
+ /* Instruction pointer is stored in CR0.2. */
+ gdb_assert (data->cr0_regnum != -1);
+ /* CR0 elements are 4 byte wide. */
+ gdb_assert (regsize + 8 <= register_size (arch, data->cr0_regnum));
+
+ return pseudo_from_raw_part (next_frame, pseudo_regnum,
+ data->cr0_regnum, 8);
+ }
+
+ return nullptr;
+}
+
+/* Write the value of a pseudo-register REGNUM. */
+
+static void
+intelgt_pseudo_register_write (gdbarch *arch,
+ const frame_info_ptr &next_frame,
+ int pseudo_regnum,
+ gdb::array_view<const gdb_byte> buf)
+{
+ const char *name = intelgt_pseudo_register_name (arch, pseudo_regnum);
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+
+ if (strcmp (name, "framedesc") == 0)
+ {
+ int grf_num = data->framedesc_base_regnum ();
+ int grf_size = register_size (arch, grf_num);
+ int desc_size = register_size (arch, pseudo_regnum);
+ gdb_assert (grf_size >= desc_size);
+ pseudo_to_raw_part (next_frame, buf, grf_num, 0);
+ }
+ else if (strcmp (name, "ip") == 0)
+ {
+ /* Instruction pointer is stored in CR0.2. */
+ gdb_assert (data->cr0_regnum != -1);
+ int cr0_size = register_size (arch, data->cr0_regnum);
+
+ /* CR0 elements are 4 byte wide. */
+ int reg_size = register_size (arch, pseudo_regnum);
+ gdb_assert (reg_size + 8 <= cr0_size);
+ pseudo_to_raw_part (next_frame, buf, data->cr0_regnum, 8);
+ }
+ else
+ error ("Pseudo-register %s is read-only", name);
+}
+
+/* Called by tdesc_use_registers each time a new regnum
+ is assigned. Used to track down assigned numbers for
+ any important regnums. */
+
+static int
+intelgt_unknown_register_cb (gdbarch *arch, tdesc_feature *feature,
+ const char *reg_name, int possible_regnum)
+{
+ intelgt_gdbarch_tdep *data = gdbarch_tdep<intelgt_gdbarch_tdep> (arch);
+
+ /* First, check if this a beginning of a not yet tracked regset
+ assignment. */
+
+ for (int regset = 0; regset < intelgt::REGSET_COUNT; ++regset)
+ {
+ if (data->regset_ranges[regset].start == -1
+ && feature->name == intelgt::DWARF_REGSET_FEATURES[regset])
+ {
+ data->regset_ranges[regset].start = possible_regnum;
+ data->regset_ranges[regset].end
+ = feature->registers.size () + possible_regnum;
+ break;
+ }
+ }
+
+ /* Second, check if it is any specific individual register that
+ needs to be tracked. */
+
+ if (strcmp ("r0", reg_name) == 0)
+ data->r0_regnum = possible_regnum;
+ else if (strcmp ("r26", reg_name) == 0)
+ data->retval_regnum = possible_regnum;
+ else if (strcmp ("cr0", reg_name) == 0)
+ data->cr0_regnum = possible_regnum;
+ else if (strcmp ("sr0", reg_name) == 0)
+ data->sr0_regnum = possible_regnum;
+ else if (strcmp ("isabase", reg_name) == 0)
+ data->isabase_regnum = possible_regnum;
+ else if (strcmp ("ce", reg_name) == 0)
+ data->ce_regnum = possible_regnum;
+ else if (strcmp ("genstbase", reg_name) == 0)
+ data->genstbase_regnum = possible_regnum;
+ else if (strcmp ("dbg0", reg_name) == 0)
+ data->dbg0_regnum = possible_regnum;
+
+ return possible_regnum;
+}
+
+/* Architecture initialization. */
+
+static gdbarch *
+intelgt_gdbarch_init (gdbarch_info info, gdbarch_list *arches)
+{
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != nullptr)
+ return arches->gdbarch;
+
+ const target_desc *tdesc = info.target_desc;
+ gdbarch_up gdbarch_u
+ (gdbarch_alloc (&info,
+ gdbarch_tdep_up (new intelgt_gdbarch_tdep)));
+ gdbarch *gdbarch = gdbarch_u.get ();
+ intelgt_gdbarch_tdep *data
+ = gdbarch_tdep<intelgt_gdbarch_tdep> (gdbarch);
+
+ /* Initialize register info. */
+ set_gdbarch_num_regs (gdbarch, 0);
+ set_gdbarch_register_name (gdbarch, tdesc_register_name);
+
+ if (tdesc_has_registers (tdesc))
+ {
+ tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
+
+ /* First assign register numbers to all registers. The
+ callback function will record any relevant metadata
+ about it in the intelgt_gdbarch_data instance to be
+ inspected after. */
+
+ tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data),
+ intelgt_unknown_register_cb);
+
+ /* Now check the collected metadata to ensure that all
+ mandatory pieces are in place. */
+
+ if (data->ce_regnum == -1)
+ error (_("Debugging requires $ce provided by the target"));
+ if (data->retval_regnum == -1)
+ error (_("Debugging requires return value register to be provided "
+ "by the target"));
+ if (data->cr0_regnum == -1)
+ error (_("Debugging requires control register to be provided by "
+ "the target"));
+ if (data->sr0_regnum == -1)
+ error (_("Debugging requires state register to be provided by "
+ "the target"));
+
+ /* Unconditionally enabled pseudo-registers: */
+ data->enabled_pseudo_regs.push_back ("ip");
+ data->enabled_pseudo_regs.push_back ("framedesc");
+
+ set_gdbarch_num_pseudo_regs (gdbarch, data->enabled_pseudo_regs.size ());
+ set_gdbarch_pseudo_register_read_value (
+ gdbarch, intelgt_pseudo_register_read_value);
+ set_gdbarch_pseudo_register_write (gdbarch,
+ intelgt_pseudo_register_write);
+ set_tdesc_pseudo_register_type (gdbarch, intelgt_pseudo_register_type);
+ set_tdesc_pseudo_register_name (gdbarch, intelgt_pseudo_register_name);
+ set_gdbarch_read_pc (gdbarch, intelgt_read_pc);
+ set_gdbarch_write_pc (gdbarch, intelgt_write_pc);
+ }
+
+ /* Populate gdbarch fields. */
+ set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_addr_bit (gdbarch, 64);
+ set_gdbarch_long_bit (gdbarch, 64);
+
+ set_gdbarch_register_type (gdbarch, tdesc_register_type);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, intelgt_dwarf_reg_to_regnum);
+
+ set_gdbarch_skip_prologue (gdbarch, intelgt_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
+ set_gdbarch_unwind_pc (gdbarch, intelgt_unwind_pc);
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &intelgt_frame_unwind);
+
+ set_gdbarch_return_value_as_value (gdbarch, intelgt_return_value_as_value);
+
+ set_gdbarch_memory_insert_breakpoint (gdbarch,
+ intelgt_memory_insert_breakpoint);
+ set_gdbarch_memory_remove_breakpoint (gdbarch,
+ intelgt_memory_remove_breakpoint);
+ set_gdbarch_program_breakpoint_here_p (gdbarch,
+ intelgt_program_breakpoint_here_p);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch,
+ intelgt_breakpoint_kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch,
+ intelgt_sw_breakpoint_from_kind);
+ dwarf2_frame_set_init_reg (gdbarch, intelgt_init_reg);
+
+ /* Disassembly. */
+ set_gdbarch_print_insn (gdbarch, intelgt_print_insn);
+
+ return gdbarch_u.release ();
+}
+
+static void
+show_intelgt_debug (ui_file *file, int from_tty,
+ cmd_list_element *c, const char *value)
+{
+ gdb_printf (file, _("Intel(R) Graphics Technology debugging is "
+ "%s.\n"), value);
+}
+
+INIT_GDB_FILE (intelgt_tdep)
+{
+ gdbarch_register (bfd_arch_intelgt, intelgt_gdbarch_init);
+
+ /* Debugging flag. */
+ add_setshow_boolean_cmd ("intelgt", class_maintenance, &intelgt_debug,
+ _("Set Intel(R) Graphics Technology debugging."),
+ _("Show Intel(R) Graphics Technology debugging."),
+ _("When on, Intel(R) Graphics Technology "
+ "debugging is enabled."),
+ nullptr,
+ show_intelgt_debug,
+ &setdebuglist, &showdebuglist);
+}
diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c
index 452258c0eb9a1346222477ae682b712f45d00729..1cbb065e5811e16c746d2d0061321b2fbdf5b3ea 100644
--- a/gdb/selftest-arch.c
+++ b/gdb/selftest-arch.c
@@ -122,9 +122,13 @@ selftest_skip_warning_arch (struct gdbarch *gdbarch)
Stack backtrace will not work.
We could instead capture the output and then filter out the warning, but
that seems more trouble than it's worth. */
+ /* The 'intelgt' arch populates the register sets dynamically based on
+ what the target reports. With no target description, the register
+ file is empty. */
return (strcmp (name, "m68hc11") == 0
|| strcmp (name, "m68hc12") == 0
- || strcmp (name, "m68hc12:HCS12") == 0);
+ || strcmp (name, "m68hc12:HCS12") == 0
+ || strcmp (name, "intelgt") == 0);
}
} /* namespace selftests */
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
next prev parent reply other threads:[~2025-08-01 9:45 UTC|newest]
Thread overview: 92+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-01 9:37 [PATCH v3 00/44] A new target to debug Intel GPUs Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 01/44] gdb, intelgt: add intelgt as a basic machine Tankut Baris Aktemur
2025-12-09 20:44 ` Simon Marchi
2025-12-19 11:13 ` Aktemur, Tankut Baris
2025-08-01 9:37 ` [PATCH v3 02/44] bfd: add intelgt target to BFD Tankut Baris Aktemur
2025-08-01 12:20 ` Jan Beulich
2025-08-08 5:03 ` Metzger, Markus T
2025-12-09 21:05 ` Simon Marchi
2025-12-19 12:46 ` Aktemur, Tankut Baris
2025-08-01 9:37 ` [PATCH v3 03/44] ld: add intelgt as a target configuration Tankut Baris Aktemur
2025-08-01 12:06 ` Jan Beulich
2025-08-08 5:03 ` Metzger, Markus T
2025-08-01 9:37 ` [PATCH v3 04/44] opcodes: add intelgt as a configuration Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 05/44] gdb, gdbserver, gdbsupport: add 'device' tag to XML target description Tankut Baris Aktemur
2025-12-09 21:27 ` Simon Marchi
2025-12-15 21:03 ` Simon Marchi
2025-12-18 15:04 ` Aktemur, Tankut Baris
2026-01-09 19:12 ` Aktemur, Tankut Baris
2026-01-09 19:34 ` Simon Marchi
2025-08-01 9:37 ` [PATCH v3 06/44] gdb, arch, intelgt: add intelgt arch definitions Tankut Baris Aktemur
2025-12-09 21:48 ` Simon Marchi
2025-12-16 15:47 ` Metzger, Markus T
2025-08-01 9:37 ` Tankut Baris Aktemur [this message]
2025-12-11 18:53 ` [PATCH v3 07/44] gdb, intelgt: add the target-dependent definitions for the Intel GT architecture Simon Marchi
2025-12-19 16:01 ` Aktemur, Tankut Baris
2025-08-01 9:37 ` [PATCH v3 08/44] gdb, intelgt: add disassemble feature " Tankut Baris Aktemur
2025-12-11 19:37 ` Simon Marchi
2025-12-23 11:03 ` Aktemur, Tankut Baris
2025-08-01 9:37 ` [PATCH v3 09/44] gdb, gdbserver, ze: in-memory libraries Tankut Baris Aktemur
2025-12-12 4:13 ` Simon Marchi
2025-12-12 11:20 ` Metzger, Markus T
2025-12-12 19:34 ` Simon Marchi
2025-12-15 13:07 ` Metzger, Markus T
2025-12-15 21:25 ` Simon Marchi
2025-08-01 9:37 ` [PATCH v3 10/44] gdb, gdbserver, rsp, ze: acknowledge libraries Tankut Baris Aktemur
2025-12-12 4:41 ` Simon Marchi
2025-12-12 14:28 ` Metzger, Markus T
2025-08-01 9:37 ` [PATCH v3 11/44] gdb, solib, ze: update target_solib_ops::bfd_open_from_target_memory Tankut Baris Aktemur
2025-12-12 4:43 ` Simon Marchi
2025-12-12 14:33 ` Metzger, Markus T
2025-08-01 9:37 ` [PATCH v3 12/44] gdb, infrun, ze: allow saving process events Tankut Baris Aktemur
2025-12-12 4:57 ` Simon Marchi
2025-12-15 13:13 ` Metzger, Markus T
2025-12-16 21:10 ` Simon Marchi
2025-12-17 9:30 ` Metzger, Markus T
2025-12-17 20:44 ` Simon Marchi
2025-12-18 7:20 ` Metzger, Markus T
2025-08-01 9:37 ` [PATCH v3 13/44] gdb, ze: add TARGET_WAITKIND_UNAVAILABLE Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 14/44] gdb, infrun, ze: handle stopping unavailable threads Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 15/44] gdb, infrun, ze: allow resuming " Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 16/44] gdb, gdbserver, ze: add U stop reply Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 17/44] gdb, gdbserver, ze: add library notification to " Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 18/44] gdbserver, ze: report TARGET_WAITKIND_UNAVAILABLE events Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 19/44] gdb, ze: handle TARGET_WAITKIND_UNAVAILABLE in stop_all_threads Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 20/44] gdb, remote: handle thread unavailability in print_one_stopped_thread Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 21/44] gdb, remote: do 'remote_add_inferior' in 'remote_notice_new_inferior' earlier Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 22/44] gdb, remote: handle a generic process PID in remote_notice_new_inferior Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 23/44] gdb, remote: handle a generic process PID in process_stop_reply Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 24/44] gdb: use the pid from inferior in setup_inferior Tankut Baris Aktemur
2025-12-12 19:51 ` Simon Marchi
2025-12-13 12:40 ` Aktemur, Tankut Baris
2025-08-01 9:37 ` [PATCH v3 25/44] gdb: revise the pid_to_exec_file target op Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 26/44] gdb: load solibs if the target does not have the notion of an exec file Tankut Baris Aktemur
2025-12-12 20:30 ` Simon Marchi
2026-01-09 19:10 ` Aktemur, Tankut Baris
2025-08-01 9:37 ` [PATCH v3 27/44] gdbserver: import AC_LIB_HAVE_LINKFLAGS macro into the autoconf script Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 28/44] gdbserver: add a pointer to the owner thread in regcache Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 29/44] gdbserver: wait for stopped threads in queue_stop_reply_callback Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 30/44] gdbserver: adjust pid after the target attaches Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 31/44] gdb: do not create a thread after a process event Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 32/44] gdb, ze: on a whole process stop, mark all threads as not_resumed Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 33/44] gdb, dwarf, ze: add DW_OP_INTEL_regval_bits Tankut Baris Aktemur
2025-08-01 12:02 ` Jan Beulich
2025-08-01 12:31 ` Metzger, Markus T
2025-08-01 12:50 ` Jan Beulich
2025-08-08 5:25 ` Metzger, Markus T
2025-08-01 9:37 ` [PATCH v3 34/44] gdbserver: allow configuring for a heterogeneous target Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 35/44] gdbserver, ze, intelgt: introduce ze-low and intel-ze-low targets Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 36/44] testsuite, sycl: add SYCL support Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 37/44] testsuite, sycl: add test for backtracing inside a kernel Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 38/44] testsuite, sycl: add test for 'info locals' and 'info args' Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 39/44] testsuite, sycl: add tests for stepping and accessing data elements Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 40/44] testsuite, sycl: add test for 1-D and 2-D parallel_for kernels Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 41/44] testsuite, sycl: add test for scheduler-locking Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 42/44] testsuite, arch, intelgt: add a disassembly test Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 43/44] testsuite, arch, intelgt: add intelgt-program-bp.exp Tankut Baris Aktemur
2025-08-01 9:37 ` [PATCH v3 44/44] testsuite, sycl: test canceling a stepping flow Tankut Baris Aktemur
2025-09-17 12:43 ` [PATCH v3 00/44] A new target to debug Intel GPUs Aktemur, Tankut Baris
2025-10-14 6:34 ` Aktemur, Tankut Baris
2025-12-08 11:32 ` Aktemur, Tankut Baris
2025-12-09 21:30 ` Simon Marchi
2025-12-19 12:52 ` Aktemur, Tankut Baris
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250801-upstream-intelgt-mvp-v3-7-59ce0f87075b@intel.com \
--to=tankut.baris.aktemur@intel.com \
--cc=gdb-patches@sourceware.org \
--cc=markus.t.metzger@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox