Compare commits

...

8 Commits

Author SHA1 Message Date
Philipp Rudo
95368b12b2 Add S390 support for linux-kernel target
After implementing the new linux-kernel target and preparing s390-tdep.
It is now time to get everything to work.  Thus implement the hooks
required by the linux-kernel target and enable s390's privileged
registers.

gdb/ChangeLog:

	* s390-lk-tdep.h: New file.
	* s390-lk-tdep.c: New file.
	* Makefile.in (ALL_TARGET_OBS): Add s390-lk-tdep.o.
	(ALLDEPFILES): Add s390-lk-tdep.c.
	* s390-tdep.h: Define macros for address translation.
	* s390-tdep.c (s390-lk-tdep.h): New include.
	(s390_iterate_over_regset_sections): Enable privileged registers.
	(s390_core_read_description): Enable privileged registers.
	(s390_gdbarch_init): : Enable privileged registers and adjust.
2017-02-07 16:25:55 +01:00
Philipp Rudo
654305d228 Add privileged registers for s390x
The Linux kernel and thus the linux-kernel target needs access to S390x's
privileged registers. Define new features and prepare s390-tdep.* to use
them in new Linux kernel code.

gdb/ChangeLog:

	* features/s390-cr.xml: New file.
	* features/s390x-cr-linux64.xml: New file
	* features/s390x-vxcr-linux64.xml: New file
	* features/Makefile: Add s390x-cr-linux64-expedite and
	s390x-vxcr-linux64-expedite
	(WICH): Add s390x-cr-linux64.xml and s390x-vxcr-linux64.xml
	(XMLTOC): Add s390x-cr-linux64.xml and s390x-vxcr-linux64.xml
	* features/s390x-cr-linux64.c: Generated.
	* features/s390x-vxcr-linux64.c: Generated.
	* regformats/s390x-cr-linux64.dat: Generated.
	* regformats/s390x-vxcr-linux64.dat: Generated.
	* s390-tdep.h: Define regnums for control registers.
	(S390_NUM_REGS): Adjust.
	* s390-tdep.c: (s390_dwarf_regmat): Add control registers.
2017-02-07 16:25:55 +01:00
Philipp Rudo
368915f5f1 Seperate common s390-tdep.* from s390-linux-tdep.*
The new linux-kernel target need some architecture dependant code.  To
prepare for this split up the existing s390 code into a general s390-tedep
and a GDNU/Linux (user space) specific s390-linux-tdep.  This keeps the
files manageable and allows for kernel specific code e.g. unwinder.

gdb/ChangeLog:

	* s390-tdep.h: New file.
	* s390-tdep.c: New file.
	* s390-linux-tdep.h: Move defines for hardware capabilities and
	register informations to s390-tdep.h.
	(s390_gdbarch_linux_init): New export.
	(s390_upper_registers): New export.
	* s390-linux-tdep.c: Remove unneeded includes and sort alphabetically.
	(s390-tdep.h): New include.
	(s390_upper_regset): Remove static.
	(s390_gdbarch_init): Rename to...
	(s390_gdbarch_linux_init): ...this and adjust.
	(_initialize_s390_tdep): Rename to...
	(_initialize_s390_linux_tdep): ...this and adjust.
	(s390_abi_kind, s390_vector_abi_kind): Move to s390-tdep.h
	(gdbarch_tdep, enum named opcodes): Move to s390-tdep.h
	(s390_readinstruction, is_ri, is_ril): Move to s390-tdep.c
	(is_rr, is_rre, is_rs, is_rsy, is_rsi, is_rie): Move to s390-tdep.c
	(is_rx, is_rxy, s390_break_insn): Move to s390-tdep.c
	(s390_breakpoint, s390_is_partial_instruction): Move to s390-tdep.c
	(s390_software_single_step, s390_prologue_data): Move to s390-tdep.c
	(s390_addr, s390_store, s390_load): Move to s390-tdep.c
	(s390_check_for_saved, s390_analyze_prologue): Move to s390-tdep.c
	(s390_skip_prologue, s390_register_call_saved): Move to s390-tdep.c
	(s390_register_name, s390_cannot_store_register): Move to s390-tdep.c
	(s390_write_pc, s390_dwarf_regmap): Move to s390-tdep.c
	(s390_dwarf_reg_to_regnum, regnum_is_gpr_full): Move to s390-tdep.c
	(regnum_is_vxr_full, s390_value_from_register): Move to s390-tdep.c
	(s390_core_read_description): Move to s390-tdep.c
	(s390_iterate_over_regset_sections): Move to s390-tdep.c
	(s390_pseudo_register_name): Move to s390-tdep.c
	(s390_pseudo_register_read): Move to s390-tdep.c
	(s390_pseudo_register_write): Move to s390-tdep.c
	(s390_pseudo_register_type): Move to s390-tdep.c
	(s390_pseudo_register_reggroup_p): Move to s390-tdep.c
	(s390_ax_pseudo_register_collect): Move to s390-tdep.c
	(s390_ax_pseudo_register_push_stack): Move to s390-tdep.c
	(s390_gen_return_address): Move to s390-tdep.c
	(s390_unwind_pseudo_register): Move to s390-tdep.c
	(s390_effective_inner_type): Move to s390-tdep.c
	(s390_function_arg_float): Move to s390-tdep.c
	(s390_function_arg_vector, is_power_of_two): Move to s390-tdep.c
	(s390_function_arg_integer, s390_arg_state): Move to s390-tdep.c
	(s390_handle_arg, s390_push_dummy_call): Move to s390-tdep.c
	(s390_dummy_id, s390_register_return_value): Move to s390-tdep.c
	(s390_return_value, s390_stack_frame_destroyed_p): Move to s390-tdep.c
	(s390_dwarf2_prev_register): Move to s390-tdep.c
	(s390_dwarf2_frame_init_reg): Move to s390-tdep.c
	(s390_adjust_frame_regnum, s390_unwind_cache): Move to s390-tdep.c
	(s390_prologue_frame_unwind_cache): Move to s390-tdep.c
	(s390_stub_unwind_cache): Move to s390-tdep.c
	(s390_stub_frame_unwind_cache): Move to s390-tdep.c
	(s390_stub_frame_this_id): Move to s390-tdep.c
	(s390_trad_frame_prev_register): Move to s390-tdep.c
	(s390_stub_frame_prev_register): Move to s390-tdep.c
	(s390_stub_frame_sniffer, s390_stub_frame_unwind): Move to s390-tdep.c
	(s390_sigtramp_unwind_cache): Move to s390-tdep.c
	(s390_sigtramp_frame_unwind_cache): Move to s390-tdep.c
	(s390_sigtramp_frame_this_id): Move to s390-tdep.c
	(s390_sigtramp_frame_prev_register): Move to s390-tdep.c
	(s390_sigtramp_frame_sniffer): Move to s390-tdep.c
	(s390_sigtramp_frame_unwind): Move to s390-tdep.c
	(s390_backchain_frame_unwind_cache): Move to s390-tdep.c
	(s390_frame_unwind_cache, s390_frame_this_id): Move to s390-tdep.c
	(s390_frame_prev_register, s390_frame_unwind): Move to s390-tdep.c
	(s390_frame_base_address): Move to s390-tdep.c
	(s390_local_base_address, s390_frame_base): Move to s390-tdep.c
	(s390_unwind_pc, s390_unwind_sp): Move to s390-tdep.c
	(is_non_branch_ril): Move to s390-tdep.c
	(s390_displaced_step_copy_insn): Move to s390-tdep.c
	(s390_displaced_step_fixup): Move to s390-tdep.c
	(s390_displaced_step_hw_singlestep): Move to s390-tdep.c
	(s390_addr_bits_remove): Move to s390-tdep.c
	(s390_address_class_type_flags): Move to s390-tdep.c
	(s390_address_class_type_flags_to_name): Move to s390-tdep.c
	(s390_address_class_name_to_type_flags): Move to s390-tdep.c
2017-02-07 16:25:54 +01:00
Philipp Rudo
44098f3fb6 Add commands for linux-kernel target
This patch implements a "lsmod", "struct" and, "offset" command to work with
the new linux-kernel target. The commands are a handy byproduct from
development and crude hacks. I don't expect them to be accepted in the
current state.  Nevertheless there needs to be an discussion on how and
where (see gdb/python scrips in kernel sources) to implement them. So here
is the start for it.

gdb/Changelog:

    * lk-cmds.h: New file.
    * lk-cmds.c: New file.
    * lk-low.c: Include lk-cmds.h.
    (lk_try_push_target): Init commands.
    * typeprint.c: Remove unnecessary forward declarations.
    (whatis_exp): Remove static.
    * typeprint.h (whatis_exp): New export.
    * Makefile.in (SFILES, ALLDEPFILES): Add lk-cmds.c.
    (HFILES_NO_SRCDIR): Add lk-cmds.h.
    (COMMON_OBS): Add lk-cmds.o.
2017-02-07 16:25:54 +01:00
Philipp Rudo
fc83f37b41 Add kernel module support for linux-kernel target
This patch implements module support for the new linux-kernel target by
adding a target_so_ops. In addition this patch adds handling for kernel
virtual addresses. This is necessary because kernel modules, unlike
task_structs, live in kernel virtual address space. Thus addresses need
to be translated before they can be read from. We achieve this by adding
an implementation for the targets to_xfer_partial hook, which translates
the addresses before passing them down to the target beneath.

gdb/ChangeLog:

    * lk-modules.h: New file.
    * lk-modules.c: New file.
    * lk-low.h (lk_hook_is_kvaddr, lk_hook_vtop)
    (lk_hook_get_module_text_offset): New arch dependent hooks.
    (sturct lk_private_hooks): Add new hooks.
    (LK_MODULES_NAME_LEN, LK_UTS_NAME_LEN): New define.
    * lk-low.c (lk-modules.h): New include.
    (lk_kvtop, restore_current_target, lk_xfer_partial): New functions.
    (lk_init_private_data): Declare needed debug symbols.
    (lk_try_push_target): Assert for new hooks and set solib_ops.
    (init_linux_kernel_ops): Add implementation for to_xfer_partial.
    * solib.c (get_solib_search_path): New function.
    * solib.h (get_solib_search_path): New export.
    * Makefile.in (SFILES, ALLDEPFILES): Add lk-modules.c.
    (HFILES_NO_SRCDIR): Add lk-modules.h.
    (COMMON_OBS): Add lk-modules.o.
2017-02-07 16:25:54 +01:00
Philipp Rudo
757186093b Add basic Linux kernel support
This patch implements a basic target_ops for Linux kernel support. In
particular it models Linux tasks as GDB threads such that you are able to
change to a given thread, get backtraces, disassemble the current frame
etc..

Currently the target_ops is designed only to work with static targets, i.e.
dumps. Thus it lacks implementation for hooks like to_wait, to_resume or
to_store_registers. Furthermore the mapping between a CPU and the
task_struct of the running task is only be done once at initialization. See
cover letter for a detailed discussion.

Nevertheless i made some design decisions different to Peter [1] which are
worth discussing. Especially storing the private data in a htab (or
std::unordered_map if i had the time...) instead of global variables makes
the code much nicer and less memory consuming.

[1] https://sourceware.org/ml/gdb-patches/2016-12/msg00382.html

gdb/ChangeLog:

    * gdbarch.sh (lk_init_private): New hook.
    * gdbarch.h: Regenerated.
    * gdbarch.c: Regenerated.
    * lk-low.h: New file.
    * lk-low.c: New file.
    * lk-lists.h: New file.
    * lk-lists.c: New file.
    * Makefile.in (SFILES, ALLDEPFILES): Add lk-low.c and lk-lists.c.
    (HFILES_NO_SRCDIR): Add lk-low.h and lk-lists.h.
    (ALL_TARGET_OBS): Add lk-low.o
    (COMMON_OBS): Add lk-lists.o
2017-02-07 16:25:54 +01:00
Philipp Rudo
75d79af413 Add libiberty/concat styled concat_path function
This commit adds concat_path function to concatenate an arbitrary number of
    path elements.  The function automatically adds an directory separator between
    two elements as needed.

    gdb/ChangeLog:

	* common/common-utils.h (endswith): New function.
	* utils.c (_concat_path, approx_path_length): New function.
	* utils.h (_concat_path): New export.
	(concat_path): New define.
2017-02-07 16:25:53 +01:00
Philipp Rudo
c48c4ca231 Convert substitute_path_component to C++
Simplify the code of utils.c:substiute_path_component by converting it to C++.

gdb/ChangeLog:

	* utils.c (substitute_path_component): Convert to C++.
	* utils.h (substitute_path_componetn): Adjust declatation.
	* auto-load.c (auto_load_expand_dir_vars): Adjust.
2017-02-07 16:25:53 +01:00
35 changed files with 7080 additions and 3631 deletions

View File

@@ -805,6 +805,7 @@ ALL_TARGET_OBS = \
iq2000-tdep.o \
linux-record.o \
linux-tdep.o \
lk-low.o \
lm32-tdep.o \
m32c-tdep.o \
m32r-linux-tdep.o \
@@ -847,6 +848,8 @@ ALL_TARGET_OBS = \
rs6000-tdep.o \
rx-tdep.o \
s390-linux-tdep.o \
s390-lk-tdep.o \
s390-tdep.o \
score-tdep.o \
sh-linux-tdep.o \
sh-nbsd-tdep.o \
@@ -1092,6 +1095,10 @@ SFILES = \
jit.c \
language.c \
linespec.c \
lk-cmds.c \
lk-lists.c \
lk-low.c \
lk-modules.c \
location.c \
m2-exp.y \
m2-lang.c \
@@ -1339,6 +1346,10 @@ HFILES_NO_SRCDIR = \
linux-nat.h \
linux-record.h \
linux-tdep.h \
lk-cmds.h \
lk-lists.h \
lk-low.h \
lk-modules.h \
location.h \
m2-lang.h \
m32r-tdep.h \
@@ -1396,7 +1407,7 @@ HFILES_NO_SRCDIR = \
remote-notif.h \
rs6000-aix-tdep.h \
rs6000-tdep.h \
s390-linux-tdep.h \
s390-tdep.h \
score-tdep.h \
selftest-arch.h \
sentinel-frame.h \
@@ -1699,6 +1710,9 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
jit.o \
language.o \
linespec.o \
lk-cmds.o \
lk-lists.o \
lk-modules.o \
location.o \
m2-lang.o \
m2-typeprint.o \
@@ -2531,6 +2545,10 @@ ALLDEPFILES = \
linux-fork.c \
linux-record.c \
linux-tdep.c \
lk-cmds.c \
lk-lists.c \
lk-low.c \
lk-modules.c \
lm32-tdep.c \
m32r-linux-nat.c \
m32r-linux-tdep.c \
@@ -2586,6 +2604,8 @@ ALLDEPFILES = \
rx-tdep.c \
s390-linux-nat.c \
s390-linux-tdep.c \
s390-lk-tdep.c \
s390-tdep.c \
score-tdep.c \
ser-go32.c \
ser-mingw.c \

View File

@@ -40,6 +40,7 @@
#include "filestuff.h"
#include "extension.h"
#include "gdb/section-scripts.h"
#include <string>
/* The section to look in for auto-loaded scripts (in file formats that
support sections).
@@ -175,21 +176,20 @@ static VEC (char_ptr) *auto_load_safe_path_vec;
this vector must be freed by free_char_ptr_vec by the caller. */
static VEC (char_ptr) *
auto_load_expand_dir_vars (const char *string)
auto_load_expand_dir_vars (std::string orig)
{
VEC (char_ptr) *dir_vec;
char *s;
std::string str = orig;
s = xstrdup (string);
substitute_path_component (&s, "$datadir", gdb_datadir);
substitute_path_component (&s, "$debugdir", debug_file_directory);
substitute_path_component (str, "$datadir", gdb_datadir);
substitute_path_component (str, "$debugdir", debug_file_directory);
if (debug_auto_load && strcmp (s, string) != 0)
if (debug_auto_load && str.compare (orig) != 0)
fprintf_unfiltered (gdb_stdlog,
_("auto-load: Expanded $-variables to \"%s\".\n"), s);
_("auto-load: Expanded $-variables to \"%s\".\n"),
str.c_str ());
dir_vec = dirnames_to_char_ptr_vec (s);
xfree(s);
dir_vec = dirnames_to_char_ptr_vec (str.c_str ());
return dir_vec;
}

View File

@@ -83,6 +83,17 @@ startswith (const char *string, const char *pattern)
return strncmp (string, pattern, strlen (pattern)) == 0;
}
/* Return non-zero if the end of STRING matches PATTERN, zero
otherwise. */
static inline int
endswith (const char *string, const char *pattern)
{
return (strlen (string) > strlen (pattern)
&& strncmp (string + strlen (string) - strlen (pattern), pattern,
strlen (pattern)) == 0);
}
ULONGEST strtoulst (const char *num, const char **trailer, int base);
/* Skip leading whitespace characters in INP, returning an updated

View File

@@ -76,6 +76,7 @@ WHICH = aarch64 \
s390-linux32v2 s390-linux64v2 s390x-linux64v2 \
s390-te-linux64 s390x-te-linux64 s390-vx-linux64 s390x-vx-linux64 \
s390-tevx-linux64 s390x-tevx-linux64 \
s390x-cr-linux64 s390x-vxcr-linux64 \
tic6x-c64xp tic6x-c64x tic6x-c62x \
tic6x-c64xp-linux tic6x-c64x-linux tic6x-c62x-linux
@@ -109,6 +110,8 @@ s390x-linux64v2-expedite = r14,r15,pswa
s390x-te-linux64-expedite = r14,r15,pswa
s390x-vx-linux64-expedite = r14,r15,pswa
s390x-tevx-linux64-expedite = r14,r15,pswa
s390x-cr-linux64-expedite = r14,r15,pswa
s390x-vxcr-linux64-expedite = r14,r15,pswa
tic6x-c64xp-expedite = A15,PC
tic6x-c64x-expedite = A15,PC
tic6x-c62x-expedite = A15,PC
@@ -214,14 +217,16 @@ XMLTOC = \
s390-linux64v1.xml \
s390-linux64v2.xml \
s390-te-linux64.xml \
s390-vx-linux64.xml \
s390-tevx-linux64.xml \
s390x-linux64.xml \
s390x-linux64v1.xml \
s390x-linux64v2.xml \
s390x-te-linux64.xml \
s390-tevx-linux64.xml \
s390-vx-linux64.xml \
s390x-tevx-linux64.xml \
s390x-vx-linux64.xml \
s390x-cr-linux64.xml \
s390x-tevx-linux64.xml \
s390x-vxcr-linux64.xml \
tic6x-c62x-linux.xml \
tic6x-c62x.xml \
tic6x-c64x-linux.xml \

26
gdb/features/s390-cr.xml Normal file
View File

@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2016 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.s390.cr">
<reg name="cr0" bitsize="64" type="uint64" group="control"/>
<reg name="cr1" bitsize="64" type="uint64" group="control"/>
<reg name="cr2" bitsize="64" type="uint64" group="control"/>
<reg name="cr3" bitsize="64" type="uint64" group="control"/>
<reg name="cr4" bitsize="64" type="uint64" group="control"/>
<reg name="cr5" bitsize="64" type="uint64" group="control"/>
<reg name="cr6" bitsize="64" type="uint64" group="control"/>
<reg name="cr7" bitsize="64" type="uint64" group="control"/>
<reg name="cr8" bitsize="64" type="uint64" group="control"/>
<reg name="cr9" bitsize="64" type="uint64" group="control"/>
<reg name="cr10" bitsize="64" type="uint64" group="control"/>
<reg name="cr11" bitsize="64" type="uint64" group="control"/>
<reg name="cr12" bitsize="64" type="uint64" group="control"/>
<reg name="cr13" bitsize="64" type="uint64" group="control"/>
<reg name="cr14" bitsize="64" type="uint64" group="control"/>
<reg name="cr15" bitsize="64" type="uint64" group="control"/>
</feature>

View File

@@ -0,0 +1,99 @@
/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
Original: s390x-cr-linux64.xml */
#include "defs.h"
#include "osabi.h"
#include "target-descriptions.h"
struct target_desc *tdesc_s390x_cr_linux64;
static void
initialize_tdesc_s390x_cr_linux64 (void)
{
struct target_desc *result = allocate_target_description ();
struct tdesc_feature *feature;
set_tdesc_architecture (result, bfd_scan_arch ("s390:64-bit"));
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core");
tdesc_create_reg (feature, "pswm", 0, 1, "psw", 64, "uint64");
tdesc_create_reg (feature, "pswa", 1, 1, "psw", 64, "uint64");
tdesc_create_reg (feature, "r0", 2, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r1", 3, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r2", 4, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r3", 5, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r4", 6, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r5", 7, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r6", 8, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r7", 9, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r8", 10, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r9", 11, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r10", 12, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r11", 13, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r12", 14, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r13", 15, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r14", 16, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r15", 17, 1, "general", 64, "uint64");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.acr");
tdesc_create_reg (feature, "acr0", 18, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr1", 19, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr2", 20, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr3", 21, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr4", 22, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr5", 23, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr6", 24, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr7", 25, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr8", 26, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr9", 27, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr10", 28, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr11", 29, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr12", 30, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr13", 31, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr14", 32, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr15", 33, 1, "access", 32, "uint32");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.fpr");
tdesc_create_reg (feature, "fpc", 34, 1, "float", 32, "uint32");
tdesc_create_reg (feature, "f0", 35, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f1", 36, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f2", 37, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f3", 38, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f4", 39, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f5", 40, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f6", 41, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f7", 42, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f8", 43, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f9", 44, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f10", 45, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f11", 46, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f12", 47, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f13", 48, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f14", 49, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f15", 50, 1, "float", 64, "ieee_double");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.cr");
tdesc_create_reg (feature, "cr0", 51, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr1", 52, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr2", 53, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr3", 54, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr4", 55, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr5", 56, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr6", 57, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr7", 58, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr8", 59, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr9", 60, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr10", 61, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr11", 62, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr12", 63, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr13", 64, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr14", 65, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr15", 66, 1, "control", 64, "uint64");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.privileged");
tdesc_create_reg (feature, "timer", 67, 1, "system", 64, "uint64");
tdesc_create_reg (feature, "todcmp", 68, 1, "system", 64, "uint64");
tdesc_create_reg (feature, "todpreg", 69, 1, "system", 32, "uint32");
tdesc_create_reg (feature, "prefix", 70, 1, "system", 32, "uint32");
tdesc_s390x_cr_linux64 = result;
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2016 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!-- S/390 64-bit kernel-level code. -->
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>s390:64-bit</architecture>
<xi:include href="s390x-core64.xml"/>
<xi:include href="s390-acr.xml"/>
<xi:include href="s390-fpr.xml"/>
<xi:include href="s390-cr.xml"/>
<feature name="org.gnu.gdb.s390.privileged">
<reg name="timer" bitsize="64" type="uint64" group="system"/>
<reg name="todcmp" bitsize="64" type="uint64" group="system"/>
<reg name="todpreg" bitsize="32" type="uint32" group="system"/>
<reg name="prefix" bitsize="32" type="uint32" group="system"/>
</feature>
</target>

View File

@@ -0,0 +1,169 @@
/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
Original: s390x-vxcr-linux64.xml */
#include "defs.h"
#include "osabi.h"
#include "target-descriptions.h"
struct target_desc *tdesc_s390x_vxcr_linux64;
static void
initialize_tdesc_s390x_vxcr_linux64 (void)
{
struct target_desc *result = allocate_target_description ();
struct tdesc_feature *feature;
struct tdesc_type *field_type;
struct tdesc_type *type;
set_tdesc_architecture (result, bfd_scan_arch ("s390:64-bit"));
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core");
tdesc_create_reg (feature, "pswm", 0, 1, "psw", 64, "uint64");
tdesc_create_reg (feature, "pswa", 1, 1, "psw", 64, "uint64");
tdesc_create_reg (feature, "r0", 2, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r1", 3, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r2", 4, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r3", 5, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r4", 6, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r5", 7, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r6", 8, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r7", 9, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r8", 10, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r9", 11, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r10", 12, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r11", 13, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r12", 14, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r13", 15, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r14", 16, 1, "general", 64, "uint64");
tdesc_create_reg (feature, "r15", 17, 1, "general", 64, "uint64");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.acr");
tdesc_create_reg (feature, "acr0", 18, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr1", 19, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr2", 20, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr3", 21, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr4", 22, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr5", 23, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr6", 24, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr7", 25, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr8", 26, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr9", 27, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr10", 28, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr11", 29, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr12", 30, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr13", 31, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr14", 32, 1, "access", 32, "uint32");
tdesc_create_reg (feature, "acr15", 33, 1, "access", 32, "uint32");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.fpr");
tdesc_create_reg (feature, "fpc", 34, 1, "float", 32, "uint32");
tdesc_create_reg (feature, "f0", 35, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f1", 36, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f2", 37, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f3", 38, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f4", 39, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f5", 40, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f6", 41, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f7", 42, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f8", 43, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f9", 44, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f10", 45, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f11", 46, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f12", 47, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f13", 48, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f14", 49, 1, "float", 64, "ieee_double");
tdesc_create_reg (feature, "f15", 50, 1, "float", 64, "ieee_double");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.vx");
field_type = tdesc_named_type (feature, "ieee_single");
tdesc_create_vector (feature, "v4f", field_type, 4);
field_type = tdesc_named_type (feature, "ieee_double");
tdesc_create_vector (feature, "v2d", field_type, 2);
field_type = tdesc_named_type (feature, "int8");
tdesc_create_vector (feature, "v16i8", field_type, 16);
field_type = tdesc_named_type (feature, "int16");
tdesc_create_vector (feature, "v8i16", field_type, 8);
field_type = tdesc_named_type (feature, "int32");
tdesc_create_vector (feature, "v4i32", field_type, 4);
field_type = tdesc_named_type (feature, "int64");
tdesc_create_vector (feature, "v2i64", field_type, 2);
type = tdesc_create_union (feature, "vec128");
field_type = tdesc_named_type (feature, "v4f");
tdesc_add_field (type, "v4_float", field_type);
field_type = tdesc_named_type (feature, "v2d");
tdesc_add_field (type, "v2_double", field_type);
field_type = tdesc_named_type (feature, "v16i8");
tdesc_add_field (type, "v16_int8", field_type);
field_type = tdesc_named_type (feature, "v8i16");
tdesc_add_field (type, "v8_int16", field_type);
field_type = tdesc_named_type (feature, "v4i32");
tdesc_add_field (type, "v4_int32", field_type);
field_type = tdesc_named_type (feature, "v2i64");
tdesc_add_field (type, "v2_int64", field_type);
field_type = tdesc_named_type (feature, "uint128");
tdesc_add_field (type, "uint128", field_type);
tdesc_create_reg (feature, "v0l", 51, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v1l", 52, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v2l", 53, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v3l", 54, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v4l", 55, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v5l", 56, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v6l", 57, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v7l", 58, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v8l", 59, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v9l", 60, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v10l", 61, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v11l", 62, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v12l", 63, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v13l", 64, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v14l", 65, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v15l", 66, 1, NULL, 64, "uint64");
tdesc_create_reg (feature, "v16", 67, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v17", 68, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v18", 69, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v19", 70, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v20", 71, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v21", 72, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v22", 73, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v23", 74, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v24", 75, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v25", 76, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v26", 77, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v27", 78, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v28", 79, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v29", 80, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v30", 81, 1, NULL, 128, "vec128");
tdesc_create_reg (feature, "v31", 82, 1, NULL, 128, "vec128");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.cr");
tdesc_create_reg (feature, "cr0", 83, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr1", 84, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr2", 85, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr3", 86, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr4", 87, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr5", 88, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr6", 89, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr7", 90, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr8", 91, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr9", 92, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr10", 93, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr11", 94, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr12", 95, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr13", 96, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr14", 97, 1, "control", 64, "uint64");
tdesc_create_reg (feature, "cr15", 98, 1, "control", 64, "uint64");
feature = tdesc_create_feature (result, "org.gnu.gdb.s390.privileged");
tdesc_create_reg (feature, "timer", 99, 1, "system", 64, "uint64");
tdesc_create_reg (feature, "todcmp", 100, 1, "system", 64, "uint64");
tdesc_create_reg (feature, "todpreg", 101, 1, "system", 32, "uint32");
tdesc_create_reg (feature, "prefix", 102, 1, "system", 32, "uint32");
tdesc_s390x_vxcr_linux64 = result;
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2016 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!-- S/390 64-bit kernel-level code. -->
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>s390:64-bit</architecture>
<xi:include href="s390x-core64.xml"/>
<xi:include href="s390-acr.xml"/>
<xi:include href="s390-fpr.xml"/>
<xi:include href="s390-vx.xml"/>
<xi:include href="s390-cr.xml"/>
<feature name="org.gnu.gdb.s390.privileged">
<reg name="timer" bitsize="64" type="uint64" group="system"/>
<reg name="todcmp" bitsize="64" type="uint64" group="system"/>
<reg name="todpreg" bitsize="32" type="uint32" group="system"/>
<reg name="prefix" bitsize="32" type="uint32" group="system"/>
</feature>
</target>

View File

@@ -339,6 +339,7 @@ struct gdbarch
gdbarch_gcc_target_options_ftype *gcc_target_options;
gdbarch_gnu_triplet_regexp_ftype *gnu_triplet_regexp;
gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size;
gdbarch_lk_init_private_ftype *lk_init_private;
};
/* Create a new ``struct gdbarch'' based on information provided by
@@ -1123,6 +1124,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: iterate_over_regset_sections = <%s>\n",
host_address_to_string (gdbarch->iterate_over_regset_sections));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_lk_init_private_p() = %d\n",
gdbarch_lk_init_private_p (gdbarch));
fprintf_unfiltered (file,
"gdbarch_dump: lk_init_private = <%s>\n",
host_address_to_string (gdbarch->lk_init_private));
fprintf_unfiltered (file,
"gdbarch_dump: long_bit = %s\n",
plongest (gdbarch->long_bit));
@@ -4956,6 +4963,30 @@ set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch,
gdbarch->addressable_memory_unit_size = addressable_memory_unit_size;
}
int
gdbarch_lk_init_private_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
return gdbarch->lk_init_private != NULL;
}
void
gdbarch_lk_init_private (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->lk_init_private != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_lk_init_private called\n");
gdbarch->lk_init_private (gdbarch);
}
void
set_gdbarch_lk_init_private (struct gdbarch *gdbarch,
gdbarch_lk_init_private_ftype lk_init_private)
{
gdbarch->lk_init_private = lk_init_private;
}
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */

View File

@@ -1545,6 +1545,14 @@ typedef int (gdbarch_addressable_memory_unit_size_ftype) (struct gdbarch *gdbarc
extern int gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch);
extern void set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch, gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size);
/* Initiate architecture dependent private data for the linux-kernel target. */
extern int gdbarch_lk_init_private_p (struct gdbarch *gdbarch);
typedef void (gdbarch_lk_init_private_ftype) (struct gdbarch *gdbarch);
extern void gdbarch_lk_init_private (struct gdbarch *gdbarch);
extern void set_gdbarch_lk_init_private (struct gdbarch *gdbarch, gdbarch_lk_init_private_ftype *lk_init_private);
/* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1)

View File

@@ -1163,6 +1163,10 @@ m:const char *:gnu_triplet_regexp:void:::default_gnu_triplet_regexp::0
# each address in memory.
m:int:addressable_memory_unit_size:void:::default_addressable_memory_unit_size::0
# Initialize architecture dependent private data for the linux-kernel
# target.
M:void:lk_init_private:void:
EOF
}

253
gdb/lk-cmds.c Normal file
View File

@@ -0,0 +1,253 @@
/* Commands for Linux kernel target.
Copyright (C) 2016 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 "defs.h"
#include "cli/cli-decode.h"
#include "gdbcore.h"
#include "inferior.h"
#include "lk-lists.h"
#include "lk-low.h"
#include "lk-modules.h"
#include "typeprint.h"
#include "valprint.h"
/* Print line for module MOD to UIOUT for lsmod command. */
static bool
lk_lsmod_print_single_module (struct ui_out *uiout, CORE_ADDR mod)
{
char *src_list, name[LK_MODULE_NAME_LEN + 2];
CORE_ADDR next, src_list_addr;
size_t src_num, src_size, list_len;
bool loaded;
struct cleanup *ui_chain;
/* Get name. */
read_memory_string (mod + LK_OFFSET (module, name), name + 1,
LK_MODULE_NAME_LEN);
loaded = lk_modules_debug_info_loaded (name + 1);
name[0] = loaded ? ' ' : '*' ;
name[LK_MODULE_NAME_LEN + 1] = '\0';
/* Get size. */
if (LK_FIELD (module, module_core))
{
src_size = lk_read_uint (mod + LK_OFFSET (module, init_size));
src_size += lk_read_uint (mod + LK_OFFSET (module, core_size));
}
else
{
src_size = lk_read_uint (mod + LK_OFFSET (module, init_layout)
+ LK_OFFSET (module_layout, size));
src_size += lk_read_uint (mod + LK_OFFSET (module, core_layout)
+ LK_OFFSET (module_layout, size));
}
/* Get number of sources and list of their names. */
src_num = 0;
src_list_addr = mod + LK_OFFSET (module, source_list);
src_list = xstrdup ("");
list_len = 0;
lk_list_for_each (next, src_list_addr, module, source_list)
{
char src_name[LK_MODULE_NAME_LEN + 1];
CORE_ADDR src_mod, src_addr;
src_addr = (LK_CONTAINER_OF (next, module_use, source_list)
+ LK_OFFSET (module_use, source));
src_mod = lk_read_addr (src_addr);
read_memory_string (src_mod + LK_OFFSET (module, name), src_name,
LK_MODULE_NAME_LEN);
/* 2 = strlen (", "). */
list_len += strlen (src_name) + 2;
src_list = reconcat (src_list, src_list, src_name, ", ", NULL);
src_num++;
}
make_cleanup (xfree, src_list);
/* Remove trailing comma. */
if (strlen (src_list) >= 2)
src_list [list_len - 2] = '\0';
ui_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
uiout->field_fmt ("addr", "0x%s",
phex(mod, lk_builtin_type_size (unsigned_long)));
uiout->field_string ("module", name);
uiout->field_int ("size", src_size);
uiout->field_int ("src_num", src_num);
uiout->field_string ("src_list", src_list);
uiout->text ("\n");
do_cleanups (ui_chain);
return loaded;
}
/* Print information about loaded kernel modules. Output equivalent to
lsmod, but also prints the address of the corrensponfing struct module.
Marks modules with missing debug info with an asterix '*'. */
void
lk_lsmod (char *args, int from_tty)
{
struct ui_out *uiout;
struct cleanup *ui_chain;
CORE_ADDR modules, next;
bool all_loaded = true;
uiout = current_uiout;
ui_chain = make_cleanup_ui_out_table_begin_end (uiout, 5, -1,
"ModuleTable");
uiout->table_header (14, ui_left, "addr", "ADDR");
uiout->table_header (20, ui_left, "module", "Module");
uiout->table_header (7, ui_right, "size", "Size");
uiout->table_header (4, ui_right, "src_num", "");
uiout->table_header (40, ui_left, "src_list", "Used by");
uiout->table_body ();
modules = LK_ADDR (modules);
lk_list_for_each (next, modules, module, list)
{
CORE_ADDR mod;
mod = LK_CONTAINER_OF (next, module, list);
all_loaded &= lk_lsmod_print_single_module (uiout, mod);
}
if (!all_loaded)
uiout->text ("(*) Missing debug info for module.\n");
do_cleanups (ui_chain);
}
static void
lk_print_struct (char *args_, int from_tty)
{
struct format_data fmt;
size_t pos;
print_command_parse_format ((const char **) &args_, "print", &fmt);
if (!args_)
return;
std::string args (args_);
/* No address given default to behave like ptype. */
if ((pos = args.find (" ")) == std::string::npos)
{
args = "struct " + args;
char *tmp = xstrdup (args.c_str ());
whatis_exp (tmp, 1);
xfree (tmp);
return;
}
std::string type = args.substr (0, pos);
std::string addr = args.substr (args.find_first_not_of (" ", pos));
if ((pos = type.find ("."))!= std::string::npos)
{
std::string field = type.substr (pos + 1);
type = type.substr (0, pos);
args = "((struct " + type + " *) " + addr + ")->" + field;
}
else if ((pos = type.find ("->"))!= std::string::npos)
{
std::string field = type.substr (pos + 2);
type = type.substr (0, pos);
args = "((struct " + type + " *) " + addr + ")->" + field;
}
else
args = "*(struct " + type + " *) " + addr;
expression_up expr = parse_expression (args.c_str ());
struct value *val = evaluate_expression (expr.get ());
print_value (val, &fmt);
}
#include "gdbtypes.h"
void
lk_print_offset (char *args_, int from_tty)
{
std::string args (args_);
std::string type, field;
size_t pos;
if ((pos = args.find ('.')) != std::string::npos)
{
type = "struct " + args.substr (0, pos);
field = args.substr (pos + 1);
}
else if ((pos = args.find ("->")) != std::string::npos)
{
type = "struct " + args.substr (0, pos);
field = args.substr (pos + 2);
}
else
return;
expression_up expr = parse_expression (type.c_str ());
struct type *tp = value_type (evaluate_type (expr.get ()));
struct field *first = TYPE_FIELDS (tp);
struct field *last = first + TYPE_NFIELDS (tp);
for (; first != last; first++)
if (field.compare (first->name) == 0)
break;
if (first == last)
return;
size_t offset = FIELD_BITPOS (*first);
if (offset % TARGET_CHAR_BIT)
printf_unfiltered ("offset = %lu + %lu\n", offset / 8, offset % TARGET_CHAR_BIT);
else
printf_unfiltered ("offset = %lu\n", offset / 8);
}
void
lk_init_cmds ()
{
add_com ("lsmod", class_vars, lk_lsmod, "\n\
lsmod\n\n\
List kernel modules as known by the kernel. The address belongs to the \
corresponding struct module. \
");
add_com ("struct", class_vars, lk_print_struct, "\n\
struct <struct>.<field> <address>\n\n\
Print content of field <field> in structure <struct> for structure located\n\
at address <address>. If no field is given prints entire content of\n\
<struct>. If neither <field> nor <address> is given prints type definition\n\
of <struct> (equivalent to ptype).\
");
add_com ("offset", class_vars, lk_print_offset, "\n\
offset <struct>.<field>\n\n\
Print offset of field <field> in structure <struct> in byte (+ bit for bit fields).\n\
");
}

25
gdb/lk-cmds.h Normal file
View File

@@ -0,0 +1,25 @@
/* Commands for Linux kernel target.
Copyright (C) 2016 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/>. */
#ifndef __LK_CMDS_H__
#define __LK_CMDS_H__
extern void lk_init_cmds ();
#endif /* __LK_CMDS_H__ */

47
gdb/lk-lists.c Normal file
View File

@@ -0,0 +1,47 @@
/* Iterators for internal data structures of the Linux kernel.
Copyright (C) 2016 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 "defs.h"
#include "inferior.h"
#include "lk-lists.h"
#include "lk-low.h"
/* Returns next entry from struct list_head CURR while iterating field
SNAME->FNAME. */
CORE_ADDR
lk_list_head_next (CORE_ADDR curr, const char *sname, const char *fname)
{
CORE_ADDR next, next_prev;
/* We must always assume that the data we handle is corrupted. Thus use
curr->next->prev == curr as sanity check. */
next = lk_read_addr (curr + LK_OFFSET (list_head, next));
next_prev = lk_read_addr (next + LK_OFFSET (list_head, prev));
if (!curr || curr != next_prev)
{
error (_("Memory corruption detected while iterating list_head at "\
"0x%s belonging to list %s->%s."),
phex (curr, lk_builtin_type_size (unsigned_long)) , sname, fname);
}
return next;
}

56
gdb/lk-lists.h Normal file
View File

@@ -0,0 +1,56 @@
/* Iterators for internal data structures of the Linux kernel.
Copyright (C) 2016 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/>. */
#ifndef __LK_LISTS_H__
#define __LK_LISTS_H__
extern CORE_ADDR lk_list_head_next (CORE_ADDR curr, const char *sname,
const char *fname);
/* Iterator over field SNAME->FNAME of type struct list_head starting at
address START of type struct list_head. This iterator is intended to be
used for lists initiated with macro LIST_HEAD (include/linux/list.h) in
the kernel, i.e. lists that START is a global variable of type struct
list_head and _not_ of type struct SNAME as the rest of the list. Thus
START will not be iterated over but only be used to start/terminate the
iteration. */
#define lk_list_for_each(next, start, sname, fname) \
for ((next) = lk_list_head_next ((start), #sname, #fname); \
(next) != (start); \
(next) = lk_list_head_next ((next), #sname, #fname))
/* Iterator over struct SNAME linked together via field SNAME->FNAME of type
struct list_head starting at address START of type struct SNAME. In
contrast to the iterator above, START is a "full" member of the list and
thus will be iterated over. */
#define lk_list_for_each_container(cont, start, sname, fname) \
CORE_ADDR _next; \
bool _first_loop = true; \
for ((cont) = (start), \
_next = (start) + LK_OFFSET (sname, fname); \
\
(cont) != (start) || _first_loop; \
\
_next = lk_list_head_next (_next, #sname, #fname), \
(cont) = LK_CONTAINER_OF (_next, sname, fname), \
_first_loop = false)
#endif /* __LK_LISTS_H__ */

964
gdb/lk-low.c Normal file
View File

@@ -0,0 +1,964 @@
/* Basic Linux kernel support, architecture independent.
Copyright (C) 2016 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 "defs.h"
#include "block.h"
#include "exceptions.h"
#include "frame.h"
#include "gdbarch.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "gdbtypes.h"
#include "inferior.h"
#include "lk-cmds.h"
#include "lk-lists.h"
#include "lk-low.h"
#include "lk-modules.h"
#include "objfiles.h"
#include "observer.h"
#include "solib.h"
#include "target.h"
#include "value.h"
#include <algorithm>
struct target_ops *linux_kernel_ops = NULL;
/* Initialize a private data entry for an address, where NAME is the name
of the symbol, i.e. variable name in Linux, ALIAS the name used to
retrieve the entry from hashtab, and SILENT a flag to determine if
errors should be ignored.
Returns a pointer to the new entry. In case of an error, either returns
NULL (SILENT = TRUE) or throws an error (SILENT = FALSE). If SILENT = TRUE
the caller is responsible to check for errors.
Do not use directly, use LK_DECLARE_* macros defined in lk-low.h instead. */
struct lk_private_data *
lk_init_addr (const char *name, const char *alias, int silent)
{
/* Initialize to NULL to silence gcc. */
struct value *val = NULL;
struct lk_private_data *data;
void **new_slot;
void *old_slot;
if ((old_slot = lk_find (alias)) != NULL)
return (struct lk_private_data *) old_slot;
TRY
{
/* Choose global block for search, in case the variable was redefined
in the current context. */
const struct block *global = block_global_block (get_selected_block (0));
const char *tmp = name;
expression_up expr = parse_exp_1 (&tmp, 0, global, 0);
gdb_assert (*tmp == '\0');
val = evaluate_expression (expr.get ());
}
CATCH (except, RETURN_MASK_ALL)
{
if (!silent)
error (_("Could not find address %s. Aborting."), alias);
return NULL;
}
END_CATCH
data = XCNEW (struct lk_private_data);
data->alias = alias;
data->data.addr = value_address (val);
new_slot = lk_find_slot (alias);
*new_slot = data;
return data;
}
/* Same as lk_init_addr but for structs. */
struct lk_private_data *
lk_init_struct (const char *name, const char *alias, int silent)
{
/* Initialize to NULL to silence GCC. */
struct value *val = NULL;
struct lk_private_data *data;
void **new_slot;
void *old_slot;
if ((old_slot = lk_find (alias)) != NULL)
return (struct lk_private_data *) old_slot;
/* There are two ways to define structs
o struct name { ... };
o typedef struct { ... } name;
Both are used in the linux kernel. Thus we have to check for both ways.
We do this by first searching for "struct name" (the "struct " is added
by macro LK_STRUCT_NAME in lk-low.h) and if not found seach for "name".
Note: The alias will always keep its "struct "-prefix, even when
given explicitely. Besides some weird error messages this has no effect.
*/
retry:
TRY
{
/* Choose global block for search, in case the struct was redefined
in the current context. */
const struct block *global = block_global_block(get_selected_block (0));
const char *tmp = name;
expression_up expr = parse_exp_1 (&tmp, 0, global, 0);
gdb_assert (*tmp == '\0');
/* parsing just for 'name' can cause name clashes. Thus also check for
OP_TYPE. */
if (expr->elts[0].opcode != OP_TYPE)
error ("We just need to get to the catch block");
val = evaluate_type (expr.get ());
}
CATCH (except, RETURN_MASK_ALL)
{
/* 7 = strlen ("struct "). */
if (strncmp (name, "struct ", 7) == 0)
{
name += 7;
goto retry;
}
if (!silent)
error (_("Could not find %s. Aborting."), alias);
return NULL;
}
END_CATCH
data = XCNEW (struct lk_private_data);
data->alias = alias;
data->data.type = value_type (val);
new_slot = lk_find_slot (alias);
*new_slot = data;
return data;
}
/* Nearly the same as lk_init_addr, with the difference that two names are
needed, i.e. the struct name S_NAME containing the field with name
F_NAME. */
struct lk_private_data *
lk_init_field (const char *s_name, const char *f_name, const char *alias,
int silent)
{
struct lk_private_data *data;
struct lk_private_data *parent;
struct field *first, *last, *field;
void **new_slot;
void *old_slot;
if ((old_slot = lk_find (alias)) != NULL)
return (struct lk_private_data *) old_slot;
parent = lk_find (s_name);
if (parent == NULL)
{
parent = lk_init_struct (s_name, s_name, silent);
/* Only SILENT == true needed, as otherwise lk_init_struct would throw
an error. */
if (parent == NULL)
return NULL;
}
first = TYPE_FIELDS (parent->data.type);
last = first + TYPE_NFIELDS (parent->data.type);
for (field = first; field < last; field ++)
{
if (streq (field->name, f_name))
break;
}
if (field == last)
{
if (!silent)
error (_("Could not find field %s->%s. Aborting."), s_name, f_name);
return NULL;
}
data = XCNEW (struct lk_private_data);
data->alias = alias;
data->data.field = field;
new_slot = lk_find_slot (alias);
*new_slot = data;
return data;
}
/* Map cpu number CPU to the original PTID from target beneath. */
static ptid_t
lk_cpu_to_old_ptid (const int cpu)
{
struct lk_ptid_map *ptid_map;
for (ptid_map = LK_PRIVATE->old_ptid; ptid_map;
ptid_map = ptid_map->next)
{
if (ptid_map->cpu == cpu)
return ptid_map->old_ptid;
}
error (_("Could not map CPU %d to original PTID. Aborting."), cpu);
}
/* Helper functions to read and return basic types at a given ADDRess. */
/* Read and return the integer value at address ADDR. */
int
lk_read_int (CORE_ADDR addr)
{
size_t int_size = lk_builtin_type_size (int);
enum bfd_endian endian = gdbarch_byte_order (current_inferior ()->gdbarch);
return read_memory_integer (addr, int_size, endian);
}
/* Read and return the unsigned integer value at address ADDR. */
unsigned int
lk_read_uint (CORE_ADDR addr)
{
size_t uint_size = lk_builtin_type_size (unsigned_int);
enum bfd_endian endian = gdbarch_byte_order (current_inferior ()->gdbarch);
return read_memory_integer (addr, uint_size, endian);
}
/* Read and return the long integer value at address ADDR. */
LONGEST
lk_read_long (CORE_ADDR addr)
{
size_t long_size = lk_builtin_type_size (long);
enum bfd_endian endian = gdbarch_byte_order (current_inferior ()->gdbarch);
return read_memory_integer (addr, long_size, endian);
}
/* Read and return the unsigned long integer value at address ADDR. */
ULONGEST
lk_read_ulong (CORE_ADDR addr)
{
size_t ulong_size = lk_builtin_type_size (unsigned_long);
enum bfd_endian endian = gdbarch_byte_order (current_inferior ()->gdbarch);
return read_memory_unsigned_integer (addr, ulong_size, endian);
}
/* Read and return the address value at address ADDR. */
CORE_ADDR
lk_read_addr (CORE_ADDR addr)
{
return (CORE_ADDR) lk_read_ulong (addr);
}
/* Reads a bitmap at a given ADDRess of size SIZE (in bits). Allocates and
returns an array of ulongs. The caller is responsible to free the array
after it is no longer needed. */
ULONGEST *
lk_read_bitmap (CORE_ADDR addr, size_t size)
{
ULONGEST *bitmap;
size_t ulong_size, len;
ulong_size = lk_builtin_type_size (unsigned_long);
len = LK_DIV_ROUND_UP (size, ulong_size * LK_BITS_PER_BYTE);
bitmap = XNEWVEC (ULONGEST, len);
for (size_t i = 0; i < len; i++)
bitmap[i] = lk_read_ulong (addr + i * ulong_size);
return bitmap;
}
/* Return the next set bit in bitmap BITMAP of size SIZE (in bits)
starting from bit (index) BIT. Return SIZE when the end of the bitmap
was reached. To iterate over all set bits use macro
LK_BITMAP_FOR_EACH_SET_BIT defined in lk-low.h. */
size_t
lk_bitmap_find_next_bit (ULONGEST *bitmap, size_t size, size_t bit)
{
size_t ulong_size, bits_per_ulong, elt;
ulong_size = lk_builtin_type_size (unsigned_long);
bits_per_ulong = ulong_size * LK_BITS_PER_BYTE;
elt = bit / bits_per_ulong;
while (bit < size)
{
/* FIXME: Explain why using lsb0 bit order. */
if (bitmap[elt] & (1UL << (bit % bits_per_ulong)))
return bit;
bit++;
if (bit % bits_per_ulong == 0)
elt++;
}
return size;
}
/* Returns the Hamming weight, i.e. number of set bits, of bitmap BITMAP
with size SIZE (in bits). */
size_t
lk_bitmap_hweight (ULONGEST *bitmap, size_t size)
{
size_t ulong_size, bit, bits_per_ulong, elt, retval;
ulong_size = lk_builtin_type_size (unsigned_long);
bits_per_ulong = ulong_size * LK_BITS_PER_BYTE;
elt = bit = 0;
retval = 0;
while (bit < size)
{
if (bitmap[elt] & (1 << bit % bits_per_ulong))
retval++;
bit++;
if (bit % bits_per_ulong == 0)
elt++;
}
return retval;
}
/* Provide the per_cpu_offset of cpu CPU. See comment in lk-low.h for
details. */
CORE_ADDR
lk_get_percpu_offset (unsigned int cpu)
{
size_t ulong_size = lk_builtin_type_size (unsigned_long);
CORE_ADDR percpu_elt;
/* Give the architecture a chance to overwrite default behaviour. */
if (LK_HOOK->get_percpu_offset)
return LK_HOOK->get_percpu_offset (cpu);
percpu_elt = LK_ADDR (__per_cpu_offset) + (ulong_size * cpu);
return lk_read_addr (percpu_elt);
}
/* Test if a given task TASK is running. See comment in lk-low.h for
details. */
unsigned int
lk_task_running (CORE_ADDR task)
{
ULONGEST *cpu_online_mask;
size_t size;
unsigned int cpu;
struct cleanup *old_chain;
size = LK_BITMAP_SIZE (cpumask);
cpu_online_mask = lk_read_bitmap (LK_ADDR (cpu_online_mask), size);
old_chain = make_cleanup (xfree, cpu_online_mask);
LK_BITMAP_FOR_EACH_SET_BIT (cpu_online_mask, size, cpu)
{
CORE_ADDR rq;
CORE_ADDR curr;
rq = LK_ADDR (runqueues) + lk_get_percpu_offset (cpu);
curr = lk_read_addr (rq + LK_OFFSET (rq, curr));
if (curr == task)
break;
}
if (cpu == size)
cpu = LK_CPU_INVAL;
do_cleanups (old_chain);
return cpu;
}
/* Update running tasks with information from struct rq->curr. */
static void
lk_update_running_tasks ()
{
ULONGEST *cpu_online_mask;
size_t size;
unsigned int cpu;
struct cleanup *old_chain;
size = LK_BITMAP_SIZE (cpumask);
cpu_online_mask = lk_read_bitmap (LK_ADDR (cpu_online_mask), size);
old_chain = make_cleanup (xfree, cpu_online_mask);
LK_BITMAP_FOR_EACH_SET_BIT (cpu_online_mask, size, cpu)
{
struct thread_info *tp;
CORE_ADDR rq, curr;
LONGEST pid, inf_pid;
ptid_t new_ptid, old_ptid;
rq = LK_ADDR (runqueues) + lk_get_percpu_offset (cpu);
curr = lk_read_addr (rq + LK_OFFSET (rq, curr));
pid = lk_read_int (curr + LK_OFFSET (task_struct, pid));
inf_pid = current_inferior ()->pid;
new_ptid = ptid_build (inf_pid, pid, curr);
old_ptid = lk_cpu_to_old_ptid (cpu); /* FIXME not suitable for
running targets? */
tp = find_thread_ptid (old_ptid);
if (tp && tp->state != THREAD_EXITED)
thread_change_ptid (old_ptid, new_ptid);
}
do_cleanups (old_chain);
}
/* Update sleeping tasks by walking the task_structs starting from
init_task. */
static void
lk_update_sleeping_tasks ()
{
CORE_ADDR init_task, task, thread;
int inf_pid;
inf_pid = current_inferior ()->pid;
init_task = LK_ADDR (init_task);
lk_list_for_each_container (task, init_task, task_struct, tasks)
{
lk_list_for_each_container (thread, task, task_struct, thread_group)
{
int pid;
ptid_t ptid;
struct thread_info *tp;
pid = lk_read_int (thread + LK_OFFSET (task_struct, pid));
ptid = ptid_build (inf_pid, pid, thread);
tp = find_thread_ptid (ptid);
if (tp == NULL || tp->state == THREAD_EXITED)
add_thread (ptid);
}
}
}
/* Function for targets to_update_thread_list hook. */
static void
lk_update_thread_list (struct target_ops *target)
{
prune_threads ();
lk_update_running_tasks ();
lk_update_sleeping_tasks ();
}
/* Function for targets to_fetch_registers hook. */
static void
lk_fetch_registers (struct target_ops *target,
struct regcache *regcache, int regnum)
{
CORE_ADDR task;
unsigned int cpu;
task = (CORE_ADDR) ptid_get_tid (inferior_ptid);
cpu = lk_task_running (task);
/* Let the target beneath fetch registers of running tasks. */
if (cpu != LK_CPU_INVAL)
{
struct cleanup *old_inferior_ptid;
old_inferior_ptid = save_inferior_ptid ();
inferior_ptid = lk_cpu_to_old_ptid (cpu);
linux_kernel_ops->beneath->to_fetch_registers (target, regcache, regnum);
do_cleanups (old_inferior_ptid);
}
else
{
struct gdbarch *gdbarch;
unsigned int i;
LK_HOOK->get_registers (task, target, regcache, regnum);
/* Mark all registers not found as unavailable. */
gdbarch = get_regcache_arch (regcache);
for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
{
if (regcache_register_status (regcache, i) == REG_UNKNOWN)
regcache_raw_supply (regcache, i, NULL);
}
}
}
/* Function for targets to_pid_to_str hook. Marks running tasks with an
asterisk "*". */
static char *
lk_pid_to_str (struct target_ops *target, ptid_t ptid)
{
static char buf[64];
long pid;
CORE_ADDR task;
pid = ptid_get_lwp (ptid);
task = (CORE_ADDR) ptid_get_tid (ptid);
xsnprintf (buf, sizeof (buf), "PID: %5li%s, 0x%s",
pid, ((lk_task_running (task) != LK_CPU_INVAL) ? "*" : ""),
phex (task, lk_builtin_type_size (unsigned_long)));
return buf;
}
/* Function for targets to_thread_name hook. */
static const char *
lk_thread_name (struct target_ops *target, struct thread_info *ti)
{
static char buf[LK_TASK_COMM_LEN + 1];
char tmp[LK_TASK_COMM_LEN + 1];
CORE_ADDR task, comm;
size_t size;
size = std::min ((unsigned int) LK_TASK_COMM_LEN,
LK_ARRAY_LEN(LK_FIELD (task_struct, comm)));
task = (CORE_ADDR) ptid_get_tid (ti->ptid);
comm = task + LK_OFFSET (task_struct, comm);
read_memory (comm, (gdb_byte *) tmp, size);
xsnprintf (buf, sizeof (buf), "%-16s", tmp);
return buf;
}
/* Translate a kernel virtual address ADDR to a physical address. */
CORE_ADDR
lk_kvtop (CORE_ADDR addr)
{
CORE_ADDR pgd = lk_read_addr (LK_ADDR (init_mm)
+ LK_OFFSET (mm_struct, pgd));
return LK_HOOK->vtop (pgd, addr);
}
/* Restore current_target to TARGET. */
static void
restore_current_target (void *target)
{
current_target.beneath = (struct target_ops *) target;
}
/* Function for targets to_xfer_partial hook. */
enum target_xfer_status
lk_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
ULONGEST *xfered_len)
{
enum target_xfer_status ret_val;
struct cleanup *old_chain = make_cleanup (restore_current_target, ops);
current_target.beneath = ops->beneath;
if (LK_HOOK->is_kvaddr (offset))
offset = lk_kvtop (offset);
ret_val = ops->beneath->to_xfer_partial (ops->beneath, object, annex,
readbuf, writebuf, offset, len,
xfered_len);
do_cleanups (old_chain);
return ret_val;
}
/* Functions to initialize and free target_ops and its private data. As well
as functions for targets to_open/close/detach hooks. */
/* Check if OBFFILE is a Linux kernel. */
static int
lk_is_linux_kernel (struct objfile *objfile)
{
int ok = 0;
if (objfile == NULL || !(objfile->flags & OBJF_MAINLINE))
return 0;
ok += lookup_minimal_symbol ("linux_banner", NULL, objfile).minsym != NULL;
ok += lookup_minimal_symbol ("_stext", NULL, objfile).minsym != NULL;
ok += lookup_minimal_symbol ("_etext", NULL, objfile).minsym != NULL;
return (ok > 2);
}
/* Initialize struct lk_private. */
static void
lk_init_private ()
{
linux_kernel_ops->to_data = XCNEW (struct lk_private);
LK_PRIVATE->hooks = XCNEW (struct lk_private_hooks);
LK_PRIVATE->data = htab_create_alloc (31, (htab_hash) lk_hash_private_data,
(htab_eq) lk_private_data_eq, NULL,
xcalloc, xfree);
}
/* Initialize architecture independent private data. Must be called
_after_ symbol tables were initialized. */
/* FIXME: throw error more fine-grained. */
/* FIXME: make independent of compile options. */
static void
lk_init_private_data ()
{
if (LK_PRIVATE->data != NULL)
htab_empty (LK_PRIVATE->data);
LK_DECLARE_FIELD (task_struct, tasks);
LK_DECLARE_FIELD (task_struct, pid);
LK_DECLARE_FIELD (task_struct, tgid);
LK_DECLARE_FIELD (task_struct, thread_group);
LK_DECLARE_FIELD (task_struct, comm);
LK_DECLARE_FIELD (task_struct, thread);
LK_DECLARE_FIELD (list_head, next);
LK_DECLARE_FIELD (list_head, prev);
LK_DECLARE_FIELD (rq, curr);
LK_DECLARE_FIELD (cpumask, bits);
LK_DECLARE_FIELD (mm_struct, pgd);
LK_DECLARE_FIELD (pgd_t, pgd);
LK_DECLARE_FIELD (module, list);
LK_DECLARE_FIELD (module, name);
LK_DECLARE_FIELD (module, source_list);
LK_DECLARE_FIELD (module, arch);
LK_DECLARE_FIELD (module, init);
LK_DECLARE_FIELD (module, percpu);
LK_DECLARE_FIELD (module, percpu_size);
/* Module offset moved to new struct module_layout with linux 4.5.
It must be checked in code which of this fields exist. */
if (LK_DECLARE_FIELD_SILENT (module_layout, base)) /* linux 4.5+ */
{
LK_DECLARE_FIELD (module, init_layout);
LK_DECLARE_FIELD (module, core_layout);
LK_DECLARE_FIELD (module_layout, size);
LK_DECLARE_FIELD (module_layout, text_size);
LK_DECLARE_FIELD (module_layout, ro_size);
}
else if (LK_DECLARE_FIELD_SILENT (module, module_core)) /* linux -4.4 */
{
LK_DECLARE_FIELD (module, init_size);
LK_DECLARE_FIELD (module, core_size);
LK_DECLARE_FIELD (module, core_text_size);
LK_DECLARE_FIELD (module, core_ro_size);
}
else
{
error (_("Could not find module base. Aborting."));
}
LK_DECLARE_FIELD (module_use, source_list);
LK_DECLARE_FIELD (module_use, source);
LK_DECLARE_FIELD (uts_namespace, name);
LK_DECLARE_STRUCT_ALIAS (new_utsname, utsname);
LK_DECLARE_STRUCT_ALIAS (old_utsname, utsname);
LK_DECLARE_STRUCT_ALIAS (oldold_utsname, utsname);
if (LK_STRUCT (utsname) == NULL)
error (_("Could not find struct utsname. Aborting."));
LK_DECLARE_FIELD (utsname, version);
LK_DECLARE_FIELD (utsname, release);
LK_DECLARE_ADDR (init_task);
LK_DECLARE_ADDR (runqueues);
LK_DECLARE_ADDR (__per_cpu_offset);
LK_DECLARE_ADDR (init_mm);
LK_DECLARE_ADDR (modules);
LK_DECLARE_ADDR (init_uts_ns);
LK_DECLARE_ADDR_ALIAS (__cpu_online_mask, cpu_online_mask); /* linux 4.5+ */
LK_DECLARE_ADDR_ALIAS (cpu_online_bits, cpu_online_mask); /* linux -4.4 */
if (LK_ADDR (cpu_online_mask) == -1)
error (_("Could not find address cpu_online_mask. Aborting."));
}
/* Frees the cpu to old ptid map. */
static void
lk_free_ptid_map ()
{
while (LK_PRIVATE->old_ptid)
{
struct lk_ptid_map *tmp;
tmp = LK_PRIVATE->old_ptid;
LK_PRIVATE->old_ptid = tmp->next;
XDELETE (tmp);
}
}
/* Initialize the cpu to old ptid map. Prefer the arch dependent
map_running_task_to_cpu hook if provided, else assume that the PID used
by target beneath is the same as in task_struct PID task_struct. See
comment on lk_ptid_map in lk-low.h for details. */
static void
lk_init_ptid_map ()
{
struct thread_info *ti;
ULONGEST *cpu_online_mask;
size_t size;
unsigned int cpu;
struct cleanup *old_chain;
if (LK_PRIVATE->old_ptid != NULL)
lk_free_ptid_map ();
size = LK_BITMAP_SIZE (cpumask);
cpu_online_mask = lk_read_bitmap (LK_ADDR (cpu_online_mask), size);
old_chain = make_cleanup (xfree, cpu_online_mask);
ALL_THREADS (ti)
{
struct lk_ptid_map *ptid_map = XCNEW (struct lk_ptid_map);
CORE_ADDR rq, curr;
int pid;
/* Give the architecture a chance to overwrite default behaviour. */
if (LK_HOOK->map_running_task_to_cpu)
{
ptid_map->cpu = LK_HOOK->map_running_task_to_cpu (ti);
}
else
{
LK_BITMAP_FOR_EACH_SET_BIT (cpu_online_mask, size, cpu)
{
rq = LK_ADDR (runqueues) + lk_get_percpu_offset (cpu);
curr = lk_read_addr (rq + LK_OFFSET (rq, curr));
pid = lk_read_int (curr + LK_OFFSET (task_struct, pid));
if (pid == ptid_get_lwp (ti->ptid))
{
ptid_map->cpu = cpu;
break;
}
}
if (cpu == size)
error (_("Could not map thread with pid %d, lwp %lu to a cpu."),
ti->ptid.pid, ti->ptid.lwp);
}
ptid_map->old_ptid = ti->ptid;
ptid_map->next = LK_PRIVATE->old_ptid;
LK_PRIVATE->old_ptid = ptid_map;
}
do_cleanups (old_chain);
}
/* Initializes all private data and pushes the linux kernel target, if not
already done. */
static void
lk_try_push_target ()
{
struct gdbarch *gdbarch;
gdbarch = current_inferior ()->gdbarch;
if (!(gdbarch && gdbarch_lk_init_private_p (gdbarch)))
error (_("Linux kernel debugging not supported on %s."),
gdbarch_bfd_arch_info (gdbarch)->printable_name);
lk_init_private ();
lk_init_private_data ();
gdbarch_lk_init_private (gdbarch);
/* Check for required arch hooks. */
gdb_assert (LK_HOOK->get_registers);
gdb_assert (LK_HOOK->is_kvaddr);
gdb_assert (LK_HOOK->vtop);
gdb_assert (LK_HOOK->get_module_text_offset);
lk_init_ptid_map ();
lk_update_thread_list (linux_kernel_ops);
if (!target_is_pushed (linux_kernel_ops))
push_target (linux_kernel_ops);
lk_init_cmds ();
set_solib_ops (gdbarch, lk_modules_so_ops);
}
/* Function for targets to_open hook. */
static void
lk_open (const char *args, int from_tty)
{
struct objfile *objfile;
if (target_is_pushed (linux_kernel_ops))
{
printf_unfiltered (_("Linux kernel target already pushed. Aborting\n"));
return;
}
for (objfile = current_program_space->objfiles; objfile;
objfile = objfile->next)
{
if (lk_is_linux_kernel (objfile)
&& ptid_get_pid (inferior_ptid) != 0)
{
lk_try_push_target ();
return;
}
}
printf_unfiltered (_("Could not find a valid Linux kernel object file. "
"Aborting.\n"));
}
/* Function for targets to_close hook. Deletes all private data. */
static void
lk_close (struct target_ops *ops)
{
htab_delete (LK_PRIVATE->data);
lk_free_ptid_map ();
XDELETE (LK_PRIVATE->hooks);
XDELETE (LK_PRIVATE);
linux_kernel_ops->to_data = NULL;
}
/* Function for targets to_detach hook. */
static void
lk_detach (struct target_ops *t, const char *args, int from_tty)
{
struct target_ops *beneath = linux_kernel_ops->beneath;
unpush_target (linux_kernel_ops);
reinit_frame_cache ();
if (from_tty)
printf_filtered (_("Linux kernel target detached.\n"));
beneath->to_detach (beneath, args, from_tty);
}
/* Function for new objfile observer. */
static void
lk_observer_new_objfile (struct objfile *objfile)
{
if (lk_is_linux_kernel (objfile)
&& ptid_get_pid (inferior_ptid) != 0)
lk_try_push_target ();
}
/* Function for inferior created observer. */
static void
lk_observer_inferior_created (struct target_ops *ops, int from_tty)
{
struct objfile *objfile;
if (ptid_get_pid (inferior_ptid) == 0)
return;
for (objfile = current_inferior ()->pspace->objfiles; objfile;
objfile = objfile->next)
{
if (lk_is_linux_kernel (objfile))
{
lk_try_push_target ();
return;
}
}
}
/* Initialize linux kernel target. */
static void
init_linux_kernel_ops (void)
{
struct target_ops *t;
if (linux_kernel_ops != NULL)
return;
t = XCNEW (struct target_ops);
t->to_shortname = "linux-kernel";
t->to_longname = "linux kernel support";
t->to_doc = "Adds support to debug the Linux kernel";
/* set t->to_data = struct lk_private in lk_init_private. */
t->to_open = lk_open;
t->to_close = lk_close;
t->to_detach = lk_detach;
t->to_fetch_registers = lk_fetch_registers;
t->to_update_thread_list = lk_update_thread_list;
t->to_pid_to_str = lk_pid_to_str;
t->to_thread_name = lk_thread_name;
t->to_xfer_partial = lk_xfer_partial;
t->to_stratum = thread_stratum;
t->to_magic = OPS_MAGIC;
linux_kernel_ops = t;
add_target (t);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_linux_kernel;
void
_initialize_linux_kernel (void)
{
init_linux_kernel_ops ();
observer_attach_new_objfile (lk_observer_new_objfile);
observer_attach_inferior_created (lk_observer_inferior_created);
}

333
gdb/lk-low.h Normal file
View File

@@ -0,0 +1,333 @@
/* Basic Linux kernel support, architecture independent.
Copyright (C) 2016 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/>. */
#ifndef __LK_LOW_H__
#define __LK_LOW_H__
#include "target.h"
extern struct target_ops *linux_kernel_ops;
/* Copy constants defined in Linux kernel. */
#define LK_TASK_COMM_LEN 16
#define LK_BITS_PER_BYTE 8
#define LK_MODULE_NAME_LEN 56
#define LK_UTS_NAME_LEN 64
/* Definitions used in linux kernel target. */
#define LK_CPU_INVAL -1U
/* Private data structs for this target. */
/* Forward declarations. */
struct lk_private_hooks;
struct lk_ptid_map;
/* Short hand access to private data. */
#define LK_PRIVATE ((struct lk_private *) linux_kernel_ops->to_data)
#define LK_HOOK (LK_PRIVATE->hooks)
struct lk_private
{
/* Hashtab for needed addresses, structs and fields. */
htab_t data;
/* Linked list to map between cpu number and original ptid from target
beneath. */
struct lk_ptid_map *old_ptid;
/* Hooks for architecture dependent functions. */
struct lk_private_hooks *hooks;
};
/* We use the following convention for PTIDs:
ptid->pid = inferiors PID
ptid->lwp = PID from task_stuct
ptid->tid = address of task_struct
The task_structs address as TID has two reasons. First, we need it quite
often and there is no other reasonable way to pass it down. Second, it
helps us to distinguish swapper tasks as they all have PID = 0.
Furthermore we cannot rely on the target beneath to use the same PID as the
task_struct. Thus we need a mapping between our PTID and the PTID of the
target beneath. Otherwise it is impossible to pass jobs, e.g. fetching
registers of running tasks, to the target beneath. */
/* Private data struct to map between our and the target beneath PTID. */
struct lk_ptid_map
{
struct lk_ptid_map *next;
unsigned int cpu;
ptid_t old_ptid;
};
/* Private data struct to be stored in hashtab. */
struct lk_private_data
{
const char *alias;
union
{
CORE_ADDR addr;
struct type *type;
struct field *field;
} data;
};
/* Wrapper for htab_hash_string to work with our private data. */
static inline hashval_t
lk_hash_private_data (const struct lk_private_data *entry)
{
return htab_hash_string (entry->alias);
}
/* Function for htab_eq to work with our private data. */
static inline int
lk_private_data_eq (const struct lk_private_data *entry,
const struct lk_private_data *element)
{
return streq (entry->alias, element->alias);
}
/* Wrapper for htab_find_slot to work with our private data. Do not use
directly, use the macros below instead. */
static inline void **
lk_find_slot (const char *alias)
{
const struct lk_private_data dummy = { alias };
return htab_find_slot (LK_PRIVATE->data, &dummy, INSERT);
}
/* Wrapper for htab_find to work with our private data. Do not use
directly, use the macros below instead. */
static inline struct lk_private_data *
lk_find (const char *alias)
{
const struct lk_private_data dummy = { alias };
return (struct lk_private_data *) htab_find (LK_PRIVATE->data, &dummy);
}
/* Functions to initialize private data. Do not use directly, use the
macros below instead. */
extern struct lk_private_data *lk_init_addr (const char *name,
const char *alias, int silent);
extern struct lk_private_data *lk_init_struct (const char *name,
const char *alias, int silent);
extern struct lk_private_data *lk_init_field (const char *s_name,
const char *f_name,
const char *alias, int silent);
/* The names we use to store our private data in the hashtab. */
#define LK_STRUCT_NAME(s_name) ("struct " #s_name)
#define LK_FIELD_NAME(s_name, f_name) (#s_name " " #f_name)
/* Macros to initiate addresses and fields, where (S_/F_)NAME is the variables
name as used in Linux. LK_DECLARE_FIELD also initializes the corresponding
struct entry. Throws an error, if no symbol with the given name is found.
*/
#define LK_DECLARE_ADDR(name) \
lk_init_addr (#name, #name, 0)
#define LK_DECLARE_FIELD(s_name, f_name) \
lk_init_field (LK_STRUCT_NAME (s_name), #f_name,\
LK_FIELD_NAME (s_name, f_name), 0)
/* Same as LK_DECLARE_*, but returns NULL instead of throwing an error if no
symbol was found. The caller is responsible to check for possible errors.
*/
#define LK_DECLARE_ADDR_SILENT(name) \
lk_init_addr (#name, #name, 1)
#define LK_DECLARE_FIELD_SILENT(s_name, f_name) \
lk_init_field (LK_STRUCT_NAME (s_name), #f_name,\
LK_FIELD_NAME (s_name, f_name), 1)
/* Same as LK_DECLARE_*_SILENT, but allows you to give an ALIAS name. If used
for a struct, the struct has to be declared explicitly _before_ any of its
fields. They are ment to be used, when a variable in the kernel was simply
renamed (at least from our point of view). The caller is responsible to
check for possible errors. */
#define LK_DECLARE_ADDR_ALIAS(name, alias) \
lk_init_addr (#name, #alias, 1)
#define LK_DECLARE_STRUCT_ALIAS(s_name, alias) \
lk_init_struct (LK_STRUCT_NAME(s_name), LK_STRUCT_NAME (alias), 1)
#define LK_DECLARE_FIELD_ALIAS(s_alias, f_name, f_alias) \
lk_init_field (LK_STRUCT_NAME (s_alias), #f_name, \
LK_FIELD_NAME (s_alias, f_alias), 1)
/* Macros to retrieve private data from hashtab. Returns NULL (-1) if no entry
with the given ALIAS exists. The caller only needs to check for possible
errors if not done so at initialization. */
#define LK_ADDR(alias) \
(lk_find (#alias) ? (lk_find (#alias))->data.addr : -1)
#define LK_STRUCT(alias) \
(lk_find (LK_STRUCT_NAME (alias)) \
? (lk_find (LK_STRUCT_NAME (alias)))->data.type \
: NULL)
#define LK_FIELD(s_alias, f_alias) \
(lk_find (LK_FIELD_NAME (s_alias, f_alias)) \
? (lk_find (LK_FIELD_NAME (s_alias, f_alias)))->data.field \
: NULL)
/* Definitions for architecture dependent hooks. */
/* Hook to read registers from the target and supply their content
to the regcache. */
typedef void (*lk_hook_get_registers) (CORE_ADDR task,
struct target_ops *target,
struct regcache *regcache,
int regnum);
/* Hook to check if address ADDR is a kernel virtual address.
NOTE: This hook is called in the context of target beneath. */
typedef int (*lk_hook_is_kvaddr) (CORE_ADDR addr);
/* Hook to translate virtual adress ADDR to a pysical address using page
table located at PGD.
NOTE: This hook is called in the context of target beneath. */
typedef CORE_ADDR (*lk_hook_vtop) (CORE_ADDR addr, CORE_ADDR pgd);
/* Hook to get the offset between a modules base and the start of its
.text section. */
typedef CORE_ADDR (*lk_hook_get_module_text_offset) (CORE_ADDR mod);
/* Hook to return the per_cpu_offset of cpu CPU. Only architectures that
do not use the __per_cpu_offset array to determin the offset have to
supply this hook. */
typedef CORE_ADDR (*lk_hook_get_percpu_offset) (unsigned int cpu);
/* Hook to map a running task to a logical CPU. Required if the target
beneath uses a different PID as struct rq. */
typedef unsigned int (*lk_hook_map_running_task_to_cpu) (struct thread_info *ti);
struct lk_private_hooks
{
/* required */
lk_hook_get_registers get_registers;
/* required */
lk_hook_is_kvaddr is_kvaddr;
/* required */
lk_hook_vtop vtop;
/* reqired */
lk_hook_get_module_text_offset get_module_text_offset;
/* optional, required if __per_cpu_offset array is not used to determine
offset. */
lk_hook_get_percpu_offset get_percpu_offset;
/* optional, required if the target beneath uses a different PID as struct
rq. */
lk_hook_map_running_task_to_cpu map_running_task_to_cpu;
};
/* Helper functions to read and return a value at a given ADDRess. */
extern int lk_read_int (CORE_ADDR addr);
extern unsigned int lk_read_uint (CORE_ADDR addr);
extern LONGEST lk_read_long (CORE_ADDR addr);
extern ULONGEST lk_read_ulong (CORE_ADDR addr);
extern CORE_ADDR lk_read_addr (CORE_ADDR addr);
/* Reads a bitmap at a given ADDRess of size SIZE (in bits). Allocates and
returns an array of ulongs. The caller is responsible to free the array
after it is no longer needed. */
extern ULONGEST *lk_read_bitmap (CORE_ADDR addr, size_t size);
/* Walks the bitmap BITMAP of size SIZE from bit (index) BIT.
Returns the index of the next set bit or SIZE, when the end of the bitmap
was reached. To iterate over all set bits use macro
LK_BITMAP_FOR_EACH_SET_BIT defined below. */
extern size_t lk_bitmap_find_next_bit (ULONGEST *bitmap, size_t bit,
size_t size);
#define LK_BITMAP_FOR_EACH_SET_BIT(bitmap, size, bit) \
for ((bit) = lk_bitmap_find_next_bit ((bitmap), (size), 0); \
(bit) < (size); \
(bit) = lk_bitmap_find_next_bit ((bitmap), (size), (bit) + 1))
/* Returns the size of BITMAP in bits. */
#define LK_BITMAP_SIZE(bitmap) \
(FIELD_SIZE (LK_FIELD (bitmap, bits)) * LK_BITS_PER_BYTE)
/* Returns the Hamming weight, i.e. number of set bits, of bitmap BITMAP with
size SIZE (in bits). */
extern size_t lk_bitmap_hweight (ULONGEST *bitmap, size_t size);
/* Short hand access to current gdbarchs builtin types and their
size (in byte). For TYPE replace spaces " " by underscore "_", e.g.
"unsigned int" => "unsigned_int". */
#define lk_builtin_type(type) \
(builtin_type (current_inferior ()->gdbarch)->builtin_##type)
#define lk_builtin_type_size(type) \
(lk_builtin_type (type)->length)
/* If field FIELD is an array returns its length (in #elements). */
#define LK_ARRAY_LEN(field) \
(FIELD_SIZE (field) / FIELD_TARGET_SIZE (field))
/* Short hand access to the offset of field F_NAME in struct S_NAME. */
#define LK_OFFSET(s_name, f_name) \
(FIELD_OFFSET (LK_FIELD (s_name, f_name)))
/* Returns the container of field FNAME of struct SNAME located at address
ADDR. */
#define LK_CONTAINER_OF(addr, sname, fname) \
((addr) - LK_OFFSET (sname, fname))
/* Divides numinator N by demoniator D and rounds up the result. */
#define LK_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
/* Additional access macros to fields in the style of gdbtypes.h */
/* Returns the size of field FIELD (in bytes). If FIELD is an array returns
the size of the whole array. */
#define FIELD_SIZE(field) \
TYPE_LENGTH (check_typedef (FIELD_TYPE (*field)))
/* Returns the size of the target type of field FIELD (in bytes). If FIELD is
an array returns the size of its elements. */
#define FIELD_TARGET_SIZE(field) \
TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (FIELD_TYPE (*field))))
/* Returns the offset of field FIELD (in bytes). */
#define FIELD_OFFSET(field) \
(FIELD_BITPOS (*field) / TARGET_CHAR_BIT)
/* Provides the per_cpu_offset of cpu CPU. If the architecture
provides a get_percpu_offset hook, the call is passed to it. Otherwise
returns the __per_cpu_offset[CPU] element. */
extern CORE_ADDR lk_get_percpu_offset (unsigned int cpu);
/* Tests if a given task TASK is running. Returns either the cpu-id
if running or LK_CPU_INVAL if not. */
extern unsigned int lk_task_running (CORE_ADDR task);
#endif /* __LK_LOW_H__ */

412
gdb/lk-modules.c Normal file
View File

@@ -0,0 +1,412 @@
/* Handle Linux kernel modules as shared libraries.
Copyright (C) 2016 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 "defs.h"
#include "common/filestuff.h"
#include "filenames.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdb_regex.h"
#include "lk-lists.h"
#include "lk-low.h"
#include "lk-modules.h"
#include "objfiles.h"
#include "observer.h"
#include "readline/readline.h"
#include "solib.h"
#include "solist.h"
#include "utils.h"
#include <unordered_map>
#include <string>
struct target_so_ops *lk_modules_so_ops = NULL;
/* Info for single section type. */
struct lm_info_sec
{
CORE_ADDR start;
CORE_ADDR offset;
unsigned int size;
};
/* Link map info to include in an allocated so_list entry. */
struct lm_info
{
CORE_ADDR base;
unsigned int size;
struct lm_info_sec text;
struct lm_info_sec init_text;
struct lm_info_sec ro_data;
struct lm_info_sec rw_data;
struct lm_info_sec percpu;
};
/* Check if debug info for module NAME are loaded. */
bool
lk_modules_debug_info_loaded (const std::string &name)
{
struct so_list *so;
for (so = master_so_list (); so; so = so->next)
{
if (name == so->so_original_name)
return (so->symbols_loaded && objfile_has_symbols (so->objfile));
}
return false;
}
/* Replace tags, like '$release', with corresponding data in
solib_search_path.
Known tags:
$release Linux kernel release, same as 'uname -r'
Returns the expanded path. */
static std::string
lk_modules_expand_search_path ()
{
char release[LK_UTS_NAME_LEN + 1];
CORE_ADDR utsname;
utsname = LK_ADDR (init_uts_ns) + LK_OFFSET (uts_namespace, name);
read_memory_string (utsname + LK_OFFSET (utsname, release),
release, LK_UTS_NAME_LEN);
release[LK_UTS_NAME_LEN] = '\0';
std::string search_path = get_solib_search_path ();
substitute_path_component (search_path, "$release", release);
return search_path;
}
/* With kernel modules there is the problem that the kernel only stores
the modules name but not the path from wich it was loaded from.
Thus we need to map the name to a path GDB can read from. We use file
modules.order to do so. It is created by kbuild containing the order in
which the modules appear in the Makefile and is also used by modprobe.
The drawback of this method is that it needs the modules.order file and
all relative paths, starting from <solib-search-path>, must be exactly the
same as decribed in it. */
/* Open file <solib-search-path>/modules.order and return its file
pointer. */
FILE *
lk_modules_open_mod_order ()
{
FILE *mod_order;
std::string filename = concat_path (lk_modules_expand_search_path (),
"modules.order");
mod_order = gdb_fopen_cloexec (filename.c_str (), "r");
if (!mod_order)
{
error (_("\
Can not find file module.order at %s \
to load module symbol files.\n\
Please check if solib-search-path is set correctly."),
filename.c_str ());
}
return mod_order;
}
/* Build map between module name and path to binary file by reading file
modules.order. Returns unordered_map with module name as key and its
path as value. */
std::unordered_map<std::string, std::string>
lk_modules_build_path_map ()
{
std::unordered_map<std::string, std::string> umap;
FILE *mod_order;
struct cleanup *old_chain;
char line[SO_NAME_MAX_PATH_SIZE + 1];
mod_order = lk_modules_open_mod_order ();
old_chain = make_cleanup_fclose (mod_order);
line[SO_NAME_MAX_PATH_SIZE] = '\0';
std::string search_path = lk_modules_expand_search_path ();
while (fgets (line, SO_NAME_MAX_PATH_SIZE, mod_order))
{
/* Remove trailing newline. */
line[strlen (line) - 1] = '\0';
std::string name = lbasename (line);
/* 3 = strlen (".ko"). */
if (!endswith (name.c_str (), ".ko")
|| name.length () >= LK_MODULE_NAME_LEN + 3)
continue;
name = name.substr (0, name.length () - 3);
/* Kernel modules are named after the files they are stored in with
all minus '-' replaced by underscore '_'. Do the same to enable
mapping. */
for (size_t p = name.find('-'); p != std::string::npos;
p = name.find ('-', p + 1))
name[p] = '_';
umap[name] = concat_path(search_path, line);
}
do_cleanups (old_chain);
return umap;
}
/* Allocate and fill a copy of struct lm_info for module at address MOD. */
struct lm_info *
lk_modules_read_lm_info (CORE_ADDR mod)
{
struct lm_info *lmi = XNEW (struct lm_info);
struct cleanup *old_chain = make_cleanup (xfree, lmi);
if (LK_FIELD (module, module_core)) /* linux -4.4 */
{
lmi->base = lk_read_addr (mod + LK_OFFSET (module, module_core));
lmi->size = lk_read_addr (mod + LK_OFFSET (module, core_size));
lmi->text.start = lmi->base;
lmi->text.offset = LK_HOOK->get_module_text_offset (mod);
lmi->text.size = lk_read_uint (mod + LK_OFFSET (module, core_text_size));
lmi->ro_data.start = lmi->base + lmi->text.size;
lmi->ro_data.offset = 0;
lmi->ro_data.size = lk_read_uint (mod + LK_OFFSET (module,
core_ro_size));
}
else /* linux 4.5+ */
{
CORE_ADDR mod_core = mod + LK_OFFSET (module, core_layout);
lmi->base = lk_read_addr (mod_core
+ LK_OFFSET (module_layout, base));
lmi->size = lk_read_uint (mod_core
+ LK_OFFSET (module_layout, size));
lmi->text.start = lmi->base;
lmi->text.offset = LK_HOOK->get_module_text_offset (mod);
lmi->text.size = lk_read_uint (mod_core
+ LK_OFFSET (module_layout, text_size));
lmi->ro_data.start = lmi->base + lmi->text.size;
lmi->ro_data.offset = 0;
lmi->ro_data.size = lk_read_uint (mod_core
+ LK_OFFSET (module_layout, ro_size));
}
lmi->rw_data.start = lmi->base + lmi->ro_data.size;
lmi->rw_data.offset = 0;
lmi->rw_data.size = lmi->size - lmi->ro_data.size;
lmi->init_text.start = lk_read_addr (mod + LK_OFFSET (module, init));
lmi->init_text.offset = 0;
lmi->percpu.start = lk_read_addr (mod + LK_OFFSET (module, percpu));
lmi->percpu.size = lk_read_uint (mod + LK_OFFSET (module, percpu_size));
lmi->percpu.offset = 0;
discard_cleanups (old_chain);
return lmi;
}
/* Function for current_sos hook. */
struct so_list *
lk_modules_current_sos (void)
{
CORE_ADDR modules, next;
FILE *mod_order;
struct so_list *list = NULL;
std::unordered_map<std::string, std::string> umap;
umap = lk_modules_build_path_map ();
modules = LK_ADDR (modules);
lk_list_for_each (next, modules, module, list)
{
char name[LK_MODULE_NAME_LEN];
CORE_ADDR mod, name_addr;
mod = LK_CONTAINER_OF (next, module, list);
name_addr = mod + LK_OFFSET (module, name);
read_memory_string (name_addr, name, LK_MODULE_NAME_LEN);
if (umap.count (name))
{
struct so_list *newso = XCNEW (struct so_list);
newso->next = list;
list = newso;
newso->lm_info = lk_modules_read_lm_info (mod);
strncpy (newso->so_original_name, name, SO_NAME_MAX_PATH_SIZE);
strncpy (newso->so_name, umap[name].c_str (), SO_NAME_MAX_PATH_SIZE);
newso->pspace = current_program_space;
}
}
return list;
}
/* Relocate target_section SEC to section type LMI_SEC. Helper function for
lk_modules_relocate_section_addresses. */
void
lk_modules_relocate_sec (struct target_section *sec,
struct lm_info_sec *lmi_sec)
{
unsigned int alignment = 1;
alignment = 1 << sec->the_bfd_section->alignment_power;
/* Adjust offset to section alignment. */
if (lmi_sec->offset % alignment != 0)
lmi_sec->offset += alignment - (lmi_sec->offset % alignment);
sec->addr += lmi_sec->start + lmi_sec->offset;
sec->endaddr += lmi_sec->start + lmi_sec->offset;
lmi_sec->offset += sec->endaddr - sec->addr;
}
/* Function for relocate_section_addresses hook. */
void
lk_modules_relocate_section_addresses (struct so_list *so,
struct target_section *sec)
{
struct lm_info *lmi = so->lm_info;
unsigned int flags = sec->the_bfd_section->flags;
const char *name = sec->the_bfd_section->name;
if (streq (name, ".modinfo") || streq (name, "__versions"))
return;
/* FIXME: Make dependent on module state, i.e. only map .init sections if
* state is MODULE_STATE_COMING. */
if (startswith (name, ".init"))
lk_modules_relocate_sec (sec, &lmi->init_text);
else if (endswith (name, ".percpu"))
lk_modules_relocate_sec (sec, &lmi->percpu);
else if (flags & SEC_CODE)
lk_modules_relocate_sec (sec, &lmi->text);
else if (flags & SEC_READONLY)
lk_modules_relocate_sec (sec, &lmi->ro_data);
else if (flags & SEC_ALLOC)
lk_modules_relocate_sec (sec, &lmi->rw_data);
/* Set address range to be displayed with info shared.
size = text + (ro + rw) data without .init sections. */
if (so->addr_low == so->addr_high)
{
so->addr_low = lmi->base;
so->addr_high = lmi->base + lmi->size;
}
}
/* Function for free_so hook. */
void
lk_modules_free_so (struct so_list *so)
{
xfree (so->lm_info);
}
/* Function for clear_so hook. */
void
lk_modules_clear_so (struct so_list *so)
{
if (so->lm_info != NULL)
memset (so->lm_info, 0, sizeof (struct lm_info));
}
/* Function for clear_solib hook. */
void
lk_modules_clear_solib ()
{
/* Nothing to do. */
}
/* Function for clear_create_inferior_hook hook. */
void
lk_modules_create_inferior_hook (int from_tty)
{
/* Nothing to do. */
}
/* Function for clear_create_inferior_hook hook. */
int
lk_modules_in_dynsym_resolve_code (CORE_ADDR pc)
{
return 0;
}
/* Function for same hook. */
int
lk_modules_same (struct so_list *gdb, struct so_list *inf)
{
return streq (gdb->so_name, inf->so_name);
}
/* Initialize linux modules solib target. */
void
init_lk_modules_so_ops (void)
{
struct target_so_ops *t;
if (lk_modules_so_ops != NULL)
return;
t = XCNEW (struct target_so_ops);
t->relocate_section_addresses = lk_modules_relocate_section_addresses;
t->free_so = lk_modules_free_so;
t->clear_so = lk_modules_clear_so;
t->clear_solib = lk_modules_clear_solib;
t->solib_create_inferior_hook = lk_modules_create_inferior_hook;
t->current_sos = lk_modules_current_sos;
t->bfd_open = solib_bfd_open;
t->in_dynsym_resolve_code = lk_modules_in_dynsym_resolve_code;
t->same = lk_modules_same;
lk_modules_so_ops = t;
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_lk_modules;
void
_initialize_lk_modules (void)
{
init_lk_modules_so_ops ();
}

29
gdb/lk-modules.h Normal file
View File

@@ -0,0 +1,29 @@
/* Handle kernel modules as shared libraries.
Copyright (C) 2016 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/>. */
#ifndef __LK_MODULES_H__
#define __LK_MODULES_H__
extern struct target_so_ops *lk_modules_so_ops;
/* Check if debug info for module NAME are loaded. Needed by lsmod command. */
extern bool lk_modules_debug_info_loaded (const std::string &name);
#endif /* __LK_MODULES_H__ */

View File

@@ -0,0 +1,76 @@
# THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi :set ro:
# Generated from: s390x-cr-linux64.xml
name:s390x_cr_linux64
xmltarget:s390x-cr-linux64.xml
expedite:r14,r15,pswa
64:pswm
64:pswa
64:r0
64:r1
64:r2
64:r3
64:r4
64:r5
64:r6
64:r7
64:r8
64:r9
64:r10
64:r11
64:r12
64:r13
64:r14
64:r15
32:acr0
32:acr1
32:acr2
32:acr3
32:acr4
32:acr5
32:acr6
32:acr7
32:acr8
32:acr9
32:acr10
32:acr11
32:acr12
32:acr13
32:acr14
32:acr15
32:fpc
64:f0
64:f1
64:f2
64:f3
64:f4
64:f5
64:f6
64:f7
64:f8
64:f9
64:f10
64:f11
64:f12
64:f13
64:f14
64:f15
64:cr0
64:cr1
64:cr2
64:cr3
64:cr4
64:cr5
64:cr6
64:cr7
64:cr8
64:cr9
64:cr10
64:cr11
64:cr12
64:cr13
64:cr14
64:cr15
64:timer
64:todcmp
32:todpreg
32:prefix

View File

@@ -0,0 +1,108 @@
# THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi :set ro:
# Generated from: s390x-vxcr-linux64.xml
name:s390x_vxcr_linux64
xmltarget:s390x-vxcr-linux64.xml
expedite:r14,r15,pswa
64:pswm
64:pswa
64:r0
64:r1
64:r2
64:r3
64:r4
64:r5
64:r6
64:r7
64:r8
64:r9
64:r10
64:r11
64:r12
64:r13
64:r14
64:r15
32:acr0
32:acr1
32:acr2
32:acr3
32:acr4
32:acr5
32:acr6
32:acr7
32:acr8
32:acr9
32:acr10
32:acr11
32:acr12
32:acr13
32:acr14
32:acr15
32:fpc
64:f0
64:f1
64:f2
64:f3
64:f4
64:f5
64:f6
64:f7
64:f8
64:f9
64:f10
64:f11
64:f12
64:f13
64:f14
64:f15
64:v0l
64:v1l
64:v2l
64:v3l
64:v4l
64:v5l
64:v6l
64:v7l
64:v8l
64:v9l
64:v10l
64:v11l
64:v12l
64:v13l
64:v14l
64:v15l
128:v16
128:v17
128:v18
128:v19
128:v20
128:v21
128:v22
128:v23
128:v24
128:v25
128:v26
128:v27
128:v28
128:v29
128:v30
128:v31
64:cr0
64:cr1
64:cr2
64:cr3
64:cr4
64:cr5
64:cr6
64:cr7
64:cr8
64:cr9
64:cr10
64:cr11
64:cr12
64:cr13
64:cr14
64:cr15
64:timer
64:todcmp
32:todpreg
32:prefix

View File

@@ -31,6 +31,7 @@
#include "gdbcmd.h"
#include "s390-linux-tdep.h"
#include "s390-tdep.h"
#include "elf/common.h"
#include <asm/ptrace.h>

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* Target-dependent code for GDB, the GNU debugger.
/* Target-dependent code for GNU/Linux on S390.
Copyright (C) 2003-2017 Free Software Foundation, Inc.
This file is part of GDB.
@@ -16,181 +16,19 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef S390_TDEP_H
#define S390_TDEP_H
#ifndef S390_LINUX_TDEP_H
#define S390_LINUX_TDEP_H
/* Hardware capabilities. */
extern void s390_gdbarch_linux_init (struct gdbarch_info info,
struct gdbarch *gdbarch);
#ifndef HWCAP_S390_HIGH_GPRS
#define HWCAP_S390_HIGH_GPRS 512
#endif
#ifndef HWCAP_S390_TE
#define HWCAP_S390_TE 1024
#endif
#ifndef HWCAP_S390_VX
#define HWCAP_S390_VX 2048
#endif
/* Register information. */
/* Program Status Word. */
#define S390_PSWM_REGNUM 0
#define S390_PSWA_REGNUM 1
/* General Purpose Registers. */
#define S390_R0_REGNUM 2
#define S390_R1_REGNUM 3
#define S390_R2_REGNUM 4
#define S390_R3_REGNUM 5
#define S390_R4_REGNUM 6
#define S390_R5_REGNUM 7
#define S390_R6_REGNUM 8
#define S390_R7_REGNUM 9
#define S390_R8_REGNUM 10
#define S390_R9_REGNUM 11
#define S390_R10_REGNUM 12
#define S390_R11_REGNUM 13
#define S390_R12_REGNUM 14
#define S390_R13_REGNUM 15
#define S390_R14_REGNUM 16
#define S390_R15_REGNUM 17
/* Access Registers. */
#define S390_A0_REGNUM 18
#define S390_A1_REGNUM 19
#define S390_A2_REGNUM 20
#define S390_A3_REGNUM 21
#define S390_A4_REGNUM 22
#define S390_A5_REGNUM 23
#define S390_A6_REGNUM 24
#define S390_A7_REGNUM 25
#define S390_A8_REGNUM 26
#define S390_A9_REGNUM 27
#define S390_A10_REGNUM 28
#define S390_A11_REGNUM 29
#define S390_A12_REGNUM 30
#define S390_A13_REGNUM 31
#define S390_A14_REGNUM 32
#define S390_A15_REGNUM 33
/* Floating Point Control Word. */
#define S390_FPC_REGNUM 34
/* Floating Point Registers. */
#define S390_F0_REGNUM 35
#define S390_F1_REGNUM 36
#define S390_F2_REGNUM 37
#define S390_F3_REGNUM 38
#define S390_F4_REGNUM 39
#define S390_F5_REGNUM 40
#define S390_F6_REGNUM 41
#define S390_F7_REGNUM 42
#define S390_F8_REGNUM 43
#define S390_F9_REGNUM 44
#define S390_F10_REGNUM 45
#define S390_F11_REGNUM 46
#define S390_F12_REGNUM 47
#define S390_F13_REGNUM 48
#define S390_F14_REGNUM 49
#define S390_F15_REGNUM 50
/* General Purpose Register Upper Halves. */
#define S390_R0_UPPER_REGNUM 51
#define S390_R1_UPPER_REGNUM 52
#define S390_R2_UPPER_REGNUM 53
#define S390_R3_UPPER_REGNUM 54
#define S390_R4_UPPER_REGNUM 55
#define S390_R5_UPPER_REGNUM 56
#define S390_R6_UPPER_REGNUM 57
#define S390_R7_UPPER_REGNUM 58
#define S390_R8_UPPER_REGNUM 59
#define S390_R9_UPPER_REGNUM 60
#define S390_R10_UPPER_REGNUM 61
#define S390_R11_UPPER_REGNUM 62
#define S390_R12_UPPER_REGNUM 63
#define S390_R13_UPPER_REGNUM 64
#define S390_R14_UPPER_REGNUM 65
#define S390_R15_UPPER_REGNUM 66
/* GNU/Linux-specific optional registers. */
#define S390_ORIG_R2_REGNUM 67
#define S390_LAST_BREAK_REGNUM 68
#define S390_SYSTEM_CALL_REGNUM 69
/* Transaction diagnostic block. */
#define S390_TDB_DWORD0_REGNUM 70
#define S390_TDB_ABORT_CODE_REGNUM 71
#define S390_TDB_CONFLICT_TOKEN_REGNUM 72
#define S390_TDB_ATIA_REGNUM 73
#define S390_TDB_R0_REGNUM 74
#define S390_TDB_R1_REGNUM 75
#define S390_TDB_R2_REGNUM 76
#define S390_TDB_R3_REGNUM 77
#define S390_TDB_R4_REGNUM 78
#define S390_TDB_R5_REGNUM 79
#define S390_TDB_R6_REGNUM 80
#define S390_TDB_R7_REGNUM 81
#define S390_TDB_R8_REGNUM 82
#define S390_TDB_R9_REGNUM 83
#define S390_TDB_R10_REGNUM 84
#define S390_TDB_R11_REGNUM 85
#define S390_TDB_R12_REGNUM 86
#define S390_TDB_R13_REGNUM 87
#define S390_TDB_R14_REGNUM 88
#define S390_TDB_R15_REGNUM 89
/* Vector registers. */
#define S390_V0_LOWER_REGNUM 90
#define S390_V1_LOWER_REGNUM 91
#define S390_V2_LOWER_REGNUM 92
#define S390_V3_LOWER_REGNUM 93
#define S390_V4_LOWER_REGNUM 94
#define S390_V5_LOWER_REGNUM 95
#define S390_V6_LOWER_REGNUM 96
#define S390_V7_LOWER_REGNUM 97
#define S390_V8_LOWER_REGNUM 98
#define S390_V9_LOWER_REGNUM 99
#define S390_V10_LOWER_REGNUM 100
#define S390_V11_LOWER_REGNUM 101
#define S390_V12_LOWER_REGNUM 102
#define S390_V13_LOWER_REGNUM 103
#define S390_V14_LOWER_REGNUM 104
#define S390_V15_LOWER_REGNUM 105
#define S390_V16_REGNUM 106
#define S390_V17_REGNUM 107
#define S390_V18_REGNUM 108
#define S390_V19_REGNUM 109
#define S390_V20_REGNUM 110
#define S390_V21_REGNUM 111
#define S390_V22_REGNUM 112
#define S390_V23_REGNUM 113
#define S390_V24_REGNUM 114
#define S390_V25_REGNUM 115
#define S390_V26_REGNUM 116
#define S390_V27_REGNUM 117
#define S390_V28_REGNUM 118
#define S390_V29_REGNUM 119
#define S390_V30_REGNUM 120
#define S390_V31_REGNUM 121
/* Total. */
#define S390_NUM_REGS 122
/* Special register usage. */
#define S390_SP_REGNUM S390_R15_REGNUM
#define S390_RETADDR_REGNUM S390_R14_REGNUM
#define S390_FRAME_REGNUM S390_R11_REGNUM
#define S390_IS_GREGSET_REGNUM(i) \
(((i) >= S390_PSWM_REGNUM && (i) <= S390_A15_REGNUM) \
|| ((i) >= S390_R0_UPPER_REGNUM && (i) <= S390_R15_UPPER_REGNUM) \
|| (i) == S390_ORIG_R2_REGNUM)
#define S390_IS_FPREGSET_REGNUM(i) \
((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM)
#define S390_IS_TDBREGSET_REGNUM(i) \
((i) >= S390_TDB_DWORD0_REGNUM && (i) <= S390_TDB_R15_REGNUM)
/* Core file register sets, defined in s390-tdep.c. */
/* Core file register sets, defined in s390-linux-tdep.c. */
#define s390_sizeof_gregset 0x90
#define s390x_sizeof_gregset 0xd8
extern const struct regset s390_gregset;
#define s390_sizeof_fpregset 0x88
extern const struct regset s390_fpregset;
extern const struct regset s390_upper_regset;
extern const struct regset s390_last_break_regset;
extern const struct regset s390x_last_break_regset;
extern const struct regset s390_system_call_regset;
@@ -216,4 +54,4 @@ extern struct target_desc *tdesc_s390x_te_linux64;
extern struct target_desc *tdesc_s390x_vx_linux64;
extern struct target_desc *tdesc_s390x_tevx_linux64;
#endif
#endif /* S390_LINUX_TDEP_H */

390
gdb/s390-lk-tdep.c Normal file
View File

@@ -0,0 +1,390 @@
/* Target-dependent code for linux-kernel target on S390.
Copyright (C) 2017 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 "defs.h"
#include "gdbarch.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "lk-low.h"
#include "osabi.h"
#include "regcache.h"
#include "regset.h"
#include "s390-tdep.h"
#include "s390-lk-tdep.h"
#include "features/s390x-cr-linux64.c"
#include "features/s390x-vxcr-linux64.c"
/* Register maps and sets. */
static const struct regcache_map_entry s390x_gregmap_lk[] =
{
{ 10, S390_R6_REGNUM }, /* r0-r5 volatile */
{ -2, REGCACHE_MAP_SKIP, 8 },
{ 1, S390_PSWA_REGNUM }, /* Use r14 for PSWA. */
{ 0 }
};
static const struct regcache_map_entry s390x_regmap_cr [] =
{
{ 16, S390_CR0_REGNUM, 8 },
{ 0 }
};
static const struct regcache_map_entry s390x_regmap_timer [] =
{
{ 1, S390_TIMER_REGNUM, 8 },
{ 0 }
};
static const struct regcache_map_entry s390x_regmap_todcmp [] =
{
{ 1, S390_TODCMP_REGNUM, 8 },
{ 0 }
};
static const struct regcache_map_entry s390x_regmap_todpreg [] =
{
{ 1, S390_TODPREG_REGNUM, 4 },
{ 0 }
};
static const struct regcache_map_entry s390x_regmap_prefix [] =
{
{ 1, S390_PREFIX_REGNUM, 4 },
{ 0 }
};
const struct regset s390x_gregset_lk = {
s390x_gregmap_lk,
regcache_supply_regset,
regcache_collect_regset
};
const struct regset s390x_cr_regset = {
s390x_regmap_cr,
regcache_supply_regset,
regcache_collect_regset
};
const struct regset s390x_timer_regset = {
s390x_regmap_timer,
regcache_supply_regset,
regcache_collect_regset
};
const struct regset s390x_todcmp_regset = {
s390x_regmap_todcmp,
regcache_supply_regset,
regcache_collect_regset
};
const struct regset s390x_todpreg_regset = {
s390x_regmap_todpreg,
regcache_supply_regset,
regcache_collect_regset
};
const struct regset s390x_prefix_regset = {
s390x_regmap_prefix,
regcache_supply_regset,
regcache_collect_regset
};
/* Function for Linux kernel target get_registers hook. Supplies gprs for
task TASK to REGCACHE. Uses r14 (back jump address) as current pswa. */
void
s390_lk_get_registers (CORE_ADDR task, struct target_ops *target,
struct regcache *regcache, int regnum)
{
const struct regset *regset;
CORE_ADDR ksp, gprs, pswa;
gdb_byte buf[80]; /* 80 = 10 (#registers saved) * 8 (64 bit width) */
size_t size;
regset = &s390x_gregset_lk;
ksp = lk_read_addr (task + LK_OFFSET (task_struct, thread)
+ LK_OFFSET (thread_struct, ksp));
gprs = ksp + LK_OFFSET (stack_frame, gprs);
size = FIELD_SIZE (LK_FIELD (stack_frame, gprs));
gdb_assert (size <= sizeof (buf));
read_memory (gprs, buf, size);
regset->supply_regset (regset, regcache, -1, buf, size);
}
/* Function for Linux kernel target get_percpu_offset hook. Returns the
percpu_offset from lowcore for cpu CPU. */
CORE_ADDR
s390_lk_get_percpu_offset (unsigned int cpu)
{
CORE_ADDR lowcore_ptr, lowcore;
size_t ptr_len = lk_builtin_type_size (unsigned_long);
lowcore_ptr = LK_ADDR (lowcore_ptr) + (ptr_len * cpu);
lowcore = lk_read_addr (lowcore_ptr);
return lk_read_addr (lowcore + LK_OFFSET (lowcore, percpu_offset));
}
/* Function for Linux kernel target map_running_task_to_cpu hook. */
unsigned int
s390_lk_map_running_task_to_cpu (struct thread_info *ti)
{
struct regcache *regcache;
enum register_status reg_status;
CORE_ADDR lowcore;
unsigned int cpu;
regcache = get_thread_regcache (ti->ptid);
reg_status = regcache_raw_read_unsigned (regcache, S390_PREFIX_REGNUM,
(ULONGEST *) &lowcore);
if (reg_status != REG_VALID)
error (_("Could not find prefix register for thread with pid %d, lwp %li."),
ti->ptid.pid, ti->ptid.lwp);
cpu = lk_read_uint (lowcore + LK_OFFSET (lowcore, cpu_nr));
return cpu;
}
/* Function for Linux kernel target is_kvaddr hook. */
int
s390_lk_is_kvaddr (CORE_ADDR addr)
{
return addr >= LK_ADDR (high_memory);
}
/* Read table entry from TABLE at offset OFFSET. Helper for s390_lk_vtop. */
static inline ULONGEST
s390_lk_read_table_entry (CORE_ADDR table, ULONGEST offset)
{
return lk_read_ulong (table + offset * lk_builtin_type_size (unsigned_long));
}
/* Function for Linux kernel target vtop hook. Assume 64 bit addresses. */
CORE_ADDR
s390_lk_vtop (CORE_ADDR table, CORE_ADDR vaddr)
{
ULONGEST entry, offset;
CORE_ADDR paddr;
unsigned int table_type;
size_t addr_size = lk_builtin_type_size (unsigned_long);
/* Read first entry in table to get its type. As the Table-Type bits are
the same in every table assume Region1-Table. */
entry = s390_lk_read_table_entry (table, 0);
table_type = (entry & S390_LK_RFTE_TT) >> 2;
switch (table_type)
{
case S390_LK_DAT_TT_REGION1:
{
offset = (vaddr & S390_LK_VADDR_RFX) >> 53;
entry = s390_lk_read_table_entry (table, offset);
/* Do sanity checks. */
if (!entry)
warning (_("Trying to translate address 0x%s with empty "\
"region-first-table entry."),
phex (vaddr, addr_size));
else if ((entry & S390_LK_RFTE_TT) >> 2 != S390_LK_DAT_TT_REGION1)
warning (_("Trying to translate address 0x%s with corrupt "\
"table type in region-first-table entry."),
phex (vaddr, addr_size));
else if (entry & S390_LK_RFTE_I)
warning (_("Translating address 0x%s with invalid bit set at "\
"region-first-table entry."),
phex (vaddr, addr_size));
table = entry & S390_LK_RFTE_O;
}
/* fall through */
case S390_LK_DAT_TT_REGION2:
{
offset = (vaddr & S390_LK_VADDR_RSX) >> 42;
entry = s390_lk_read_table_entry (table, offset);
/* Do sanity checks. */
if (!entry)
warning (_("Trying to translate address 0x%s with empty "\
"region-second-table entry."),
phex (vaddr, addr_size));
else if ((entry & S390_LK_RSTE_TT) >> 2 != S390_LK_DAT_TT_REGION2)
warning (_("Trying to translate address 0x%s with corrupt "\
"table type in region-second-table entry."),
phex (vaddr, addr_size));
else if (entry & S390_LK_RSTE_I)
warning (_("Translating address 0x%s with invalid bit set at "\
"region-second-table entry."),
phex (vaddr, addr_size));
table = entry & S390_LK_RSTE_O;
}
/* fall through */
case S390_LK_DAT_TT_REGION3:
{
offset = (vaddr & S390_LK_VADDR_RTX) >> 31;
entry = s390_lk_read_table_entry (table, offset);
/* Do sanity checks. */
if (!entry)
warning (_("Trying to translate address 0x%s with empty "\
"region-third-table entry."),
phex (vaddr, addr_size));
else if ((entry & S390_LK_RTTE_TT) >> 2 != S390_LK_DAT_TT_REGION3)
warning (_("Trying to translate address 0x%s with corrupt "\
"table type in region-third-table entry."),
phex (vaddr, addr_size));
else if (entry & S390_LK_RTTE_I)
warning (_("Translating address 0x%s with invalid bit set at "\
"region-third-table entry."),
phex (vaddr, addr_size));
/* Check for huge page. */
if (entry & S390_LK_RTTE_FC)
{
paddr = ((entry & S390_LK_RTTE_RFAA)
+ (vaddr & ~S390_LK_RTTE_RFAA));
return paddr;
}
table = entry & S390_LK_RTTE_O;
}
/* fall through */
case S390_LK_DAT_TT_SEGMENT:
{
offset = (vaddr & S390_LK_VADDR_SX) >> 20;
entry = s390_lk_read_table_entry (table, offset);
/* Do sanity checks. */
if (!entry)
warning (_("Trying to translate address 0x%s with empty "\
"segment-table entry."),
phex (vaddr, addr_size));
else if ((entry & S390_LK_STE_TT) >> 2 != S390_LK_DAT_TT_SEGMENT)
warning (_("Trying to translate address 0x%s with corrupt "\
"table type in segment-table entry."),
phex (vaddr, addr_size));
else if (entry & S390_LK_STE_I)
warning (_("Translating address 0x%s with invalid bit set at "\
"segment-table entry."),
phex (vaddr, addr_size));
/* Check for large page. */
if (entry & S390_LK_STE_FC)
{
paddr = ((entry & S390_LK_STE_SFAA)
+ (vaddr & ~S390_LK_STE_SFAA));
return paddr;
}
table = entry & S390_LK_STE_O;
break;
}
} /* switch (table_type) */
offset = (vaddr & S390_LK_VADDR_PX) >> 12;
entry = s390_lk_read_table_entry (table, offset);
/* Do sanity checks. */
if (!entry)
warning (_("Trying to translate address 0x%s with empty page-table "\
"entry."),
phex (vaddr, addr_size));
else if (entry & S390_LK_PTE_I)
warning (_("Translating address 0x%s with invalid bit set at page-table "\
"entry."),
phex (vaddr, addr_size));
paddr = ((entry & S390_LK_PTE_PFAA) + (vaddr & ~S390_LK_PTE_PFAA));
return paddr;
}
/* Function for Linux kernel target get_module_text_offset hook. */
CORE_ADDR
s390_lk_get_module_text_offset (CORE_ADDR mod)
{
CORE_ADDR offset, mod_arch;
mod_arch = mod + LK_OFFSET (module, arch);
offset = lk_read_ulong (mod_arch + LK_OFFSET (mod_arch_specific, got_size));
offset += lk_read_ulong (mod_arch + LK_OFFSET (mod_arch_specific, plt_size));
return offset;
}
/* Initialize s390 dependent private data for linux kernel target. */
static void
s390_lk_init_private (struct gdbarch *gdbarch)
{
LK_DECLARE_FIELD (stack_frame, gprs);
LK_DECLARE_FIELD (thread_struct, ksp);
LK_DECLARE_STRUCT_ALIAS (_lowcore, lowcore); /* linux -4.4 */
LK_DECLARE_STRUCT_ALIAS (lowcore, lowcore); /* linux 4.5+ */
if (LK_STRUCT (lowcore) == NULL)
error (_("Could not find struct lowcore. Aborting."));
LK_DECLARE_FIELD (lowcore, percpu_offset);
LK_DECLARE_FIELD (lowcore, current_pid);
LK_DECLARE_FIELD (lowcore, cpu_nr);
LK_DECLARE_FIELD (mod_arch_specific, got_size);
LK_DECLARE_FIELD (mod_arch_specific, plt_size);
LK_DECLARE_ADDR (lowcore_ptr);
LK_DECLARE_ADDR (high_memory);
LK_HOOK->get_registers = s390_lk_get_registers;
LK_HOOK->is_kvaddr = s390_lk_is_kvaddr;
LK_HOOK->vtop = s390_lk_vtop;
LK_HOOK->get_percpu_offset = s390_lk_get_percpu_offset;
LK_HOOK->map_running_task_to_cpu = s390_lk_map_running_task_to_cpu;
LK_HOOK->get_module_text_offset = s390_lk_get_module_text_offset;
}
/* Initialize Linux kernel specific gdbarch hooks. */
void
s390_gdbarch_lk_init (struct gdbarch_info info, struct gdbarch *gdbarch)
{
/* Support linux kernel debugging. */
set_gdbarch_lk_init_private (gdbarch, s390_lk_init_private);
}
extern initialize_file_ftype _initialize_s390_lk_tdep; /* -Wmissing-prototypes */
void
_initialize_s390_lk_tdep (void)
{
/* Initialize the Linux kernel target descriptions. */
initialize_tdesc_s390x_cr_linux64 ();
initialize_tdesc_s390x_vxcr_linux64 ();
}

36
gdb/s390-lk-tdep.h Normal file
View File

@@ -0,0 +1,36 @@
/* Target-dependent code for linux-kernel target on S390.
Copyright (C) 2017 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/>. */
#ifndef S390_LK_TDEP_H
#define S390_LK_TDEP_H
extern void s390_gdbarch_lk_init (struct gdbarch_info info,
struct gdbarch *gdbarch);
/* Core file privileged register sets, defined in s390-lk-tdep.c. */
extern const struct regset s390x_gregset_lk;
extern const struct regset s390x_cr_regset;
extern const struct regset s390x_timer_regset;
extern const struct regset s390x_todcmp_regset;
extern const struct regset s390x_todpreg_regset;
extern const struct regset s390x_prefix_regset;
extern struct target_desc *tdesc_s390x_cr_linux64;
extern struct target_desc *tdesc_s390x_vxcr_linux64;
#endif /* S390_LK_TDEP_H */

3404
gdb/s390-tdep.c Normal file

File diff suppressed because it is too large Load Diff

381
gdb/s390-tdep.h Normal file
View File

@@ -0,0 +1,381 @@
/* Target-dependent code for S390.
Copyright (C) 2017 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/>. */
#ifndef S390_TDEP_H
#define S390_TDEP_H
enum s390_abi_kind
{
ABI_LINUX_S390,
ABI_LINUX_ZSERIES
};
enum s390_vector_abi_kind
{
S390_VECTOR_ABI_NONE,
S390_VECTOR_ABI_128
};
/* The tdep structure. */
struct gdbarch_tdep
{
/* ABI version. */
enum s390_abi_kind abi;
/* Vector ABI. */
enum s390_vector_abi_kind vector_abi;
/* Pseudo register numbers. */
int gpr_full_regnum;
int pc_regnum;
int cc_regnum;
int v0_full_regnum;
int have_linux_v1;
int have_linux_v2;
int have_tdb;
};
/* Named opcode values for the S/390 instructions we recognize. Some
instructions have their opcode split across two fields; those are the
op1_* and op2_* enums. */
enum
{
op1_lhi = 0xa7, op2_lhi = 0x08,
op1_lghi = 0xa7, op2_lghi = 0x09,
op1_lgfi = 0xc0, op2_lgfi = 0x01,
op_lr = 0x18,
op_lgr = 0xb904,
op_l = 0x58,
op1_ly = 0xe3, op2_ly = 0x58,
op1_lg = 0xe3, op2_lg = 0x04,
op_lm = 0x98,
op1_lmy = 0xeb, op2_lmy = 0x98,
op1_lmg = 0xeb, op2_lmg = 0x04,
op_st = 0x50,
op1_sty = 0xe3, op2_sty = 0x50,
op1_stg = 0xe3, op2_stg = 0x24,
op_std = 0x60,
op_stm = 0x90,
op1_stmy = 0xeb, op2_stmy = 0x90,
op1_stmg = 0xeb, op2_stmg = 0x24,
op1_aghi = 0xa7, op2_aghi = 0x0b,
op1_ahi = 0xa7, op2_ahi = 0x0a,
op1_agfi = 0xc2, op2_agfi = 0x08,
op1_afi = 0xc2, op2_afi = 0x09,
op1_algfi= 0xc2, op2_algfi= 0x0a,
op1_alfi = 0xc2, op2_alfi = 0x0b,
op_ar = 0x1a,
op_agr = 0xb908,
op_a = 0x5a,
op1_ay = 0xe3, op2_ay = 0x5a,
op1_ag = 0xe3, op2_ag = 0x08,
op1_slgfi= 0xc2, op2_slgfi= 0x04,
op1_slfi = 0xc2, op2_slfi = 0x05,
op_sr = 0x1b,
op_sgr = 0xb909,
op_s = 0x5b,
op1_sy = 0xe3, op2_sy = 0x5b,
op1_sg = 0xe3, op2_sg = 0x09,
op_nr = 0x14,
op_ngr = 0xb980,
op_la = 0x41,
op1_lay = 0xe3, op2_lay = 0x71,
op1_larl = 0xc0, op2_larl = 0x00,
op_basr = 0x0d,
op_bas = 0x4d,
op_bcr = 0x07,
op_bc = 0x0d,
op_bctr = 0x06,
op_bctgr = 0xb946,
op_bct = 0x46,
op1_bctg = 0xe3, op2_bctg = 0x46,
op_bxh = 0x86,
op1_bxhg = 0xeb, op2_bxhg = 0x44,
op_bxle = 0x87,
op1_bxleg= 0xeb, op2_bxleg= 0x45,
op1_bras = 0xa7, op2_bras = 0x05,
op1_brasl= 0xc0, op2_brasl= 0x05,
op1_brc = 0xa7, op2_brc = 0x04,
op1_brcl = 0xc0, op2_brcl = 0x04,
op1_brct = 0xa7, op2_brct = 0x06,
op1_brctg= 0xa7, op2_brctg= 0x07,
op_brxh = 0x84,
op1_brxhg= 0xec, op2_brxhg= 0x44,
op_brxle = 0x85,
op1_brxlg= 0xec, op2_brxlg= 0x45,
op_svc = 0x0a,
};
/* Hardware capabilities. */
#ifndef HWCAP_S390_HIGH_GPRS
#define HWCAP_S390_HIGH_GPRS 512
#endif
#ifndef HWCAP_S390_TE
#define HWCAP_S390_TE 1024
#endif
#ifndef HWCAP_S390_VX
#define HWCAP_S390_VX 2048
#endif
/* Register information. */
/* Program Status Word. */
#define S390_PSWM_REGNUM 0
#define S390_PSWA_REGNUM 1
/* General Purpose Registers. */
#define S390_R0_REGNUM 2
#define S390_R1_REGNUM 3
#define S390_R2_REGNUM 4
#define S390_R3_REGNUM 5
#define S390_R4_REGNUM 6
#define S390_R5_REGNUM 7
#define S390_R6_REGNUM 8
#define S390_R7_REGNUM 9
#define S390_R8_REGNUM 10
#define S390_R9_REGNUM 11
#define S390_R10_REGNUM 12
#define S390_R11_REGNUM 13
#define S390_R12_REGNUM 14
#define S390_R13_REGNUM 15
#define S390_R14_REGNUM 16
#define S390_R15_REGNUM 17
/* Access Registers. */
#define S390_A0_REGNUM 18
#define S390_A1_REGNUM 19
#define S390_A2_REGNUM 20
#define S390_A3_REGNUM 21
#define S390_A4_REGNUM 22
#define S390_A5_REGNUM 23
#define S390_A6_REGNUM 24
#define S390_A7_REGNUM 25
#define S390_A8_REGNUM 26
#define S390_A9_REGNUM 27
#define S390_A10_REGNUM 28
#define S390_A11_REGNUM 29
#define S390_A12_REGNUM 30
#define S390_A13_REGNUM 31
#define S390_A14_REGNUM 32
#define S390_A15_REGNUM 33
/* Floating Point Control Word. */
#define S390_FPC_REGNUM 34
/* Floating Point Registers. */
#define S390_F0_REGNUM 35
#define S390_F1_REGNUM 36
#define S390_F2_REGNUM 37
#define S390_F3_REGNUM 38
#define S390_F4_REGNUM 39
#define S390_F5_REGNUM 40
#define S390_F6_REGNUM 41
#define S390_F7_REGNUM 42
#define S390_F8_REGNUM 43
#define S390_F9_REGNUM 44
#define S390_F10_REGNUM 45
#define S390_F11_REGNUM 46
#define S390_F12_REGNUM 47
#define S390_F13_REGNUM 48
#define S390_F14_REGNUM 49
#define S390_F15_REGNUM 50
/* General Purpose Register Upper Halves. */
#define S390_R0_UPPER_REGNUM 51
#define S390_R1_UPPER_REGNUM 52
#define S390_R2_UPPER_REGNUM 53
#define S390_R3_UPPER_REGNUM 54
#define S390_R4_UPPER_REGNUM 55
#define S390_R5_UPPER_REGNUM 56
#define S390_R6_UPPER_REGNUM 57
#define S390_R7_UPPER_REGNUM 58
#define S390_R8_UPPER_REGNUM 59
#define S390_R9_UPPER_REGNUM 60
#define S390_R10_UPPER_REGNUM 61
#define S390_R11_UPPER_REGNUM 62
#define S390_R12_UPPER_REGNUM 63
#define S390_R13_UPPER_REGNUM 64
#define S390_R14_UPPER_REGNUM 65
#define S390_R15_UPPER_REGNUM 66
/* GNU/Linux-specific optional registers. */
#define S390_ORIG_R2_REGNUM 67
#define S390_LAST_BREAK_REGNUM 68
#define S390_SYSTEM_CALL_REGNUM 69
/* Transaction diagnostic block. */
#define S390_TDB_DWORD0_REGNUM 70
#define S390_TDB_ABORT_CODE_REGNUM 71
#define S390_TDB_CONFLICT_TOKEN_REGNUM 72
#define S390_TDB_ATIA_REGNUM 73
#define S390_TDB_R0_REGNUM 74
#define S390_TDB_R1_REGNUM 75
#define S390_TDB_R2_REGNUM 76
#define S390_TDB_R3_REGNUM 77
#define S390_TDB_R4_REGNUM 78
#define S390_TDB_R5_REGNUM 79
#define S390_TDB_R6_REGNUM 80
#define S390_TDB_R7_REGNUM 81
#define S390_TDB_R8_REGNUM 82
#define S390_TDB_R9_REGNUM 83
#define S390_TDB_R10_REGNUM 84
#define S390_TDB_R11_REGNUM 85
#define S390_TDB_R12_REGNUM 86
#define S390_TDB_R13_REGNUM 87
#define S390_TDB_R14_REGNUM 88
#define S390_TDB_R15_REGNUM 89
/* Vector registers. */
#define S390_V0_LOWER_REGNUM 90
#define S390_V1_LOWER_REGNUM 91
#define S390_V2_LOWER_REGNUM 92
#define S390_V3_LOWER_REGNUM 93
#define S390_V4_LOWER_REGNUM 94
#define S390_V5_LOWER_REGNUM 95
#define S390_V6_LOWER_REGNUM 96
#define S390_V7_LOWER_REGNUM 97
#define S390_V8_LOWER_REGNUM 98
#define S390_V9_LOWER_REGNUM 99
#define S390_V10_LOWER_REGNUM 100
#define S390_V11_LOWER_REGNUM 101
#define S390_V12_LOWER_REGNUM 102
#define S390_V13_LOWER_REGNUM 103
#define S390_V14_LOWER_REGNUM 104
#define S390_V15_LOWER_REGNUM 105
#define S390_V16_REGNUM 106
#define S390_V17_REGNUM 107
#define S390_V18_REGNUM 108
#define S390_V19_REGNUM 109
#define S390_V20_REGNUM 110
#define S390_V21_REGNUM 111
#define S390_V22_REGNUM 112
#define S390_V23_REGNUM 113
#define S390_V24_REGNUM 114
#define S390_V25_REGNUM 115
#define S390_V26_REGNUM 116
#define S390_V27_REGNUM 117
#define S390_V28_REGNUM 118
#define S390_V29_REGNUM 119
#define S390_V30_REGNUM 120
#define S390_V31_REGNUM 121
/* Control registers. */
#define S390_TIMER_REGNUM 122
#define S390_TODCMP_REGNUM 123
#define S390_TODPREG_REGNUM 124
#define S390_CR0_REGNUM 125
#define S390_CR1_REGNUM 126
#define S390_CR2_REGNUM 127
#define S390_CR3_REGNUM 128
#define S390_CR4_REGNUM 129
#define S390_CR5_REGNUM 130
#define S390_CR6_REGNUM 131
#define S390_CR7_REGNUM 132
#define S390_CR8_REGNUM 133
#define S390_CR9_REGNUM 134
#define S390_CR10_REGNUM 135
#define S390_CR11_REGNUM 136
#define S390_CR12_REGNUM 137
#define S390_CR13_REGNUM 138
#define S390_CR14_REGNUM 139
#define S390_CR15_REGNUM 140
#define S390_PREFIX_REGNUM 141
/* Total. */
#define S390_NUM_REGS 142
#define S390_NUM_GPRS 16
#define S390_NUM_FPRS 16
#define S390_MAX_INSTR_SIZE 6
/* Special register usage. */
#define S390_SP_REGNUM S390_R15_REGNUM
#define S390_RETADDR_REGNUM S390_R14_REGNUM
#define S390_FRAME_REGNUM S390_R11_REGNUM
#define S390_IS_GREGSET_REGNUM(i) \
(((i) >= S390_PSWM_REGNUM && (i) <= S390_A15_REGNUM) \
|| ((i) >= S390_R0_UPPER_REGNUM && (i) <= S390_R15_UPPER_REGNUM) \
|| (i) == S390_ORIG_R2_REGNUM)
#define S390_IS_FPREGSET_REGNUM(i) \
((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM)
#define S390_IS_TDBREGSET_REGNUM(i) \
((i) >= S390_TDB_DWORD0_REGNUM && (i) <= S390_TDB_R15_REGNUM)
/* Definitions for address translation. */
/* DAT Table types. */
#define S390_LK_DAT_TT_REGION1 3
#define S390_LK_DAT_TT_REGION2 2
#define S390_LK_DAT_TT_REGION3 1
#define S390_LK_DAT_TT_SEGMENT 0
/* Region-First-Table */
#define S390_LK_RFTE_TL 0x3ULL /* Table-Length */
#define S390_LK_RFTE_TT 0xcULL /* Table-Type */
#define S390_LK_RFTE_I 0x20ULL /* Region-Invalid Bit */
#define S390_LK_RFTE_TF 0xc0ULL /* Table Offset */
#define S390_LK_RFTE_P 0x200ULL /* DAT-Protection Bit */
#define S390_LK_RFTE_O ~0xfffULL /* Region-Second-Table Origin */
/* Region-Second-Table flags. */
#define S390_LK_RSTE_TL 0x3ULL /* Table-Length */
#define S390_LK_RSTE_TT 0xcULL /* Table-Type */
#define S390_LK_RSTE_I 0x20ULL /* Region-Invalid Bit */
#define S390_LK_RSTE_TF 0xc0ULL /* Table Offset */
#define S390_LK_RSTE_P 0x200ULL /* DAT-Protection Bit */
#define S390_LK_RSTE_O ~0xfffULL /* Region-Third-Table Origin */
/* Region-Third-Table flags. */
#define S390_LK_RTTE_TL 0x3ULL /* Table-Length */
#define S390_LK_RTTE_TT 0xcULL /* Table-Type */
#define S390_LK_RTTE_CR 0x10ULL /* Common-Region Bit */
#define S390_LK_RTTE_I 0x20ULL /* Region-Invalid Bit */
#define S390_LK_RTTE_TF 0xc0ULL /* Table Offset */
#define S390_LK_RTTE_P 0x200ULL /* DAT-Protection Bit */
#define S390_LK_RTTE_FC 0x400ULL /* Format-Control Bit */
#define S390_LK_RTTE_F 0x800ULL /* Fetch-Protection Bit */
#define S390_LK_RTTE_ACC 0xf000ULL /* Access-Control Bits */
#define S390_LK_RTTE_AV 0x10000ULL /* ACCF-Validity Control */
#define S390_LK_RTTE_O ~0xfffULL /* Segment-Table Origin */
#define S390_LK_RTTE_RFAA ~0x7fffffffULL /* Region-Frame Absolute Address */
/* Segment-Table flags. */
#define S390_LK_STE_TT 0xcULL /* Table-Type */
#define S390_LK_STE_I 0x20ULL /* Segment-Invalid Bit */
#define S390_LK_STE_TF 0xc0ULL /* Table Offset */
#define S390_LK_STE_P 0x200ULL /* DAT-Protection Bit */
#define S390_LK_STE_FC 0x400ULL /* Format-Control Bit */
#define S390_LK_STE_F 0x800ULL /* Fetch-Protection Bit */
#define S390_LK_STE_ACC 0xf000ULL /* Access-Control Bits */
#define S390_LK_STE_AV 0x10000ULL /* ACCF-Validity Control */
#define S390_LK_STE_O ~0x7ffULL /* Page-Table Origin */
#define S390_LK_STE_SFAA ~0xfffffULL /* Segment-Frame Absolute Address */
/* Page-Table flags. */
#define S390_LK_PTE_P 0x200ULL /* DAT-Protection Bit */
#define S390_LK_PTE_I 0x400ULL /* Page-Invalid Bit */
#define S390_LK_PTE_PFAA ~0xfffULL /* Page-Frame Absolute Address */
/* Virtual Address Fields. */
#define S390_LK_VADDR_RFX 0xffe0000000000000ULL
#define S390_LK_VADDR_RSX 0x001ffc0000000000ULL
#define S390_LK_VADDR_RTX 0x000003ff80000000ULL
#define S390_LK_VADDR_SX 0x000000007ff00000ULL
#define S390_LK_VADDR_PX 0x00000000000ff000ULL
#define S390_LK_VADDR_BX 0x0000000000000fffULL
#endif /* S390_TDEP_H */

View File

@@ -107,6 +107,14 @@ show_solib_search_path (struct ui_file *file, int from_tty,
value);
}
/* see solib.h. */
const char *
get_solib_search_path ()
{
return solib_search_path ? solib_search_path : "";
}
/* Same as HAVE_DOS_BASED_FILE_SYSTEM, but useable as an rvalue. */
#if (HAVE_DOS_BASED_FILE_SYSTEM)
# define DOS_BASED_FILE_SYSTEM 1

View File

@@ -28,6 +28,11 @@ struct program_space;
#include "symfile-add-flags.h"
/* Returns the solib_search_path. The returned string is malloc'ed and must be
freed by the caller. */
extern const char *get_solib_search_path ();
/* Called when we free all symtabs, to free the shared library information
as well. */

View File

@@ -39,12 +39,6 @@
extern void _initialize_typeprint (void);
static void ptype_command (char *, int);
static void whatis_command (char *, int);
static void whatis_exp (char *, int);
const struct type_print_options type_print_raw_options =
{
1, /* raw */
@@ -389,7 +383,7 @@ type_to_string (struct type *type)
/* Print type of EXP, or last thing in value history if EXP == NULL.
show is passed to type_print. */
static void
void
whatis_exp (char *exp, int show)
{
struct value *val;

View File

@@ -78,4 +78,6 @@ extern void val_print_not_allocated (struct ui_file *stream);
extern void val_print_not_associated (struct ui_file *stream);
extern void whatis_exp (char *exp, int show);
#endif

View File

@@ -66,6 +66,8 @@
#include "interps.h"
#include "gdb_regex.h"
#include <string>
#if !HAVE_DECL_MALLOC
extern PTR malloc (); /* ARI: PTR */
#endif
@@ -3156,49 +3158,71 @@ make_cleanup_free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec)
return make_cleanup (do_free_char_ptr_vec, char_ptr_vec);
}
/* Substitute all occurences of string FROM by string TO in *STRINGP. *STRINGP
must come from xrealloc-compatible allocator and it may be updated. FROM
needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be
located at the start or end of *STRINGP. */
/* See utils.h. */
void
substitute_path_component (char **stringp, const char *from, const char *to)
substitute_path_component (std::string &str, const std::string &from,
const std::string &to)
{
char *string = *stringp, *s;
const size_t from_len = strlen (from);
const size_t to_len = strlen (to);
for (s = string;;)
for (size_t pos = str.find (from); pos != std::string::npos;
pos = str.find (from, pos + 1))
{
s = strstr (s, from);
if (s == NULL)
break;
if ((s == string || IS_DIR_SEPARATOR (s[-1])
|| s[-1] == DIRNAME_SEPARATOR)
&& (s[from_len] == '\0' || IS_DIR_SEPARATOR (s[from_len])
|| s[from_len] == DIRNAME_SEPARATOR))
char start, end;
start = str[pos - 1];
end = str[pos + from.length ()];
if ((pos == 0 || IS_DIR_SEPARATOR (start) || start == DIRNAME_SEPARATOR)
&& (end == '\0' || IS_DIR_SEPARATOR (end)
|| end == DIRNAME_SEPARATOR))
{
char *string_new;
string_new
= (char *) xrealloc (string, (strlen (string) + to_len + 1));
/* Relocate the current S pointer. */
s = s - string + string_new;
string = string_new;
/* Replace from by to. */
memmove (&s[to_len], &s[from_len], strlen (&s[from_len]) + 1);
memcpy (s, to, to_len);
s += to_len;
str.replace (pos, from.length (), to);
}
else
s++;
}
}
/* Approximate length of final path. Helper for concat_path. */
static inline unsigned long
approx_path_length (std::initializer_list<std::string> args,
std::string dir_separator)
{
size_t length = 0;
for (const std::string &arg: args)
length += arg.length () + dir_separator.length ();
return length;
}
/* See utils.h. */
std::string
_concat_path (std::initializer_list<std::string> args,
std::string dir_separator)
{
std::string dst;
dst.reserve (approx_path_length (args, dir_separator));
for (const std::string &arg : args)
{
if (arg.empty ())
continue;
if (startswith (arg.c_str (), dir_separator.c_str ())
&& endswith (dst.c_str (), dir_separator.c_str ()))
dst.erase (dst.length () - dir_separator.length (),
dir_separator.length ());
else if (!dst.empty ()
&& !startswith (arg.c_str (), dir_separator.c_str ())
&& !endswith (dst.c_str (), dir_separator.c_str ())
&& dst != TARGET_SYSROOT_PREFIX)
dst += dir_separator;
dst += arg;
}
*stringp = string;
dst.shrink_to_fit ();
return dst;
}
#ifdef HAVE_WAITPID

View File

@@ -24,6 +24,7 @@
#include "exceptions.h"
#include "common/scoped_restore.h"
#include <chrono>
#include <string>
extern void initialize_utils (void);
@@ -132,8 +133,29 @@ extern char *gdb_abspath (const char *);
extern int gdb_filename_fnmatch (const char *pattern, const char *string,
int flags);
extern void substitute_path_component (char **stringp, const char *from,
const char *to);
/* Substitute all occurences of string FROM by string TO in STR. FROM
needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be
located at the start or end of STR). */
extern void substitute_path_component (std::string &str,
const std::string &from,
const std::string &to);
/* Concatenate an arbitrary number of path elements. Adds and removes
directory separators as needed.
concat_path (/first, second) => /first/second
concat_path (first, second) => first/second
concat_path (first/, second) => first/second
concat_path (first, /second) => first/second
concat_path (first/, /second) => first/second
concat_path (target:, second) => target:second
*/
extern std::string _concat_path (std::initializer_list<std::string> args,
std::string dir_separator);
#define concat_path(...) _concat_path ({__VA_ARGS__}, SLASH_STRING)
char *ldirname (const char *filename);