From 06b3c5bdb018262d7c09cda9d4637015c7ebe779 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Thu, 13 Feb 2020 16:27:02 -0500 Subject: gdbsupport: rename source files to .cc This patch renames the .c source files in gdbsupport to .cc. In the gdb directory, there is an argument against renaming the source files, which is that it makes using some git commands more difficult to do archeology. Some commands have some kind of "follow" option that makes git try to follow renames, but it doesn't work in all situations. Given that we have just moved the gdbsupport directory, that argument doesn't hold for source files in that directory. I therefore suggest renaming them to .cc, so that they are automatically recognized as C++ by various tools and editors. The original motivation behind this is that when building gdbsupport with clang, I get: CC agent.o clang: error: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Werror,-Wdeprecated] In the gdb/ directory, we make clang happy by passing "-x c++". We could do this in gdbsupport too, but I think that renaming the files is a better long-term solution. gdbserver still does its own build of gdbsupport, so a few changes in its Makefile are necessary. gdbsupport/ChangeLog: * Makefile.am: Rename source files from .c to .cc. (CC, CFLAGS): Don't override. (AM_CFLAGS): Rename to ... (AM_CXXFLAGS): ... this. * Makefile.in: Re-generate. * %.c: Rename to %.cc. gdbserver/ChangeLog: * Makefile.in: Rename gdbsupport source files from .c to .cc. --- gdbsupport/ChangeLog | 9 + gdbsupport/Makefile.am | 73 ++-- gdbsupport/Makefile.in | 126 +++--- gdbsupport/agent.c | 280 ------------- gdbsupport/agent.cc | 280 +++++++++++++ gdbsupport/btrace-common.c | 190 --------- gdbsupport/btrace-common.cc | 190 +++++++++ gdbsupport/buffer.c | 178 --------- gdbsupport/buffer.cc | 178 +++++++++ gdbsupport/cleanups.c | 144 ------- gdbsupport/cleanups.cc | 144 +++++++ gdbsupport/common-debug.c | 37 -- gdbsupport/common-debug.cc | 37 ++ gdbsupport/common-exceptions.c | 235 ----------- gdbsupport/common-exceptions.cc | 235 +++++++++++ gdbsupport/common-inferior.c | 26 -- gdbsupport/common-inferior.cc | 26 ++ gdbsupport/common-regcache.c | 36 -- gdbsupport/common-regcache.cc | 36 ++ gdbsupport/common-utils.c | 417 -------------------- gdbsupport/common-utils.cc | 417 ++++++++++++++++++++ gdbsupport/environ.c | 183 --------- gdbsupport/environ.cc | 183 +++++++++ gdbsupport/errors.c | 69 ---- gdbsupport/errors.cc | 69 ++++ gdbsupport/fileio.c | 255 ------------ gdbsupport/fileio.cc | 255 ++++++++++++ gdbsupport/filestuff.c | 503 ------------------------ gdbsupport/filestuff.cc | 503 ++++++++++++++++++++++++ gdbsupport/format.c | 412 ------------------- gdbsupport/format.cc | 412 +++++++++++++++++++ gdbsupport/gdb-dlfcn.c | 118 ------ gdbsupport/gdb-dlfcn.cc | 118 ++++++ gdbsupport/gdb_tilde_expand.c | 95 ----- gdbsupport/gdb_tilde_expand.cc | 95 +++++ gdbsupport/gdb_vecs.c | 88 ----- gdbsupport/gdb_vecs.cc | 88 +++++ gdbsupport/gdb_wait.c | 85 ---- gdbsupport/gdb_wait.cc | 85 ++++ gdbsupport/job-control.c | 86 ---- gdbsupport/job-control.cc | 86 ++++ gdbsupport/netstuff.c | 154 -------- gdbsupport/netstuff.cc | 154 ++++++++ gdbsupport/new-op.c | 95 ----- gdbsupport/new-op.cc | 95 +++++ gdbsupport/pathstuff.c | 290 -------------- gdbsupport/pathstuff.cc | 290 ++++++++++++++ gdbsupport/print-utils.c | 326 --------------- gdbsupport/print-utils.cc | 326 +++++++++++++++ gdbsupport/ptid.c | 26 -- gdbsupport/ptid.cc | 26 ++ gdbsupport/rsp-low.c | 307 --------------- gdbsupport/rsp-low.cc | 307 +++++++++++++++ gdbsupport/run-time-clock.c | 58 --- gdbsupport/run-time-clock.cc | 58 +++ gdbsupport/safe-strerror.c | 56 --- gdbsupport/safe-strerror.cc | 56 +++ gdbsupport/scoped_mmap.c | 49 --- gdbsupport/scoped_mmap.cc | 49 +++ gdbsupport/selftest.c | 111 ------ gdbsupport/selftest.cc | 111 ++++++ gdbsupport/signals-state-save-restore.c | 114 ------ gdbsupport/signals-state-save-restore.cc | 114 ++++++ gdbsupport/signals.c | 653 ------------------------------- gdbsupport/signals.cc | 653 +++++++++++++++++++++++++++++++ gdbsupport/tdesc.c | 401 ------------------- gdbsupport/tdesc.cc | 401 +++++++++++++++++++ gdbsupport/thread-pool.c | 175 --------- gdbsupport/thread-pool.cc | 175 +++++++++ gdbsupport/xml-utils.c | 63 --- gdbsupport/xml-utils.cc | 63 +++ 71 files changed, 6420 insertions(+), 6418 deletions(-) delete mode 100644 gdbsupport/agent.c create mode 100644 gdbsupport/agent.cc delete mode 100644 gdbsupport/btrace-common.c create mode 100644 gdbsupport/btrace-common.cc delete mode 100644 gdbsupport/buffer.c create mode 100644 gdbsupport/buffer.cc delete mode 100644 gdbsupport/cleanups.c create mode 100644 gdbsupport/cleanups.cc delete mode 100644 gdbsupport/common-debug.c create mode 100644 gdbsupport/common-debug.cc delete mode 100644 gdbsupport/common-exceptions.c create mode 100644 gdbsupport/common-exceptions.cc delete mode 100644 gdbsupport/common-inferior.c create mode 100644 gdbsupport/common-inferior.cc delete mode 100644 gdbsupport/common-regcache.c create mode 100644 gdbsupport/common-regcache.cc delete mode 100644 gdbsupport/common-utils.c create mode 100644 gdbsupport/common-utils.cc delete mode 100644 gdbsupport/environ.c create mode 100644 gdbsupport/environ.cc delete mode 100644 gdbsupport/errors.c create mode 100644 gdbsupport/errors.cc delete mode 100644 gdbsupport/fileio.c create mode 100644 gdbsupport/fileio.cc delete mode 100644 gdbsupport/filestuff.c create mode 100644 gdbsupport/filestuff.cc delete mode 100644 gdbsupport/format.c create mode 100644 gdbsupport/format.cc delete mode 100644 gdbsupport/gdb-dlfcn.c create mode 100644 gdbsupport/gdb-dlfcn.cc delete mode 100644 gdbsupport/gdb_tilde_expand.c create mode 100644 gdbsupport/gdb_tilde_expand.cc delete mode 100644 gdbsupport/gdb_vecs.c create mode 100644 gdbsupport/gdb_vecs.cc delete mode 100644 gdbsupport/gdb_wait.c create mode 100644 gdbsupport/gdb_wait.cc delete mode 100644 gdbsupport/job-control.c create mode 100644 gdbsupport/job-control.cc delete mode 100644 gdbsupport/netstuff.c create mode 100644 gdbsupport/netstuff.cc delete mode 100644 gdbsupport/new-op.c create mode 100644 gdbsupport/new-op.cc delete mode 100644 gdbsupport/pathstuff.c create mode 100644 gdbsupport/pathstuff.cc delete mode 100644 gdbsupport/print-utils.c create mode 100644 gdbsupport/print-utils.cc delete mode 100644 gdbsupport/ptid.c create mode 100644 gdbsupport/ptid.cc delete mode 100644 gdbsupport/rsp-low.c create mode 100644 gdbsupport/rsp-low.cc delete mode 100644 gdbsupport/run-time-clock.c create mode 100644 gdbsupport/run-time-clock.cc delete mode 100644 gdbsupport/safe-strerror.c create mode 100644 gdbsupport/safe-strerror.cc delete mode 100644 gdbsupport/scoped_mmap.c create mode 100644 gdbsupport/scoped_mmap.cc delete mode 100644 gdbsupport/selftest.c create mode 100644 gdbsupport/selftest.cc delete mode 100644 gdbsupport/signals-state-save-restore.c create mode 100644 gdbsupport/signals-state-save-restore.cc delete mode 100644 gdbsupport/signals.c create mode 100644 gdbsupport/signals.cc delete mode 100644 gdbsupport/tdesc.c create mode 100644 gdbsupport/tdesc.cc delete mode 100644 gdbsupport/thread-pool.c create mode 100644 gdbsupport/thread-pool.cc delete mode 100644 gdbsupport/xml-utils.c create mode 100644 gdbsupport/xml-utils.cc (limited to 'gdbsupport') diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog index bb7ae97..0634e37 100644 --- a/gdbsupport/ChangeLog +++ b/gdbsupport/ChangeLog @@ -1,3 +1,12 @@ +2020-02-13 Simon Marchi + + * Makefile.am: Rename source files from .c to .cc. + (CC, CFLAGS): Don't override. + (AM_CFLAGS): Rename to ... + (AM_CXXFLAGS): ... this. + * Makefile.in: Re-generate. + * %.c: Rename to %.cc. + 2020-02-11 Simon Marchi * configure: Re-generate. diff --git a/gdbsupport/Makefile.am b/gdbsupport/Makefile.am index cd7b0ad..ee78a89 100644 --- a/gdbsupport/Makefile.am +++ b/gdbsupport/Makefile.am @@ -26,51 +26,48 @@ AM_CPPFLAGS = -I$(srcdir)/../include -I$(srcdir)/../gdb \ override CXX += $(CXX_DIALECT) -override CC := $(CXX) -override CFLAGS := $(CXXFLAGS) - -AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) +AM_CXXFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) noinst_LIBRARIES = libgdbsupport.a if SELFTEST -selftest = selftest.c +selftest = selftest.cc endif libgdbsupport_a_SOURCES = \ - agent.c \ - btrace-common.c \ - buffer.c \ - cleanups.c \ - common-debug.c \ - common-exceptions.c \ - common-inferior.c \ - common-regcache.c \ - common-utils.c \ - environ.c \ - errors.c \ - fileio.c \ - filestuff.c \ - format.c \ - gdb-dlfcn.c \ - gdb_tilde_expand.c \ - gdb_wait.c \ - gdb_vecs.c \ - job-control.c \ - netstuff.c \ - new-op.c \ - pathstuff.c \ - print-utils.c \ - ptid.c \ - rsp-low.c \ - run-time-clock.c \ - safe-strerror.c \ - scoped_mmap.c \ - signals.c \ - signals-state-save-restore.c \ - tdesc.c \ - thread-pool.c \ - xml-utils.c \ + agent.cc \ + btrace-common.cc \ + buffer.cc \ + cleanups.cc \ + common-debug.cc \ + common-exceptions.cc \ + common-inferior.cc \ + common-regcache.cc \ + common-utils.cc \ + environ.cc \ + errors.cc \ + fileio.cc \ + filestuff.cc \ + format.cc \ + gdb-dlfcn.cc \ + gdb_tilde_expand.cc \ + gdb_wait.cc \ + gdb_vecs.cc \ + job-control.cc \ + netstuff.cc \ + new-op.cc \ + pathstuff.cc \ + print-utils.cc \ + ptid.cc \ + rsp-low.cc \ + run-time-clock.cc \ + safe-strerror.cc \ + scoped_mmap.cc \ + signals.cc \ + signals-state-save-restore.cc \ + tdesc.cc \ + thread-pool.cc \ + xml-utils.cc \ $(selftest) # Double-check that no defines are missing from our configury. diff --git a/gdbsupport/Makefile.in b/gdbsupport/Makefile.in index be4d535..4e12354 100644 --- a/gdbsupport/Makefile.in +++ b/gdbsupport/Makefile.in @@ -177,18 +177,19 @@ DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/../depcomp am__depfiles_maybe = depfiles am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = SOURCES = $(libgdbsupport_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ @@ -353,50 +354,50 @@ AM_CPPFLAGS = -I$(srcdir)/../include -I$(srcdir)/../gdb \ -I../gnulib/import -I$(srcdir)/../gnulib/import \ -I.. -I$(srcdir)/.. $(INCINTL) -I../bfd -I$(srcdir)/../bfd -AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) +AM_CXXFLAGS = $(CXX_DIALECT) $(WARN_CFLAGS) $(WERROR_CFLAGS) noinst_LIBRARIES = libgdbsupport.a -@SELFTEST_TRUE@selftest = selftest.c +@SELFTEST_TRUE@selftest = selftest.cc libgdbsupport_a_SOURCES = \ - agent.c \ - btrace-common.c \ - buffer.c \ - cleanups.c \ - common-debug.c \ - common-exceptions.c \ - common-inferior.c \ - common-regcache.c \ - common-utils.c \ - environ.c \ - errors.c \ - fileio.c \ - filestuff.c \ - format.c \ - gdb-dlfcn.c \ - gdb_tilde_expand.c \ - gdb_wait.c \ - gdb_vecs.c \ - job-control.c \ - netstuff.c \ - new-op.c \ - pathstuff.c \ - print-utils.c \ - ptid.c \ - rsp-low.c \ - run-time-clock.c \ - safe-strerror.c \ - scoped_mmap.c \ - signals.c \ - signals-state-save-restore.c \ - tdesc.c \ - thread-pool.c \ - xml-utils.c \ + agent.cc \ + btrace-common.cc \ + buffer.cc \ + cleanups.cc \ + common-debug.cc \ + common-exceptions.cc \ + common-inferior.cc \ + common-regcache.cc \ + common-utils.cc \ + environ.cc \ + errors.cc \ + fileio.cc \ + filestuff.cc \ + format.cc \ + gdb-dlfcn.cc \ + gdb_tilde_expand.cc \ + gdb_wait.cc \ + gdb_vecs.cc \ + job-control.cc \ + netstuff.cc \ + new-op.cc \ + pathstuff.cc \ + print-utils.cc \ + ptid.cc \ + rsp-low.cc \ + run-time-clock.cc \ + safe-strerror.cc \ + scoped_mmap.cc \ + signals.cc \ + signals-state-save-restore.cc \ + tdesc.cc \ + thread-pool.cc \ + xml-utils.cc \ $(selftest) all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: -.SUFFIXES: .c .o .obj +.SUFFIXES: .cc .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @@ -495,19 +496,19 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml-utils.Po@am__quote@ -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique @@ -692,11 +693,6 @@ uninstall-am: .PRECIOUS: Makefile -override CXX += $(CXX_DIALECT) - -override CC := $(CXX) -override CFLAGS := $(CXXFLAGS) - # Double-check that no defines are missing from our configury. check-defines: cd $(srcdir) && emacs --script check-defines.el diff --git a/gdbsupport/agent.c b/gdbsupport/agent.c deleted file mode 100644 index b4127ff..0000000 --- a/gdbsupport/agent.c +++ /dev/null @@ -1,280 +0,0 @@ -/* Shared utility routines for GDB to interact with agent. - - Copyright (C) 2009-2020 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 . */ - -#include "common-defs.h" -#include "target/target.h" -#include "gdbsupport/symbol.h" -#include -#include "filestuff.h" - -#define IPA_SYM_STRUCT_NAME ipa_sym_addresses_common -#include "agent.h" - -bool debug_agent = false; - -/* A stdarg wrapper for debug_vprintf. */ - -static void ATTRIBUTE_PRINTF (1, 2) -debug_agent_printf (const char *fmt, ...) -{ - va_list ap; - - if (!debug_agent) - return; - va_start (ap, fmt); - debug_vprintf (fmt, ap); - va_end (ap); -} - -#define DEBUG_AGENT debug_agent_printf - -/* Global flag to determine using agent or not. */ -bool use_agent = false; - -/* Addresses of in-process agent's symbols both GDB and GDBserver cares - about. */ - -struct ipa_sym_addresses_common -{ - CORE_ADDR addr_helper_thread_id; - CORE_ADDR addr_cmd_buf; - CORE_ADDR addr_capability; -}; - -/* Cache of the helper thread id. FIXME: this global should be made - per-process. */ -static uint32_t helper_thread_id = 0; - -static struct -{ - const char *name; - int offset; -} symbol_list[] = { - IPA_SYM(helper_thread_id), - IPA_SYM(cmd_buf), - IPA_SYM(capability), -}; - -static struct ipa_sym_addresses_common ipa_sym_addrs; - -static bool all_agent_symbols_looked_up = false; - -bool -agent_loaded_p (void) -{ - return all_agent_symbols_looked_up; -} - -/* Look up all symbols needed by agent. Return 0 if all the symbols are - found, return non-zero otherwise. */ - -int -agent_look_up_symbols (void *arg) -{ - all_agent_symbols_looked_up = false; - - for (int i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++) - { - CORE_ADDR *addrp = - (CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset); - struct objfile *objfile = (struct objfile *) arg; - - if (find_minimal_symbol_address (symbol_list[i].name, addrp, - objfile) != 0) - { - DEBUG_AGENT ("symbol `%s' not found\n", symbol_list[i].name); - return -1; - } - } - - all_agent_symbols_looked_up = true; - return 0; -} - -static unsigned int -agent_get_helper_thread_id (void) -{ - if (helper_thread_id == 0) - { - if (target_read_uint32 (ipa_sym_addrs.addr_helper_thread_id, - &helper_thread_id)) - warning (_("Error reading helper thread's id in lib")); - } - - return helper_thread_id; -} - -#ifdef HAVE_SYS_UN_H -#include -#include -#define SOCK_DIR P_tmpdir - -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) -#endif - -#endif - -/* Connects to synchronization socket. PID is the pid of inferior, which is - used to set up the connection socket. */ - -static int -gdb_connect_sync_socket (int pid) -{ -#ifdef HAVE_SYS_UN_H - struct sockaddr_un addr; - int res, fd; - char path[UNIX_PATH_MAX]; - - res = xsnprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", P_tmpdir, pid); - if (res >= UNIX_PATH_MAX) - return -1; - - res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0); - if (res == -1) - { - warning (_("error opening sync socket: %s"), safe_strerror (errno)); - return -1; - } - - addr.sun_family = AF_UNIX; - - res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path); - if (res >= UNIX_PATH_MAX) - { - warning (_("string overflow allocating socket name")); - close (fd); - return -1; - } - - res = connect (fd, (struct sockaddr *) &addr, sizeof (addr)); - if (res == -1) - { - warning (_("error connecting sync socket (%s): %s. " - "Make sure the directory exists and that it is writable."), - path, safe_strerror (errno)); - close (fd); - return -1; - } - - return fd; -#else - return -1; -#endif -} - -/* Execute an agent command in the inferior. PID is the value of pid of the - inferior. CMD is the buffer for command. GDB or GDBserver will store the - command into it and fetch the return result from CMD. The interaction - between GDB/GDBserver and the agent is synchronized by a synchronization - socket. Return zero if success, otherwise return non-zero. */ - -int -agent_run_command (int pid, const char *cmd, int len) -{ - int fd; - int tid = agent_get_helper_thread_id (); - ptid_t ptid = ptid_t (pid, tid, 0); - - int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, - (gdb_byte *) cmd, len); - - if (ret != 0) - { - warning (_("unable to write")); - return -1; - } - - DEBUG_AGENT ("agent: resumed helper thread\n"); - - /* Resume helper thread. */ - target_continue_no_signal (ptid); - - fd = gdb_connect_sync_socket (pid); - if (fd >= 0) - { - char buf[1] = ""; - - DEBUG_AGENT ("agent: signalling helper thread\n"); - - do - { - ret = write (fd, buf, 1); - } while (ret == -1 && errno == EINTR); - - DEBUG_AGENT ("agent: waiting for helper thread's response\n"); - - do - { - ret = read (fd, buf, 1); - } while (ret == -1 && errno == EINTR); - - close (fd); - - DEBUG_AGENT ("agent: helper thread's response received\n"); - } - else - return -1; - - /* Need to read response with the inferior stopped. */ - if (ptid != null_ptid) - { - /* Stop thread PTID. */ - DEBUG_AGENT ("agent: stop helper thread\n"); - target_stop_and_wait (ptid); - } - - if (fd >= 0) - { - if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, - IPA_CMD_BUF_SIZE)) - { - warning (_("Error reading command response")); - return -1; - } - } - - return 0; -} - -/* Each bit of it stands for a capability of agent. */ -static uint32_t agent_capability = 0; - -/* Return true if agent has capability AGENT_CAP, otherwise return false. */ - -bool -agent_capability_check (enum agent_capa agent_capa) -{ - if (agent_capability == 0) - { - if (target_read_uint32 (ipa_sym_addrs.addr_capability, - &agent_capability)) - warning (_("Error reading capability of agent")); - } - return (agent_capability & agent_capa) != 0; -} - -/* Invalidate the cache of agent capability, so we'll read it from inferior - again. Call it when launches a new program or reconnect to remote stub. */ - -void -agent_capability_invalidate (void) -{ - agent_capability = 0; -} diff --git a/gdbsupport/agent.cc b/gdbsupport/agent.cc new file mode 100644 index 0000000..b4127ff --- /dev/null +++ b/gdbsupport/agent.cc @@ -0,0 +1,280 @@ +/* Shared utility routines for GDB to interact with agent. + + Copyright (C) 2009-2020 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 . */ + +#include "common-defs.h" +#include "target/target.h" +#include "gdbsupport/symbol.h" +#include +#include "filestuff.h" + +#define IPA_SYM_STRUCT_NAME ipa_sym_addresses_common +#include "agent.h" + +bool debug_agent = false; + +/* A stdarg wrapper for debug_vprintf. */ + +static void ATTRIBUTE_PRINTF (1, 2) +debug_agent_printf (const char *fmt, ...) +{ + va_list ap; + + if (!debug_agent) + return; + va_start (ap, fmt); + debug_vprintf (fmt, ap); + va_end (ap); +} + +#define DEBUG_AGENT debug_agent_printf + +/* Global flag to determine using agent or not. */ +bool use_agent = false; + +/* Addresses of in-process agent's symbols both GDB and GDBserver cares + about. */ + +struct ipa_sym_addresses_common +{ + CORE_ADDR addr_helper_thread_id; + CORE_ADDR addr_cmd_buf; + CORE_ADDR addr_capability; +}; + +/* Cache of the helper thread id. FIXME: this global should be made + per-process. */ +static uint32_t helper_thread_id = 0; + +static struct +{ + const char *name; + int offset; +} symbol_list[] = { + IPA_SYM(helper_thread_id), + IPA_SYM(cmd_buf), + IPA_SYM(capability), +}; + +static struct ipa_sym_addresses_common ipa_sym_addrs; + +static bool all_agent_symbols_looked_up = false; + +bool +agent_loaded_p (void) +{ + return all_agent_symbols_looked_up; +} + +/* Look up all symbols needed by agent. Return 0 if all the symbols are + found, return non-zero otherwise. */ + +int +agent_look_up_symbols (void *arg) +{ + all_agent_symbols_looked_up = false; + + for (int i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++) + { + CORE_ADDR *addrp = + (CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset); + struct objfile *objfile = (struct objfile *) arg; + + if (find_minimal_symbol_address (symbol_list[i].name, addrp, + objfile) != 0) + { + DEBUG_AGENT ("symbol `%s' not found\n", symbol_list[i].name); + return -1; + } + } + + all_agent_symbols_looked_up = true; + return 0; +} + +static unsigned int +agent_get_helper_thread_id (void) +{ + if (helper_thread_id == 0) + { + if (target_read_uint32 (ipa_sym_addrs.addr_helper_thread_id, + &helper_thread_id)) + warning (_("Error reading helper thread's id in lib")); + } + + return helper_thread_id; +} + +#ifdef HAVE_SYS_UN_H +#include +#include +#define SOCK_DIR P_tmpdir + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) +#endif + +#endif + +/* Connects to synchronization socket. PID is the pid of inferior, which is + used to set up the connection socket. */ + +static int +gdb_connect_sync_socket (int pid) +{ +#ifdef HAVE_SYS_UN_H + struct sockaddr_un addr; + int res, fd; + char path[UNIX_PATH_MAX]; + + res = xsnprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", P_tmpdir, pid); + if (res >= UNIX_PATH_MAX) + return -1; + + res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0); + if (res == -1) + { + warning (_("error opening sync socket: %s"), safe_strerror (errno)); + return -1; + } + + addr.sun_family = AF_UNIX; + + res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path); + if (res >= UNIX_PATH_MAX) + { + warning (_("string overflow allocating socket name")); + close (fd); + return -1; + } + + res = connect (fd, (struct sockaddr *) &addr, sizeof (addr)); + if (res == -1) + { + warning (_("error connecting sync socket (%s): %s. " + "Make sure the directory exists and that it is writable."), + path, safe_strerror (errno)); + close (fd); + return -1; + } + + return fd; +#else + return -1; +#endif +} + +/* Execute an agent command in the inferior. PID is the value of pid of the + inferior. CMD is the buffer for command. GDB or GDBserver will store the + command into it and fetch the return result from CMD. The interaction + between GDB/GDBserver and the agent is synchronized by a synchronization + socket. Return zero if success, otherwise return non-zero. */ + +int +agent_run_command (int pid, const char *cmd, int len) +{ + int fd; + int tid = agent_get_helper_thread_id (); + ptid_t ptid = ptid_t (pid, tid, 0); + + int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, + (gdb_byte *) cmd, len); + + if (ret != 0) + { + warning (_("unable to write")); + return -1; + } + + DEBUG_AGENT ("agent: resumed helper thread\n"); + + /* Resume helper thread. */ + target_continue_no_signal (ptid); + + fd = gdb_connect_sync_socket (pid); + if (fd >= 0) + { + char buf[1] = ""; + + DEBUG_AGENT ("agent: signalling helper thread\n"); + + do + { + ret = write (fd, buf, 1); + } while (ret == -1 && errno == EINTR); + + DEBUG_AGENT ("agent: waiting for helper thread's response\n"); + + do + { + ret = read (fd, buf, 1); + } while (ret == -1 && errno == EINTR); + + close (fd); + + DEBUG_AGENT ("agent: helper thread's response received\n"); + } + else + return -1; + + /* Need to read response with the inferior stopped. */ + if (ptid != null_ptid) + { + /* Stop thread PTID. */ + DEBUG_AGENT ("agent: stop helper thread\n"); + target_stop_and_wait (ptid); + } + + if (fd >= 0) + { + if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, + IPA_CMD_BUF_SIZE)) + { + warning (_("Error reading command response")); + return -1; + } + } + + return 0; +} + +/* Each bit of it stands for a capability of agent. */ +static uint32_t agent_capability = 0; + +/* Return true if agent has capability AGENT_CAP, otherwise return false. */ + +bool +agent_capability_check (enum agent_capa agent_capa) +{ + if (agent_capability == 0) + { + if (target_read_uint32 (ipa_sym_addrs.addr_capability, + &agent_capability)) + warning (_("Error reading capability of agent")); + } + return (agent_capability & agent_capa) != 0; +} + +/* Invalidate the cache of agent capability, so we'll read it from inferior + again. Call it when launches a new program or reconnect to remote stub. */ + +void +agent_capability_invalidate (void) +{ + agent_capability = 0; +} diff --git a/gdbsupport/btrace-common.c b/gdbsupport/btrace-common.c deleted file mode 100644 index 7d4f642..0000000 --- a/gdbsupport/btrace-common.c +++ /dev/null @@ -1,190 +0,0 @@ -/* Copyright (C) 2014-2020 Free Software Foundation, Inc. - - Contributed by Intel Corp. - - 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 . */ - -#include "common-defs.h" -#include "btrace-common.h" - - -/* See btrace-common.h. */ - -const char * -btrace_format_string (enum btrace_format format) -{ - switch (format) - { - case BTRACE_FORMAT_NONE: - return _("No or unknown format"); - - case BTRACE_FORMAT_BTS: - return _("Branch Trace Store"); - - case BTRACE_FORMAT_PT: - return _("Intel Processor Trace"); - } - - internal_error (__FILE__, __LINE__, _("Unknown branch trace format")); -} - -/* See btrace-common.h. */ - -const char * -btrace_format_short_string (enum btrace_format format) -{ - switch (format) - { - case BTRACE_FORMAT_NONE: - return "unknown"; - - case BTRACE_FORMAT_BTS: - return "bts"; - - case BTRACE_FORMAT_PT: - return "pt"; - } - - internal_error (__FILE__, __LINE__, _("Unknown branch trace format")); -} - -/* See btrace-common.h. */ - -void -btrace_data::fini () -{ - switch (format) - { - case BTRACE_FORMAT_NONE: - /* Nothing to do. */ - return; - - case BTRACE_FORMAT_BTS: - delete variant.bts.blocks; - variant.bts.blocks = nullptr; - return; - - case BTRACE_FORMAT_PT: - xfree (variant.pt.data); - return; - } - - internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); -} - -/* See btrace-common.h. */ - -bool -btrace_data::empty () const -{ - switch (format) - { - case BTRACE_FORMAT_NONE: - return true; - - case BTRACE_FORMAT_BTS: - return variant.bts.blocks->empty (); - - case BTRACE_FORMAT_PT: - return (variant.pt.size == 0); - } - - internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); -} - -/* See btrace-common.h. */ - -void -btrace_data::clear () -{ - fini (); - format = BTRACE_FORMAT_NONE; -} - -/* See btrace-common.h. */ - -int -btrace_data_append (struct btrace_data *dst, - const struct btrace_data *src) -{ - switch (src->format) - { - case BTRACE_FORMAT_NONE: - return 0; - - case BTRACE_FORMAT_BTS: - switch (dst->format) - { - default: - return -1; - - case BTRACE_FORMAT_NONE: - dst->format = BTRACE_FORMAT_BTS; - dst->variant.bts.blocks = new std::vector; - - /* Fall-through. */ - case BTRACE_FORMAT_BTS: - { - unsigned int blk; - - /* We copy blocks in reverse order to have the oldest block at - index zero. */ - blk = src->variant.bts.blocks->size (); - while (blk != 0) - { - const btrace_block &block - = src->variant.bts.blocks->at (--blk); - dst->variant.bts.blocks->push_back (block); - } - } - } - return 0; - - case BTRACE_FORMAT_PT: - switch (dst->format) - { - default: - return -1; - - case BTRACE_FORMAT_NONE: - dst->format = BTRACE_FORMAT_PT; - dst->variant.pt.data = NULL; - dst->variant.pt.size = 0; - - /* fall-through. */ - case BTRACE_FORMAT_PT: - { - gdb_byte *data; - size_t size; - - size = src->variant.pt.size + dst->variant.pt.size; - data = (gdb_byte *) xmalloc (size); - - memcpy (data, dst->variant.pt.data, dst->variant.pt.size); - memcpy (data + dst->variant.pt.size, src->variant.pt.data, - src->variant.pt.size); - - xfree (dst->variant.pt.data); - - dst->variant.pt.data = data; - dst->variant.pt.size = size; - } - } - return 0; - } - - internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); -} diff --git a/gdbsupport/btrace-common.cc b/gdbsupport/btrace-common.cc new file mode 100644 index 0000000..7d4f642 --- /dev/null +++ b/gdbsupport/btrace-common.cc @@ -0,0 +1,190 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 . */ + +#include "common-defs.h" +#include "btrace-common.h" + + +/* See btrace-common.h. */ + +const char * +btrace_format_string (enum btrace_format format) +{ + switch (format) + { + case BTRACE_FORMAT_NONE: + return _("No or unknown format"); + + case BTRACE_FORMAT_BTS: + return _("Branch Trace Store"); + + case BTRACE_FORMAT_PT: + return _("Intel Processor Trace"); + } + + internal_error (__FILE__, __LINE__, _("Unknown branch trace format")); +} + +/* See btrace-common.h. */ + +const char * +btrace_format_short_string (enum btrace_format format) +{ + switch (format) + { + case BTRACE_FORMAT_NONE: + return "unknown"; + + case BTRACE_FORMAT_BTS: + return "bts"; + + case BTRACE_FORMAT_PT: + return "pt"; + } + + internal_error (__FILE__, __LINE__, _("Unknown branch trace format")); +} + +/* See btrace-common.h. */ + +void +btrace_data::fini () +{ + switch (format) + { + case BTRACE_FORMAT_NONE: + /* Nothing to do. */ + return; + + case BTRACE_FORMAT_BTS: + delete variant.bts.blocks; + variant.bts.blocks = nullptr; + return; + + case BTRACE_FORMAT_PT: + xfree (variant.pt.data); + return; + } + + internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); +} + +/* See btrace-common.h. */ + +bool +btrace_data::empty () const +{ + switch (format) + { + case BTRACE_FORMAT_NONE: + return true; + + case BTRACE_FORMAT_BTS: + return variant.bts.blocks->empty (); + + case BTRACE_FORMAT_PT: + return (variant.pt.size == 0); + } + + internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); +} + +/* See btrace-common.h. */ + +void +btrace_data::clear () +{ + fini (); + format = BTRACE_FORMAT_NONE; +} + +/* See btrace-common.h. */ + +int +btrace_data_append (struct btrace_data *dst, + const struct btrace_data *src) +{ + switch (src->format) + { + case BTRACE_FORMAT_NONE: + return 0; + + case BTRACE_FORMAT_BTS: + switch (dst->format) + { + default: + return -1; + + case BTRACE_FORMAT_NONE: + dst->format = BTRACE_FORMAT_BTS; + dst->variant.bts.blocks = new std::vector; + + /* Fall-through. */ + case BTRACE_FORMAT_BTS: + { + unsigned int blk; + + /* We copy blocks in reverse order to have the oldest block at + index zero. */ + blk = src->variant.bts.blocks->size (); + while (blk != 0) + { + const btrace_block &block + = src->variant.bts.blocks->at (--blk); + dst->variant.bts.blocks->push_back (block); + } + } + } + return 0; + + case BTRACE_FORMAT_PT: + switch (dst->format) + { + default: + return -1; + + case BTRACE_FORMAT_NONE: + dst->format = BTRACE_FORMAT_PT; + dst->variant.pt.data = NULL; + dst->variant.pt.size = 0; + + /* fall-through. */ + case BTRACE_FORMAT_PT: + { + gdb_byte *data; + size_t size; + + size = src->variant.pt.size + dst->variant.pt.size; + data = (gdb_byte *) xmalloc (size); + + memcpy (data, dst->variant.pt.data, dst->variant.pt.size); + memcpy (data + dst->variant.pt.size, src->variant.pt.data, + src->variant.pt.size); + + xfree (dst->variant.pt.data); + + dst->variant.pt.data = data; + dst->variant.pt.size = size; + } + } + return 0; + } + + internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); +} diff --git a/gdbsupport/buffer.c b/gdbsupport/buffer.c deleted file mode 100644 index e3d0f1e..0000000 --- a/gdbsupport/buffer.c +++ /dev/null @@ -1,178 +0,0 @@ -/* A simple growing buffer for GDB. - - Copyright (C) 2009-2020 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 . */ - -#include "common-defs.h" -#include "xml-utils.h" -#include "buffer.h" -#include "inttypes.h" -void -buffer_grow (struct buffer *buffer, const char *data, size_t size) -{ - char *new_buffer; - size_t new_buffer_size; - - if (size == 0) - return; - - new_buffer_size = buffer->buffer_size; - - if (new_buffer_size == 0) - new_buffer_size = 1; - - while (buffer->used_size + size > new_buffer_size) - new_buffer_size *= 2; - new_buffer = (char *) xrealloc (buffer->buffer, new_buffer_size); - memcpy (new_buffer + buffer->used_size, data, size); - buffer->buffer = new_buffer; - buffer->buffer_size = new_buffer_size; - buffer->used_size += size; -} - -void -buffer_free (struct buffer *buffer) -{ - if (!buffer) - return; - - xfree (buffer->buffer); - buffer->buffer = NULL; - buffer->buffer_size = 0; - buffer->used_size = 0; -} - -void -buffer_init (struct buffer *buffer) -{ - memset (buffer, 0, sizeof (*buffer)); -} - -char* -buffer_finish (struct buffer *buffer) -{ - char *ret = buffer->buffer; - buffer->buffer = NULL; - buffer->buffer_size = 0; - buffer->used_size = 0; - return ret; -} - -void -buffer_xml_printf (struct buffer *buffer, const char *format, ...) -{ - va_list ap; - const char *f; - const char *prev; - int percent = 0; - - va_start (ap, format); - - prev = format; - for (f = format; *f; f++) - { - if (percent) - { - char buf[32]; - char *str = buf; - const char *f_old = f; - - switch (*f) - { - case 's': - str = va_arg (ap, char *); - break; - case 'd': - sprintf (str, "%d", va_arg (ap, int)); - break; - case 'u': - sprintf (str, "%u", va_arg (ap, unsigned int)); - break; - case 'x': - sprintf (str, "%x", va_arg (ap, unsigned int)); - break; - case 'o': - sprintf (str, "%o", va_arg (ap, unsigned int)); - break; - case 'l': - f++; - switch (*f) - { - case 'd': - sprintf (str, "%ld", va_arg (ap, long)); - break; - case 'u': - sprintf (str, "%lu", va_arg (ap, unsigned long)); - break; - case 'x': - sprintf (str, "%lx", va_arg (ap, unsigned long)); - break; - case 'o': - sprintf (str, "%lo", va_arg (ap, unsigned long)); - break; - case 'l': - f++; - switch (*f) - { - case 'd': - sprintf (str, "%" PRId64, - (int64_t) va_arg (ap, long long)); - break; - case 'u': - sprintf (str, "%" PRIu64, - (uint64_t) va_arg (ap, unsigned long long)); - break; - case 'x': - sprintf (str, "%" PRIx64, - (uint64_t) va_arg (ap, unsigned long long)); - break; - case 'o': - sprintf (str, "%" PRIo64, - (uint64_t) va_arg (ap, unsigned long long)); - break; - default: - str = 0; - break; - } - break; - default: - str = 0; - break; - } - break; - default: - str = 0; - break; - } - - if (str) - { - buffer_grow (buffer, prev, f_old - prev - 1); - std::string p = xml_escape_text (str); - buffer_grow_str (buffer, p.c_str ()); - prev = f + 1; - } - percent = 0; - } - else if (*f == '%') - percent = 1; - } - - buffer_grow_str (buffer, prev); - va_end (ap); -} - diff --git a/gdbsupport/buffer.cc b/gdbsupport/buffer.cc new file mode 100644 index 0000000..e3d0f1e --- /dev/null +++ b/gdbsupport/buffer.cc @@ -0,0 +1,178 @@ +/* A simple growing buffer for GDB. + + Copyright (C) 2009-2020 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 . */ + +#include "common-defs.h" +#include "xml-utils.h" +#include "buffer.h" +#include "inttypes.h" +void +buffer_grow (struct buffer *buffer, const char *data, size_t size) +{ + char *new_buffer; + size_t new_buffer_size; + + if (size == 0) + return; + + new_buffer_size = buffer->buffer_size; + + if (new_buffer_size == 0) + new_buffer_size = 1; + + while (buffer->used_size + size > new_buffer_size) + new_buffer_size *= 2; + new_buffer = (char *) xrealloc (buffer->buffer, new_buffer_size); + memcpy (new_buffer + buffer->used_size, data, size); + buffer->buffer = new_buffer; + buffer->buffer_size = new_buffer_size; + buffer->used_size += size; +} + +void +buffer_free (struct buffer *buffer) +{ + if (!buffer) + return; + + xfree (buffer->buffer); + buffer->buffer = NULL; + buffer->buffer_size = 0; + buffer->used_size = 0; +} + +void +buffer_init (struct buffer *buffer) +{ + memset (buffer, 0, sizeof (*buffer)); +} + +char* +buffer_finish (struct buffer *buffer) +{ + char *ret = buffer->buffer; + buffer->buffer = NULL; + buffer->buffer_size = 0; + buffer->used_size = 0; + return ret; +} + +void +buffer_xml_printf (struct buffer *buffer, const char *format, ...) +{ + va_list ap; + const char *f; + const char *prev; + int percent = 0; + + va_start (ap, format); + + prev = format; + for (f = format; *f; f++) + { + if (percent) + { + char buf[32]; + char *str = buf; + const char *f_old = f; + + switch (*f) + { + case 's': + str = va_arg (ap, char *); + break; + case 'd': + sprintf (str, "%d", va_arg (ap, int)); + break; + case 'u': + sprintf (str, "%u", va_arg (ap, unsigned int)); + break; + case 'x': + sprintf (str, "%x", va_arg (ap, unsigned int)); + break; + case 'o': + sprintf (str, "%o", va_arg (ap, unsigned int)); + break; + case 'l': + f++; + switch (*f) + { + case 'd': + sprintf (str, "%ld", va_arg (ap, long)); + break; + case 'u': + sprintf (str, "%lu", va_arg (ap, unsigned long)); + break; + case 'x': + sprintf (str, "%lx", va_arg (ap, unsigned long)); + break; + case 'o': + sprintf (str, "%lo", va_arg (ap, unsigned long)); + break; + case 'l': + f++; + switch (*f) + { + case 'd': + sprintf (str, "%" PRId64, + (int64_t) va_arg (ap, long long)); + break; + case 'u': + sprintf (str, "%" PRIu64, + (uint64_t) va_arg (ap, unsigned long long)); + break; + case 'x': + sprintf (str, "%" PRIx64, + (uint64_t) va_arg (ap, unsigned long long)); + break; + case 'o': + sprintf (str, "%" PRIo64, + (uint64_t) va_arg (ap, unsigned long long)); + break; + default: + str = 0; + break; + } + break; + default: + str = 0; + break; + } + break; + default: + str = 0; + break; + } + + if (str) + { + buffer_grow (buffer, prev, f_old - prev - 1); + std::string p = xml_escape_text (str); + buffer_grow_str (buffer, p.c_str ()); + prev = f + 1; + } + percent = 0; + } + else if (*f == '%') + percent = 1; + } + + buffer_grow_str (buffer, prev); + va_end (ap); +} + diff --git a/gdbsupport/cleanups.c b/gdbsupport/cleanups.c deleted file mode 100644 index 236bc17..0000000 --- a/gdbsupport/cleanups.c +++ /dev/null @@ -1,144 +0,0 @@ -/* Cleanup routines for GDB, the GNU debugger. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "cleanups.h" - -/* The cleanup list records things that have to be undone - if an error happens (descriptors to be closed, memory to be freed, etc.) - Each link in the chain records a function to call and an - argument to give it. - - Use make_cleanup to add an element to the cleanup chain. - Use do_cleanups to do all cleanup actions back to a given - point in the chain. Use discard_cleanups to remove cleanups - from the chain back to a given point, not doing them. - - If the argument is pointer to allocated memory, then you need - to additionally set the 'free_arg' member to a function that will - free that memory. This function will be called both when the cleanup - is executed and when it's discarded. */ - -struct cleanup -{ - struct cleanup *next; - void (*function) (void *); - void (*free_arg) (void *); - void *arg; -}; - -/* Used to mark the end of a cleanup chain. - The value is chosen so that it: - - is non-NULL so that make_cleanup never returns NULL, - - causes a segv if dereferenced - [though this won't catch errors that a value of, say, - ((struct cleanup *) -1) will] - - displays as something useful when printed in gdb. - This is const for a bit of extra robustness. - It is initialized to coax gcc into putting it into .rodata. - All fields are initialized to survive -Wextra. */ -static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 }; - -/* Handy macro to use when referring to sentinel_cleanup. */ -#define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup) - -/* Chain of cleanup actions established with make_final_cleanup, - to be executed when gdb exits. */ -static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP; - -/* Main worker routine to create a cleanup. - PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. - FUNCTION is the function to call to perform the cleanup. - ARG is passed to FUNCTION when called. - FREE_ARG, if non-NULL, is called after the cleanup is performed. - - The result is a pointer to the previous chain pointer - to be passed later to do_cleanups or discard_cleanups. */ - -static struct cleanup * -make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function, - void *arg, void (*free_arg) (void *)) -{ - struct cleanup *newobj = XNEW (struct cleanup); - struct cleanup *old_chain = *pmy_chain; - - newobj->next = *pmy_chain; - newobj->function = function; - newobj->free_arg = free_arg; - newobj->arg = arg; - *pmy_chain = newobj; - - gdb_assert (old_chain != NULL); - return old_chain; -} - -/* Worker routine to create a cleanup without a destructor. - PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. - FUNCTION is the function to call to perform the cleanup. - ARG is passed to FUNCTION when called. - - The result is a pointer to the previous chain pointer - to be passed later to do_cleanups or discard_cleanups. */ - -static struct cleanup * -make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, - void *arg) -{ - return make_my_cleanup2 (pmy_chain, function, arg, NULL); -} - -/* Add a new cleanup to the final cleanup_chain, - and return the previous chain pointer - to be passed later to do_cleanups or discard_cleanups. - Args are FUNCTION to clean up with, and ARG to pass to it. */ - -struct cleanup * -make_final_cleanup (make_cleanup_ftype *function, void *arg) -{ - return make_my_cleanup (&final_cleanup_chain, function, arg); -} - -/* Worker routine to perform cleanups. - PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. - OLD_CHAIN is the result of a "make" cleanup routine. - Cleanups are performed until we get back to the old end of the chain. */ - -static void -do_my_cleanups (struct cleanup **pmy_chain, - struct cleanup *old_chain) -{ - struct cleanup *ptr; - - while ((ptr = *pmy_chain) != old_chain) - { - *pmy_chain = ptr->next; /* Do this first in case of recursion. */ - (*ptr->function) (ptr->arg); - if (ptr->free_arg) - (*ptr->free_arg) (ptr->arg); - xfree (ptr); - } -} - -/* Discard final cleanups and do the actions they describe. */ - -void -do_final_cleanups () -{ - do_my_cleanups (&final_cleanup_chain, SENTINEL_CLEANUP); -} diff --git a/gdbsupport/cleanups.cc b/gdbsupport/cleanups.cc new file mode 100644 index 0000000..236bc17 --- /dev/null +++ b/gdbsupport/cleanups.cc @@ -0,0 +1,144 @@ +/* Cleanup routines for GDB, the GNU debugger. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "cleanups.h" + +/* The cleanup list records things that have to be undone + if an error happens (descriptors to be closed, memory to be freed, etc.) + Each link in the chain records a function to call and an + argument to give it. + + Use make_cleanup to add an element to the cleanup chain. + Use do_cleanups to do all cleanup actions back to a given + point in the chain. Use discard_cleanups to remove cleanups + from the chain back to a given point, not doing them. + + If the argument is pointer to allocated memory, then you need + to additionally set the 'free_arg' member to a function that will + free that memory. This function will be called both when the cleanup + is executed and when it's discarded. */ + +struct cleanup +{ + struct cleanup *next; + void (*function) (void *); + void (*free_arg) (void *); + void *arg; +}; + +/* Used to mark the end of a cleanup chain. + The value is chosen so that it: + - is non-NULL so that make_cleanup never returns NULL, + - causes a segv if dereferenced + [though this won't catch errors that a value of, say, + ((struct cleanup *) -1) will] + - displays as something useful when printed in gdb. + This is const for a bit of extra robustness. + It is initialized to coax gcc into putting it into .rodata. + All fields are initialized to survive -Wextra. */ +static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 }; + +/* Handy macro to use when referring to sentinel_cleanup. */ +#define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup) + +/* Chain of cleanup actions established with make_final_cleanup, + to be executed when gdb exits. */ +static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP; + +/* Main worker routine to create a cleanup. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + FUNCTION is the function to call to perform the cleanup. + ARG is passed to FUNCTION when called. + FREE_ARG, if non-NULL, is called after the cleanup is performed. + + The result is a pointer to the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. */ + +static struct cleanup * +make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg, void (*free_arg) (void *)) +{ + struct cleanup *newobj = XNEW (struct cleanup); + struct cleanup *old_chain = *pmy_chain; + + newobj->next = *pmy_chain; + newobj->function = function; + newobj->free_arg = free_arg; + newobj->arg = arg; + *pmy_chain = newobj; + + gdb_assert (old_chain != NULL); + return old_chain; +} + +/* Worker routine to create a cleanup without a destructor. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + FUNCTION is the function to call to perform the cleanup. + ARG is passed to FUNCTION when called. + + The result is a pointer to the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. */ + +static struct cleanup * +make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, + void *arg) +{ + return make_my_cleanup2 (pmy_chain, function, arg, NULL); +} + +/* Add a new cleanup to the final cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_final_cleanup (make_cleanup_ftype *function, void *arg) +{ + return make_my_cleanup (&final_cleanup_chain, function, arg); +} + +/* Worker routine to perform cleanups. + PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. + OLD_CHAIN is the result of a "make" cleanup routine. + Cleanups are performed until we get back to the old end of the chain. */ + +static void +do_my_cleanups (struct cleanup **pmy_chain, + struct cleanup *old_chain) +{ + struct cleanup *ptr; + + while ((ptr = *pmy_chain) != old_chain) + { + *pmy_chain = ptr->next; /* Do this first in case of recursion. */ + (*ptr->function) (ptr->arg); + if (ptr->free_arg) + (*ptr->free_arg) (ptr->arg); + xfree (ptr); + } +} + +/* Discard final cleanups and do the actions they describe. */ + +void +do_final_cleanups () +{ + do_my_cleanups (&final_cleanup_chain, SENTINEL_CLEANUP); +} diff --git a/gdbsupport/common-debug.c b/gdbsupport/common-debug.c deleted file mode 100644 index d1131a0..0000000 --- a/gdbsupport/common-debug.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Debug printing functions. - - Copyright (C) 2014-2020 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 . */ - -#include "common-defs.h" -#include "common-debug.h" - -/* See gdbsupport/common-debug.h. */ - -bool show_debug_regs; - -/* See gdbsupport/common-debug.h. */ - -void -debug_printf (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - debug_vprintf (fmt, ap); - va_end (ap); -} diff --git a/gdbsupport/common-debug.cc b/gdbsupport/common-debug.cc new file mode 100644 index 0000000..d1131a0 --- /dev/null +++ b/gdbsupport/common-debug.cc @@ -0,0 +1,37 @@ +/* Debug printing functions. + + Copyright (C) 2014-2020 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 . */ + +#include "common-defs.h" +#include "common-debug.h" + +/* See gdbsupport/common-debug.h. */ + +bool show_debug_regs; + +/* See gdbsupport/common-debug.h. */ + +void +debug_printf (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + debug_vprintf (fmt, ap); + va_end (ap); +} diff --git a/gdbsupport/common-exceptions.c b/gdbsupport/common-exceptions.c deleted file mode 100644 index 0cc515b..0000000 --- a/gdbsupport/common-exceptions.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Exception (throw catch) mechanism, for GDB, the GNU debugger. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "common-exceptions.h" -#include - -/* Possible catcher states. */ -enum catcher_state { - /* Initial state, a new catcher has just been created. */ - CATCHER_CREATED, - /* The catch code is running. */ - CATCHER_RUNNING, - CATCHER_RUNNING_1, - /* The catch code threw an exception. */ - CATCHER_ABORTING -}; - -/* Possible catcher actions. */ -enum catcher_action { - CATCH_ITER, - CATCH_ITER_1, - CATCH_THROWING -}; - -struct catcher -{ - enum catcher_state state = CATCHER_CREATED; - /* Jump buffer pointing back at the exception handler. */ - jmp_buf buf; - /* Status buffer belonging to the exception handler. */ - struct gdb_exception exception; -}; - -/* Where to go for throw_exception(). */ -static std::forward_list catchers; - -jmp_buf * -exceptions_state_mc_init () -{ - catchers.emplace_front (); - return &catchers.front ().buf; -} - -/* Catcher state machine. Returns non-zero if the m/c should be run - again, zero if it should abort. */ - -static int -exceptions_state_mc (enum catcher_action action) -{ - switch (catchers.front ().state) - { - case CATCHER_CREATED: - switch (action) - { - case CATCH_ITER: - /* Allow the code to run the catcher. */ - catchers.front ().state = CATCHER_RUNNING; - return 1; - default: - internal_error (__FILE__, __LINE__, _("bad state")); - } - case CATCHER_RUNNING: - switch (action) - { - case CATCH_ITER: - /* No error/quit has occured. */ - return 0; - case CATCH_ITER_1: - catchers.front ().state = CATCHER_RUNNING_1; - return 1; - case CATCH_THROWING: - catchers.front ().state = CATCHER_ABORTING; - /* See also throw_exception. */ - return 1; - default: - internal_error (__FILE__, __LINE__, _("bad switch")); - } - case CATCHER_RUNNING_1: - switch (action) - { - case CATCH_ITER: - /* The did a "break" from the inner while loop. */ - return 0; - case CATCH_ITER_1: - catchers.front ().state = CATCHER_RUNNING; - return 0; - case CATCH_THROWING: - catchers.front ().state = CATCHER_ABORTING; - /* See also throw_exception. */ - return 1; - default: - internal_error (__FILE__, __LINE__, _("bad switch")); - } - case CATCHER_ABORTING: - switch (action) - { - case CATCH_ITER: - { - /* Exit normally if this catcher can handle this - exception. The caller analyses the func return - values. */ - return 0; - } - default: - internal_error (__FILE__, __LINE__, _("bad state")); - } - default: - internal_error (__FILE__, __LINE__, _("bad switch")); - } -} - -int -exceptions_state_mc_catch (struct gdb_exception *exception, - int mask) -{ - *exception = std::move (catchers.front ().exception); - catchers.pop_front (); - - if (exception->reason < 0) - { - if (mask & RETURN_MASK (exception->reason)) - { - /* Exit normally and let the caller handle the - exception. */ - return 1; - } - - /* The caller didn't request that the event be caught, relay the - event to the next exception_catch/CATCH_SJLJ. */ - throw_exception_sjlj (*exception); - } - - /* No exception was thrown. */ - return 0; -} - -int -exceptions_state_mc_action_iter (void) -{ - return exceptions_state_mc (CATCH_ITER); -} - -int -exceptions_state_mc_action_iter_1 (void) -{ - return exceptions_state_mc (CATCH_ITER_1); -} - -/* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */ - -void -throw_exception_sjlj (const struct gdb_exception &exception) -{ - /* Jump to the nearest CATCH_SJLJ block, communicating REASON to - that call via setjmp's return value. Note that REASON can't be - zero, by definition in common-exceptions.h. */ - exceptions_state_mc (CATCH_THROWING); - enum return_reason reason = exception.reason; - catchers.front ().exception = exception; - longjmp (catchers.front ().buf, reason); -} - -/* Implementation of throw_exception that uses C++ try/catch. */ - -void -throw_exception (gdb_exception &&exception) -{ - if (exception.reason == RETURN_QUIT) - throw gdb_exception_quit (std::move (exception)); - else if (exception.reason == RETURN_ERROR) - throw gdb_exception_error (std::move (exception)); - else - gdb_assert_not_reached ("invalid return reason"); -} - -static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0) -throw_it (enum return_reason reason, enum errors error, const char *fmt, - va_list ap) -{ - if (reason == RETURN_QUIT) - throw gdb_exception_quit (fmt, ap); - else if (reason == RETURN_ERROR) - throw gdb_exception_error (error, fmt, ap); - else - gdb_assert_not_reached ("invalid return reason"); -} - -void -throw_verror (enum errors error, const char *fmt, va_list ap) -{ - throw_it (RETURN_ERROR, error, fmt, ap); -} - -void -throw_vquit (const char *fmt, va_list ap) -{ - throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap); -} - -void -throw_error (enum errors error, const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - throw_verror (error, fmt, args); - va_end (args); -} - -void -throw_quit (const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - throw_vquit (fmt, args); - va_end (args); -} diff --git a/gdbsupport/common-exceptions.cc b/gdbsupport/common-exceptions.cc new file mode 100644 index 0000000..0cc515b --- /dev/null +++ b/gdbsupport/common-exceptions.cc @@ -0,0 +1,235 @@ +/* Exception (throw catch) mechanism, for GDB, the GNU debugger. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "common-exceptions.h" +#include + +/* Possible catcher states. */ +enum catcher_state { + /* Initial state, a new catcher has just been created. */ + CATCHER_CREATED, + /* The catch code is running. */ + CATCHER_RUNNING, + CATCHER_RUNNING_1, + /* The catch code threw an exception. */ + CATCHER_ABORTING +}; + +/* Possible catcher actions. */ +enum catcher_action { + CATCH_ITER, + CATCH_ITER_1, + CATCH_THROWING +}; + +struct catcher +{ + enum catcher_state state = CATCHER_CREATED; + /* Jump buffer pointing back at the exception handler. */ + jmp_buf buf; + /* Status buffer belonging to the exception handler. */ + struct gdb_exception exception; +}; + +/* Where to go for throw_exception(). */ +static std::forward_list catchers; + +jmp_buf * +exceptions_state_mc_init () +{ + catchers.emplace_front (); + return &catchers.front ().buf; +} + +/* Catcher state machine. Returns non-zero if the m/c should be run + again, zero if it should abort. */ + +static int +exceptions_state_mc (enum catcher_action action) +{ + switch (catchers.front ().state) + { + case CATCHER_CREATED: + switch (action) + { + case CATCH_ITER: + /* Allow the code to run the catcher. */ + catchers.front ().state = CATCHER_RUNNING; + return 1; + default: + internal_error (__FILE__, __LINE__, _("bad state")); + } + case CATCHER_RUNNING: + switch (action) + { + case CATCH_ITER: + /* No error/quit has occured. */ + return 0; + case CATCH_ITER_1: + catchers.front ().state = CATCHER_RUNNING_1; + return 1; + case CATCH_THROWING: + catchers.front ().state = CATCHER_ABORTING; + /* See also throw_exception. */ + return 1; + default: + internal_error (__FILE__, __LINE__, _("bad switch")); + } + case CATCHER_RUNNING_1: + switch (action) + { + case CATCH_ITER: + /* The did a "break" from the inner while loop. */ + return 0; + case CATCH_ITER_1: + catchers.front ().state = CATCHER_RUNNING; + return 0; + case CATCH_THROWING: + catchers.front ().state = CATCHER_ABORTING; + /* See also throw_exception. */ + return 1; + default: + internal_error (__FILE__, __LINE__, _("bad switch")); + } + case CATCHER_ABORTING: + switch (action) + { + case CATCH_ITER: + { + /* Exit normally if this catcher can handle this + exception. The caller analyses the func return + values. */ + return 0; + } + default: + internal_error (__FILE__, __LINE__, _("bad state")); + } + default: + internal_error (__FILE__, __LINE__, _("bad switch")); + } +} + +int +exceptions_state_mc_catch (struct gdb_exception *exception, + int mask) +{ + *exception = std::move (catchers.front ().exception); + catchers.pop_front (); + + if (exception->reason < 0) + { + if (mask & RETURN_MASK (exception->reason)) + { + /* Exit normally and let the caller handle the + exception. */ + return 1; + } + + /* The caller didn't request that the event be caught, relay the + event to the next exception_catch/CATCH_SJLJ. */ + throw_exception_sjlj (*exception); + } + + /* No exception was thrown. */ + return 0; +} + +int +exceptions_state_mc_action_iter (void) +{ + return exceptions_state_mc (CATCH_ITER); +} + +int +exceptions_state_mc_action_iter_1 (void) +{ + return exceptions_state_mc (CATCH_ITER_1); +} + +/* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */ + +void +throw_exception_sjlj (const struct gdb_exception &exception) +{ + /* Jump to the nearest CATCH_SJLJ block, communicating REASON to + that call via setjmp's return value. Note that REASON can't be + zero, by definition in common-exceptions.h. */ + exceptions_state_mc (CATCH_THROWING); + enum return_reason reason = exception.reason; + catchers.front ().exception = exception; + longjmp (catchers.front ().buf, reason); +} + +/* Implementation of throw_exception that uses C++ try/catch. */ + +void +throw_exception (gdb_exception &&exception) +{ + if (exception.reason == RETURN_QUIT) + throw gdb_exception_quit (std::move (exception)); + else if (exception.reason == RETURN_ERROR) + throw gdb_exception_error (std::move (exception)); + else + gdb_assert_not_reached ("invalid return reason"); +} + +static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0) +throw_it (enum return_reason reason, enum errors error, const char *fmt, + va_list ap) +{ + if (reason == RETURN_QUIT) + throw gdb_exception_quit (fmt, ap); + else if (reason == RETURN_ERROR) + throw gdb_exception_error (error, fmt, ap); + else + gdb_assert_not_reached ("invalid return reason"); +} + +void +throw_verror (enum errors error, const char *fmt, va_list ap) +{ + throw_it (RETURN_ERROR, error, fmt, ap); +} + +void +throw_vquit (const char *fmt, va_list ap) +{ + throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap); +} + +void +throw_error (enum errors error, const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + throw_verror (error, fmt, args); + va_end (args); +} + +void +throw_quit (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + throw_vquit (fmt, args); + va_end (args); +} diff --git a/gdbsupport/common-inferior.c b/gdbsupport/common-inferior.c deleted file mode 100644 index ed16e89..0000000 --- a/gdbsupport/common-inferior.c +++ /dev/null @@ -1,26 +0,0 @@ -/* Functions to deal with the inferior being executed on GDB or - GDBserver. - - Copyright (C) 2019-2020 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 . */ - -#include "gdbsupport/common-defs.h" -#include "gdbsupport/common-inferior.h" - -/* See common-inferior.h. */ - -bool startup_with_shell = true; diff --git a/gdbsupport/common-inferior.cc b/gdbsupport/common-inferior.cc new file mode 100644 index 0000000..ed16e89 --- /dev/null +++ b/gdbsupport/common-inferior.cc @@ -0,0 +1,26 @@ +/* Functions to deal with the inferior being executed on GDB or + GDBserver. + + Copyright (C) 2019-2020 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 . */ + +#include "gdbsupport/common-defs.h" +#include "gdbsupport/common-inferior.h" + +/* See common-inferior.h. */ + +bool startup_with_shell = true; diff --git a/gdbsupport/common-regcache.c b/gdbsupport/common-regcache.c deleted file mode 100644 index 86b3a36..0000000 --- a/gdbsupport/common-regcache.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Cache and manage the values of registers for GDB, the GNU debugger. - - Copyright (C) 2015-2020 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 . */ - -#include "common-defs.h" -#include "common-regcache.h" - -/* Return the register's value or throw if it's not available. */ - -ULONGEST -regcache_raw_get_unsigned (struct regcache *regcache, int regnum) -{ - ULONGEST value; - enum register_status status; - - status = regcache_raw_read_unsigned (regcache, regnum, &value); - if (status == REG_UNAVAILABLE) - throw_error (NOT_AVAILABLE_ERROR, - _("Register %d is not available"), regnum); - return value; -} diff --git a/gdbsupport/common-regcache.cc b/gdbsupport/common-regcache.cc new file mode 100644 index 0000000..86b3a36 --- /dev/null +++ b/gdbsupport/common-regcache.cc @@ -0,0 +1,36 @@ +/* Cache and manage the values of registers for GDB, the GNU debugger. + + Copyright (C) 2015-2020 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 . */ + +#include "common-defs.h" +#include "common-regcache.h" + +/* Return the register's value or throw if it's not available. */ + +ULONGEST +regcache_raw_get_unsigned (struct regcache *regcache, int regnum) +{ + ULONGEST value; + enum register_status status; + + status = regcache_raw_read_unsigned (regcache, regnum, &value); + if (status == REG_UNAVAILABLE) + throw_error (NOT_AVAILABLE_ERROR, + _("Register %d is not available"), regnum); + return value; +} diff --git a/gdbsupport/common-utils.c b/gdbsupport/common-utils.c deleted file mode 100644 index ed05d61..0000000 --- a/gdbsupport/common-utils.c +++ /dev/null @@ -1,417 +0,0 @@ -/* Shared general utility routines for GDB, the GNU debugger. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "common-utils.h" -#include "host-defs.h" -#include - -void * -xzalloc (size_t size) -{ - return xcalloc (1, size); -} - -/* Like asprintf/vasprintf but get an internal_error if the call - fails. */ - -char * -xstrprintf (const char *format, ...) -{ - char *ret; - va_list args; - - va_start (args, format); - ret = xstrvprintf (format, args); - va_end (args); - return ret; -} - -char * -xstrvprintf (const char *format, va_list ap) -{ - char *ret = NULL; - int status = vasprintf (&ret, format, ap); - - /* NULL is returned when there was a memory allocation problem, or - any other error (for instance, a bad format string). A negative - status (the printed length) with a non-NULL buffer should never - happen, but just to be sure. */ - if (ret == NULL || status < 0) - internal_error (__FILE__, __LINE__, _("vasprintf call failed")); - return ret; -} - -int -xsnprintf (char *str, size_t size, const char *format, ...) -{ - va_list args; - int ret; - - va_start (args, format); - ret = vsnprintf (str, size, format, args); - gdb_assert (ret < size); - va_end (args); - - return ret; -} - -/* See documentation in common-utils.h. */ - -std::string -string_printf (const char* fmt, ...) -{ - va_list vp; - int size; - - va_start (vp, fmt); - size = vsnprintf (NULL, 0, fmt, vp); - va_end (vp); - - std::string str (size, '\0'); - - /* C++11 and later guarantee std::string uses contiguous memory and - always includes the terminating '\0'. */ - va_start (vp, fmt); - vsprintf (&str[0], fmt, vp); /* ARI: vsprintf */ - va_end (vp); - - return str; -} - -/* See documentation in common-utils.h. */ - -std::string -string_vprintf (const char* fmt, va_list args) -{ - va_list vp; - size_t size; - - va_copy (vp, args); - size = vsnprintf (NULL, 0, fmt, vp); - va_end (vp); - - std::string str (size, '\0'); - - /* C++11 and later guarantee std::string uses contiguous memory and - always includes the terminating '\0'. */ - vsprintf (&str[0], fmt, args); /* ARI: vsprintf */ - - return str; -} - - -/* See documentation in common-utils.h. */ - -void -string_appendf (std::string &str, const char *fmt, ...) -{ - va_list vp; - - va_start (vp, fmt); - string_vappendf (str, fmt, vp); - va_end (vp); -} - - -/* See documentation in common-utils.h. */ - -void -string_vappendf (std::string &str, const char *fmt, va_list args) -{ - va_list vp; - int grow_size; - - va_copy (vp, args); - grow_size = vsnprintf (NULL, 0, fmt, vp); - va_end (vp); - - size_t curr_size = str.size (); - str.resize (curr_size + grow_size); - - /* C++11 and later guarantee std::string uses contiguous memory and - always includes the terminating '\0'. */ - vsprintf (&str[curr_size], fmt, args); /* ARI: vsprintf */ -} - -char * -savestring (const char *ptr, size_t len) -{ - char *p = (char *) xmalloc (len + 1); - - memcpy (p, ptr, len); - p[len] = 0; - return p; -} - -/* See documentation in common-utils.h. */ - -std::string -extract_string_maybe_quoted (const char **arg) -{ - bool squote = false; - bool dquote = false; - bool bsquote = false; - std::string result; - const char *p = *arg; - - /* Find the start of the argument. */ - p = skip_spaces (p); - - /* Parse p similarly to gdb_argv buildargv function. */ - while (*p != '\0') - { - if (isspace (*p) && !squote && !dquote && !bsquote) - break; - else - { - if (bsquote) - { - bsquote = false; - result += *p; - } - else if (*p == '\\') - bsquote = true; - else if (squote) - { - if (*p == '\'') - squote = false; - else - result += *p; - } - else if (dquote) - { - if (*p == '"') - dquote = false; - else - result += *p; - } - else - { - if (*p == '\'') - squote = true; - else if (*p == '"') - dquote = true; - else - result += *p; - } - p++; - } - } - - *arg = p; - return result; -} - -/* The bit offset of the highest byte in a ULONGEST, for overflow - checking. */ - -#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) - -/* True (non-zero) iff DIGIT is a valid digit in radix BASE, - where 2 <= BASE <= 36. */ - -static int -is_digit_in_base (unsigned char digit, int base) -{ - if (!isalnum (digit)) - return 0; - if (base <= 10) - return (isdigit (digit) && digit < base + '0'); - else - return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); -} - -static int -digit_to_int (unsigned char c) -{ - if (isdigit (c)) - return c - '0'; - else - return tolower (c) - 'a' + 10; -} - -/* As for strtoul, but for ULONGEST results. */ - -ULONGEST -strtoulst (const char *num, const char **trailer, int base) -{ - unsigned int high_part; - ULONGEST result; - int minus = 0; - int i = 0; - - /* Skip leading whitespace. */ - while (isspace (num[i])) - i++; - - /* Handle prefixes. */ - if (num[i] == '+') - i++; - else if (num[i] == '-') - { - minus = 1; - i++; - } - - if (base == 0 || base == 16) - { - if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) - { - i += 2; - if (base == 0) - base = 16; - } - } - - if (base == 0 && num[i] == '0') - base = 8; - - if (base == 0) - base = 10; - - if (base < 2 || base > 36) - { - errno = EINVAL; - return 0; - } - - result = high_part = 0; - for (; is_digit_in_base (num[i], base); i += 1) - { - result = result * base + digit_to_int (num[i]); - high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); - result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; - if (high_part > 0xff) - { - errno = ERANGE; - result = ~ (ULONGEST) 0; - high_part = 0; - minus = 0; - break; - } - } - - if (trailer != NULL) - *trailer = &num[i]; - - result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); - if (minus) - return -result; - else - return result; -} - -/* See documentation in common-utils.h. */ - -char * -skip_spaces (char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && isspace (*chp)) - chp++; - return chp; -} - -/* A const-correct version of the above. */ - -const char * -skip_spaces (const char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && isspace (*chp)) - chp++; - return chp; -} - -/* See documentation in common-utils.h. */ - -const char * -skip_to_space (const char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && !isspace (*chp)) - chp++; - return chp; -} - -/* See documentation in common-utils.h. */ - -char * -skip_to_space (char *chp) -{ - return (char *) skip_to_space ((const char *) chp); -} - -/* See gdbsupport/common-utils.h. */ - -void -free_vector_argv (std::vector &v) -{ - for (char *el : v) - xfree (el); - - v.clear (); -} - -/* See gdbsupport/common-utils.h. */ - -std::string -stringify_argv (const std::vector &args) -{ - std::string ret; - - if (!args.empty () && args[0] != NULL) - { - for (auto s : args) - if (s != NULL) - { - ret += s; - ret += ' '; - } - - /* Erase the last whitespace. */ - ret.erase (ret.end () - 1); - } - - return ret; -} - -/* See gdbsupport/common-utils.h. */ - -ULONGEST -align_up (ULONGEST v, int n) -{ - /* Check that N is really a power of two. */ - gdb_assert (n && (n & (n-1)) == 0); - return (v + n - 1) & -n; -} - -/* See gdbsupport/common-utils.h. */ - -ULONGEST -align_down (ULONGEST v, int n) -{ - /* Check that N is really a power of two. */ - gdb_assert (n && (n & (n-1)) == 0); - return (v & -n); -} diff --git a/gdbsupport/common-utils.cc b/gdbsupport/common-utils.cc new file mode 100644 index 0000000..ed05d61 --- /dev/null +++ b/gdbsupport/common-utils.cc @@ -0,0 +1,417 @@ +/* Shared general utility routines for GDB, the GNU debugger. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "common-utils.h" +#include "host-defs.h" +#include + +void * +xzalloc (size_t size) +{ + return xcalloc (1, size); +} + +/* Like asprintf/vasprintf but get an internal_error if the call + fails. */ + +char * +xstrprintf (const char *format, ...) +{ + char *ret; + va_list args; + + va_start (args, format); + ret = xstrvprintf (format, args); + va_end (args); + return ret; +} + +char * +xstrvprintf (const char *format, va_list ap) +{ + char *ret = NULL; + int status = vasprintf (&ret, format, ap); + + /* NULL is returned when there was a memory allocation problem, or + any other error (for instance, a bad format string). A negative + status (the printed length) with a non-NULL buffer should never + happen, but just to be sure. */ + if (ret == NULL || status < 0) + internal_error (__FILE__, __LINE__, _("vasprintf call failed")); + return ret; +} + +int +xsnprintf (char *str, size_t size, const char *format, ...) +{ + va_list args; + int ret; + + va_start (args, format); + ret = vsnprintf (str, size, format, args); + gdb_assert (ret < size); + va_end (args); + + return ret; +} + +/* See documentation in common-utils.h. */ + +std::string +string_printf (const char* fmt, ...) +{ + va_list vp; + int size; + + va_start (vp, fmt); + size = vsnprintf (NULL, 0, fmt, vp); + va_end (vp); + + std::string str (size, '\0'); + + /* C++11 and later guarantee std::string uses contiguous memory and + always includes the terminating '\0'. */ + va_start (vp, fmt); + vsprintf (&str[0], fmt, vp); /* ARI: vsprintf */ + va_end (vp); + + return str; +} + +/* See documentation in common-utils.h. */ + +std::string +string_vprintf (const char* fmt, va_list args) +{ + va_list vp; + size_t size; + + va_copy (vp, args); + size = vsnprintf (NULL, 0, fmt, vp); + va_end (vp); + + std::string str (size, '\0'); + + /* C++11 and later guarantee std::string uses contiguous memory and + always includes the terminating '\0'. */ + vsprintf (&str[0], fmt, args); /* ARI: vsprintf */ + + return str; +} + + +/* See documentation in common-utils.h. */ + +void +string_appendf (std::string &str, const char *fmt, ...) +{ + va_list vp; + + va_start (vp, fmt); + string_vappendf (str, fmt, vp); + va_end (vp); +} + + +/* See documentation in common-utils.h. */ + +void +string_vappendf (std::string &str, const char *fmt, va_list args) +{ + va_list vp; + int grow_size; + + va_copy (vp, args); + grow_size = vsnprintf (NULL, 0, fmt, vp); + va_end (vp); + + size_t curr_size = str.size (); + str.resize (curr_size + grow_size); + + /* C++11 and later guarantee std::string uses contiguous memory and + always includes the terminating '\0'. */ + vsprintf (&str[curr_size], fmt, args); /* ARI: vsprintf */ +} + +char * +savestring (const char *ptr, size_t len) +{ + char *p = (char *) xmalloc (len + 1); + + memcpy (p, ptr, len); + p[len] = 0; + return p; +} + +/* See documentation in common-utils.h. */ + +std::string +extract_string_maybe_quoted (const char **arg) +{ + bool squote = false; + bool dquote = false; + bool bsquote = false; + std::string result; + const char *p = *arg; + + /* Find the start of the argument. */ + p = skip_spaces (p); + + /* Parse p similarly to gdb_argv buildargv function. */ + while (*p != '\0') + { + if (isspace (*p) && !squote && !dquote && !bsquote) + break; + else + { + if (bsquote) + { + bsquote = false; + result += *p; + } + else if (*p == '\\') + bsquote = true; + else if (squote) + { + if (*p == '\'') + squote = false; + else + result += *p; + } + else if (dquote) + { + if (*p == '"') + dquote = false; + else + result += *p; + } + else + { + if (*p == '\'') + squote = true; + else if (*p == '"') + dquote = true; + else + result += *p; + } + p++; + } + } + + *arg = p; + return result; +} + +/* The bit offset of the highest byte in a ULONGEST, for overflow + checking. */ + +#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) + +/* True (non-zero) iff DIGIT is a valid digit in radix BASE, + where 2 <= BASE <= 36. */ + +static int +is_digit_in_base (unsigned char digit, int base) +{ + if (!isalnum (digit)) + return 0; + if (base <= 10) + return (isdigit (digit) && digit < base + '0'); + else + return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); +} + +static int +digit_to_int (unsigned char c) +{ + if (isdigit (c)) + return c - '0'; + else + return tolower (c) - 'a' + 10; +} + +/* As for strtoul, but for ULONGEST results. */ + +ULONGEST +strtoulst (const char *num, const char **trailer, int base) +{ + unsigned int high_part; + ULONGEST result; + int minus = 0; + int i = 0; + + /* Skip leading whitespace. */ + while (isspace (num[i])) + i++; + + /* Handle prefixes. */ + if (num[i] == '+') + i++; + else if (num[i] == '-') + { + minus = 1; + i++; + } + + if (base == 0 || base == 16) + { + if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) + { + i += 2; + if (base == 0) + base = 16; + } + } + + if (base == 0 && num[i] == '0') + base = 8; + + if (base == 0) + base = 10; + + if (base < 2 || base > 36) + { + errno = EINVAL; + return 0; + } + + result = high_part = 0; + for (; is_digit_in_base (num[i], base); i += 1) + { + result = result * base + digit_to_int (num[i]); + high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); + result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; + if (high_part > 0xff) + { + errno = ERANGE; + result = ~ (ULONGEST) 0; + high_part = 0; + minus = 0; + break; + } + } + + if (trailer != NULL) + *trailer = &num[i]; + + result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); + if (minus) + return -result; + else + return result; +} + +/* See documentation in common-utils.h. */ + +char * +skip_spaces (char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} + +/* A const-correct version of the above. */ + +const char * +skip_spaces (const char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} + +/* See documentation in common-utils.h. */ + +const char * +skip_to_space (const char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && !isspace (*chp)) + chp++; + return chp; +} + +/* See documentation in common-utils.h. */ + +char * +skip_to_space (char *chp) +{ + return (char *) skip_to_space ((const char *) chp); +} + +/* See gdbsupport/common-utils.h. */ + +void +free_vector_argv (std::vector &v) +{ + for (char *el : v) + xfree (el); + + v.clear (); +} + +/* See gdbsupport/common-utils.h. */ + +std::string +stringify_argv (const std::vector &args) +{ + std::string ret; + + if (!args.empty () && args[0] != NULL) + { + for (auto s : args) + if (s != NULL) + { + ret += s; + ret += ' '; + } + + /* Erase the last whitespace. */ + ret.erase (ret.end () - 1); + } + + return ret; +} + +/* See gdbsupport/common-utils.h. */ + +ULONGEST +align_up (ULONGEST v, int n) +{ + /* Check that N is really a power of two. */ + gdb_assert (n && (n & (n-1)) == 0); + return (v + n - 1) & -n; +} + +/* See gdbsupport/common-utils.h. */ + +ULONGEST +align_down (ULONGEST v, int n) +{ + /* Check that N is really a power of two. */ + gdb_assert (n && (n & (n-1)) == 0); + return (v & -n); +} diff --git a/gdbsupport/environ.c b/gdbsupport/environ.c deleted file mode 100644 index 32434ee..0000000 --- a/gdbsupport/environ.c +++ /dev/null @@ -1,183 +0,0 @@ -/* environ.c -- library for manipulating environments for GNU. - - Copyright (C) 1986-2020 Free Software Foundation, Inc. - - 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 . */ - -#include "common-defs.h" -#include "environ.h" -#include -#include - -/* See gdbsupport/environ.h. */ - -gdb_environ & -gdb_environ::operator= (gdb_environ &&e) -{ - /* Are we self-moving? */ - if (&e == this) - return *this; - - m_environ_vector = std::move (e.m_environ_vector); - m_user_set_env = std::move (e.m_user_set_env); - m_user_unset_env = std::move (e.m_user_unset_env); - e.m_environ_vector.clear (); - e.m_environ_vector.push_back (NULL); - e.m_user_set_env.clear (); - e.m_user_unset_env.clear (); - return *this; -} - -/* See gdbsupport/environ.h. */ - -gdb_environ gdb_environ::from_host_environ () -{ - extern char **environ; - gdb_environ e; - - if (environ == NULL) - return e; - - for (int i = 0; environ[i] != NULL; ++i) - { - /* Make sure we add the element before the last (NULL). */ - e.m_environ_vector.insert (e.m_environ_vector.end () - 1, - xstrdup (environ[i])); - } - - return e; -} - -/* See gdbsupport/environ.h. */ - -void -gdb_environ::clear () -{ - for (char *v : m_environ_vector) - xfree (v); - m_environ_vector.clear (); - /* Always add the NULL element. */ - m_environ_vector.push_back (NULL); - m_user_set_env.clear (); - m_user_unset_env.clear (); -} - -/* Helper function to check if STRING contains an environment variable - assignment of VAR, i.e., if STRING starts with 'VAR='. Return true - if it contains, false otherwise. */ - -static bool -match_var_in_string (const char *string, const char *var, size_t var_len) -{ - if (strncmp (string, var, var_len) == 0 && string[var_len] == '=') - return true; - - return false; -} - -/* See gdbsupport/environ.h. */ - -const char * -gdb_environ::get (const char *var) const -{ - size_t len = strlen (var); - - for (char *el : m_environ_vector) - if (el != NULL && match_var_in_string (el, var, len)) - return &el[len + 1]; - - return NULL; -} - -/* See gdbsupport/environ.h. */ - -void -gdb_environ::set (const char *var, const char *value) -{ - char *fullvar = concat (var, "=", value, (char *) NULL); - - /* We have to unset the variable in the vector if it exists. */ - unset (var, false); - - /* Insert the element before the last one, which is always NULL. */ - m_environ_vector.insert (m_environ_vector.end () - 1, fullvar); - - /* Mark this environment variable as having been set by the user. - This will be useful when we deal with setting environment - variables on the remote target. */ - m_user_set_env.insert (std::string (fullvar)); - - /* If this environment variable is marked as unset by the user, then - remove it from the list, because now the user wants to set - it. */ - m_user_unset_env.erase (std::string (var)); -} - -/* See gdbsupport/environ.h. */ - -void -gdb_environ::unset (const char *var, bool update_unset_list) -{ - size_t len = strlen (var); - std::vector::iterator it_env; - - /* We iterate until '.end () - 1' because the last element is - always NULL. */ - for (it_env = m_environ_vector.begin (); - it_env != m_environ_vector.end () - 1; - ++it_env) - if (match_var_in_string (*it_env, var, len)) - break; - - if (it_env != m_environ_vector.end () - 1) - { - m_user_set_env.erase (std::string (*it_env)); - xfree (*it_env); - - m_environ_vector.erase (it_env); - } - - if (update_unset_list) - m_user_unset_env.insert (std::string (var)); -} - -/* See gdbsupport/environ.h. */ - -void -gdb_environ::unset (const char *var) -{ - unset (var, true); -} - -/* See gdbsupport/environ.h. */ - -char ** -gdb_environ::envp () const -{ - return const_cast (&m_environ_vector[0]); -} - -/* See gdbsupport/environ.h. */ - -const std::set & -gdb_environ::user_set_env () const -{ - return m_user_set_env; -} - -const std::set & -gdb_environ::user_unset_env () const -{ - return m_user_unset_env; -} diff --git a/gdbsupport/environ.cc b/gdbsupport/environ.cc new file mode 100644 index 0000000..32434ee --- /dev/null +++ b/gdbsupport/environ.cc @@ -0,0 +1,183 @@ +/* environ.c -- library for manipulating environments for GNU. + + Copyright (C) 1986-2020 Free Software Foundation, Inc. + + 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 . */ + +#include "common-defs.h" +#include "environ.h" +#include +#include + +/* See gdbsupport/environ.h. */ + +gdb_environ & +gdb_environ::operator= (gdb_environ &&e) +{ + /* Are we self-moving? */ + if (&e == this) + return *this; + + m_environ_vector = std::move (e.m_environ_vector); + m_user_set_env = std::move (e.m_user_set_env); + m_user_unset_env = std::move (e.m_user_unset_env); + e.m_environ_vector.clear (); + e.m_environ_vector.push_back (NULL); + e.m_user_set_env.clear (); + e.m_user_unset_env.clear (); + return *this; +} + +/* See gdbsupport/environ.h. */ + +gdb_environ gdb_environ::from_host_environ () +{ + extern char **environ; + gdb_environ e; + + if (environ == NULL) + return e; + + for (int i = 0; environ[i] != NULL; ++i) + { + /* Make sure we add the element before the last (NULL). */ + e.m_environ_vector.insert (e.m_environ_vector.end () - 1, + xstrdup (environ[i])); + } + + return e; +} + +/* See gdbsupport/environ.h. */ + +void +gdb_environ::clear () +{ + for (char *v : m_environ_vector) + xfree (v); + m_environ_vector.clear (); + /* Always add the NULL element. */ + m_environ_vector.push_back (NULL); + m_user_set_env.clear (); + m_user_unset_env.clear (); +} + +/* Helper function to check if STRING contains an environment variable + assignment of VAR, i.e., if STRING starts with 'VAR='. Return true + if it contains, false otherwise. */ + +static bool +match_var_in_string (const char *string, const char *var, size_t var_len) +{ + if (strncmp (string, var, var_len) == 0 && string[var_len] == '=') + return true; + + return false; +} + +/* See gdbsupport/environ.h. */ + +const char * +gdb_environ::get (const char *var) const +{ + size_t len = strlen (var); + + for (char *el : m_environ_vector) + if (el != NULL && match_var_in_string (el, var, len)) + return &el[len + 1]; + + return NULL; +} + +/* See gdbsupport/environ.h. */ + +void +gdb_environ::set (const char *var, const char *value) +{ + char *fullvar = concat (var, "=", value, (char *) NULL); + + /* We have to unset the variable in the vector if it exists. */ + unset (var, false); + + /* Insert the element before the last one, which is always NULL. */ + m_environ_vector.insert (m_environ_vector.end () - 1, fullvar); + + /* Mark this environment variable as having been set by the user. + This will be useful when we deal with setting environment + variables on the remote target. */ + m_user_set_env.insert (std::string (fullvar)); + + /* If this environment variable is marked as unset by the user, then + remove it from the list, because now the user wants to set + it. */ + m_user_unset_env.erase (std::string (var)); +} + +/* See gdbsupport/environ.h. */ + +void +gdb_environ::unset (const char *var, bool update_unset_list) +{ + size_t len = strlen (var); + std::vector::iterator it_env; + + /* We iterate until '.end () - 1' because the last element is + always NULL. */ + for (it_env = m_environ_vector.begin (); + it_env != m_environ_vector.end () - 1; + ++it_env) + if (match_var_in_string (*it_env, var, len)) + break; + + if (it_env != m_environ_vector.end () - 1) + { + m_user_set_env.erase (std::string (*it_env)); + xfree (*it_env); + + m_environ_vector.erase (it_env); + } + + if (update_unset_list) + m_user_unset_env.insert (std::string (var)); +} + +/* See gdbsupport/environ.h. */ + +void +gdb_environ::unset (const char *var) +{ + unset (var, true); +} + +/* See gdbsupport/environ.h. */ + +char ** +gdb_environ::envp () const +{ + return const_cast (&m_environ_vector[0]); +} + +/* See gdbsupport/environ.h. */ + +const std::set & +gdb_environ::user_set_env () const +{ + return m_user_set_env; +} + +const std::set & +gdb_environ::user_unset_env () const +{ + return m_user_unset_env; +} diff --git a/gdbsupport/errors.c b/gdbsupport/errors.c deleted file mode 100644 index 3fcac79..0000000 --- a/gdbsupport/errors.c +++ /dev/null @@ -1,69 +0,0 @@ -/* Error reporting facilities. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "errors.h" - -/* See gdbsupport/errors.h. */ - -void -warning (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - vwarning (fmt, ap); - va_end (ap); -} - -/* See gdbsupport/errors.h. */ - -void -error (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - verror (fmt, ap); - va_end (ap); -} - -/* See gdbsupport/errors.h. */ - -void -internal_error (const char *file, int line, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - internal_verror (file, line, fmt, ap); - va_end (ap); -} - -/* See gdbsupport/errors.h. */ - -void -internal_warning (const char *file, int line, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - internal_vwarning (file, line, fmt, ap); - va_end (ap); -} diff --git a/gdbsupport/errors.cc b/gdbsupport/errors.cc new file mode 100644 index 0000000..3fcac79 --- /dev/null +++ b/gdbsupport/errors.cc @@ -0,0 +1,69 @@ +/* Error reporting facilities. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "errors.h" + +/* See gdbsupport/errors.h. */ + +void +warning (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vwarning (fmt, ap); + va_end (ap); +} + +/* See gdbsupport/errors.h. */ + +void +error (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + verror (fmt, ap); + va_end (ap); +} + +/* See gdbsupport/errors.h. */ + +void +internal_error (const char *file, int line, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + internal_verror (file, line, fmt, ap); + va_end (ap); +} + +/* See gdbsupport/errors.h. */ + +void +internal_warning (const char *file, int line, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + internal_vwarning (file, line, fmt, ap); + va_end (ap); +} diff --git a/gdbsupport/fileio.c b/gdbsupport/fileio.c deleted file mode 100644 index 69ed426..0000000 --- a/gdbsupport/fileio.c +++ /dev/null @@ -1,255 +0,0 @@ -/* File-I/O functions for GDB, the GNU debugger. - - Copyright (C) 2003-2020 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 . */ - -#include "common-defs.h" -#include "fileio.h" -#include -#include - -/* See fileio.h. */ - -int -host_to_fileio_error (int error) -{ - switch (error) - { - case EPERM: - return FILEIO_EPERM; - case ENOENT: - return FILEIO_ENOENT; - case EINTR: - return FILEIO_EINTR; - case EIO: - return FILEIO_EIO; - case EBADF: - return FILEIO_EBADF; - case EACCES: - return FILEIO_EACCES; - case EFAULT: - return FILEIO_EFAULT; - case EBUSY: - return FILEIO_EBUSY; - case EEXIST: - return FILEIO_EEXIST; - case ENODEV: - return FILEIO_ENODEV; - case ENOTDIR: - return FILEIO_ENOTDIR; - case EISDIR: - return FILEIO_EISDIR; - case EINVAL: - return FILEIO_EINVAL; - case ENFILE: - return FILEIO_ENFILE; - case EMFILE: - return FILEIO_EMFILE; - case EFBIG: - return FILEIO_EFBIG; - case ENOSPC: - return FILEIO_ENOSPC; - case ESPIPE: - return FILEIO_ESPIPE; - case EROFS: - return FILEIO_EROFS; - case ENOSYS: - return FILEIO_ENOSYS; - case ENAMETOOLONG: - return FILEIO_ENAMETOOLONG; - } - return FILEIO_EUNKNOWN; -} - -/* See fileio.h. */ - -int -fileio_to_host_openflags (int fileio_open_flags, int *open_flags_p) -{ - int open_flags = 0; - - if (fileio_open_flags & ~FILEIO_O_SUPPORTED) - return -1; - - if (fileio_open_flags & FILEIO_O_CREAT) - open_flags |= O_CREAT; - if (fileio_open_flags & FILEIO_O_EXCL) - open_flags |= O_EXCL; - if (fileio_open_flags & FILEIO_O_TRUNC) - open_flags |= O_TRUNC; - if (fileio_open_flags & FILEIO_O_APPEND) - open_flags |= O_APPEND; - if (fileio_open_flags & FILEIO_O_RDONLY) - open_flags |= O_RDONLY; - if (fileio_open_flags & FILEIO_O_WRONLY) - open_flags |= O_WRONLY; - if (fileio_open_flags & FILEIO_O_RDWR) - open_flags |= O_RDWR; - /* On systems supporting binary and text mode, always open files - in binary mode. */ -#ifdef O_BINARY - open_flags |= O_BINARY; -#endif - - *open_flags_p = open_flags; - return 0; -} - -/* See fileio.h. */ - -int -fileio_to_host_mode (int fileio_mode, mode_t *mode_p) -{ - mode_t mode = 0; - - if (fileio_mode & ~FILEIO_S_SUPPORTED) - return -1; - - if (fileio_mode & FILEIO_S_IFREG) - mode |= S_IFREG; - if (fileio_mode & FILEIO_S_IFDIR) - mode |= S_IFDIR; - if (fileio_mode & FILEIO_S_IFCHR) - mode |= S_IFCHR; - if (fileio_mode & FILEIO_S_IRUSR) - mode |= S_IRUSR; - if (fileio_mode & FILEIO_S_IWUSR) - mode |= S_IWUSR; - if (fileio_mode & FILEIO_S_IXUSR) - mode |= S_IXUSR; -#ifdef S_IRGRP - if (fileio_mode & FILEIO_S_IRGRP) - mode |= S_IRGRP; -#endif -#ifdef S_IWGRP - if (fileio_mode & FILEIO_S_IWGRP) - mode |= S_IWGRP; -#endif -#ifdef S_IXGRP - if (fileio_mode & FILEIO_S_IXGRP) - mode |= S_IXGRP; -#endif - if (fileio_mode & FILEIO_S_IROTH) - mode |= S_IROTH; -#ifdef S_IWOTH - if (fileio_mode & FILEIO_S_IWOTH) - mode |= S_IWOTH; -#endif -#ifdef S_IXOTH - if (fileio_mode & FILEIO_S_IXOTH) - mode |= S_IXOTH; -#endif - - *mode_p = mode; - return 0; -} - -/* Convert a host-format mode_t into a bitmask of File-I/O flags. */ - -static LONGEST -fileio_mode_pack (mode_t mode) -{ - mode_t tmode = 0; - - if (S_ISREG (mode)) - tmode |= FILEIO_S_IFREG; - if (S_ISDIR (mode)) - tmode |= FILEIO_S_IFDIR; - if (S_ISCHR (mode)) - tmode |= FILEIO_S_IFCHR; - if (mode & S_IRUSR) - tmode |= FILEIO_S_IRUSR; - if (mode & S_IWUSR) - tmode |= FILEIO_S_IWUSR; - if (mode & S_IXUSR) - tmode |= FILEIO_S_IXUSR; -#ifdef S_IRGRP - if (mode & S_IRGRP) - tmode |= FILEIO_S_IRGRP; -#endif -#ifdef S_IWGRP - if (mode & S_IWGRP) - tmode |= FILEIO_S_IWGRP; -#endif -#ifdef S_IXGRP - if (mode & S_IXGRP) - tmode |= FILEIO_S_IXGRP; -#endif - if (mode & S_IROTH) - tmode |= FILEIO_S_IROTH; -#ifdef S_IWOTH - if (mode & S_IWOTH) - tmode |= FILEIO_S_IWOTH; -#endif -#ifdef S_IXOTH - if (mode & S_IXOTH) - tmode |= FILEIO_S_IXOTH; -#endif - return tmode; -} - -/* Pack a host-format mode_t into an fio_mode_t. */ - -static void -host_to_fileio_mode (mode_t num, fio_mode_t fnum) -{ - host_to_bigendian (fileio_mode_pack (num), (char *) fnum, 4); -} - -/* Pack a host-format integer into an fio_ulong_t. */ - -static void -host_to_fileio_ulong (LONGEST num, fio_ulong_t fnum) -{ - host_to_bigendian (num, (char *) fnum, 8); -} - -/* See fileio.h. */ - -void -host_to_fileio_stat (struct stat *st, struct fio_stat *fst) -{ - LONGEST blksize; - - host_to_fileio_uint ((long) st->st_dev, fst->fst_dev); - host_to_fileio_uint ((long) st->st_ino, fst->fst_ino); - host_to_fileio_mode (st->st_mode, fst->fst_mode); - host_to_fileio_uint ((long) st->st_nlink, fst->fst_nlink); - host_to_fileio_uint ((long) st->st_uid, fst->fst_uid); - host_to_fileio_uint ((long) st->st_gid, fst->fst_gid); - host_to_fileio_uint ((long) st->st_rdev, fst->fst_rdev); - host_to_fileio_ulong ((LONGEST) st->st_size, fst->fst_size); -#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - blksize = st->st_blksize; -#else - blksize = 512; -#endif - host_to_fileio_ulong (blksize, fst->fst_blksize); -#if HAVE_STRUCT_STAT_ST_BLOCKS - host_to_fileio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks); -#else - /* FIXME: This is correct for DJGPP, but other systems that don't - have st_blocks, if any, might prefer 512 instead of st_blksize. - (eliz, 30-12-2003) */ - host_to_fileio_ulong (((LONGEST) st->st_size + blksize - 1) - / blksize, - fst->fst_blocks); -#endif - host_to_fileio_time (st->st_atime, fst->fst_atime); - host_to_fileio_time (st->st_mtime, fst->fst_mtime); - host_to_fileio_time (st->st_ctime, fst->fst_ctime); -} diff --git a/gdbsupport/fileio.cc b/gdbsupport/fileio.cc new file mode 100644 index 0000000..69ed426 --- /dev/null +++ b/gdbsupport/fileio.cc @@ -0,0 +1,255 @@ +/* File-I/O functions for GDB, the GNU debugger. + + Copyright (C) 2003-2020 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 . */ + +#include "common-defs.h" +#include "fileio.h" +#include +#include + +/* See fileio.h. */ + +int +host_to_fileio_error (int error) +{ + switch (error) + { + case EPERM: + return FILEIO_EPERM; + case ENOENT: + return FILEIO_ENOENT; + case EINTR: + return FILEIO_EINTR; + case EIO: + return FILEIO_EIO; + case EBADF: + return FILEIO_EBADF; + case EACCES: + return FILEIO_EACCES; + case EFAULT: + return FILEIO_EFAULT; + case EBUSY: + return FILEIO_EBUSY; + case EEXIST: + return FILEIO_EEXIST; + case ENODEV: + return FILEIO_ENODEV; + case ENOTDIR: + return FILEIO_ENOTDIR; + case EISDIR: + return FILEIO_EISDIR; + case EINVAL: + return FILEIO_EINVAL; + case ENFILE: + return FILEIO_ENFILE; + case EMFILE: + return FILEIO_EMFILE; + case EFBIG: + return FILEIO_EFBIG; + case ENOSPC: + return FILEIO_ENOSPC; + case ESPIPE: + return FILEIO_ESPIPE; + case EROFS: + return FILEIO_EROFS; + case ENOSYS: + return FILEIO_ENOSYS; + case ENAMETOOLONG: + return FILEIO_ENAMETOOLONG; + } + return FILEIO_EUNKNOWN; +} + +/* See fileio.h. */ + +int +fileio_to_host_openflags (int fileio_open_flags, int *open_flags_p) +{ + int open_flags = 0; + + if (fileio_open_flags & ~FILEIO_O_SUPPORTED) + return -1; + + if (fileio_open_flags & FILEIO_O_CREAT) + open_flags |= O_CREAT; + if (fileio_open_flags & FILEIO_O_EXCL) + open_flags |= O_EXCL; + if (fileio_open_flags & FILEIO_O_TRUNC) + open_flags |= O_TRUNC; + if (fileio_open_flags & FILEIO_O_APPEND) + open_flags |= O_APPEND; + if (fileio_open_flags & FILEIO_O_RDONLY) + open_flags |= O_RDONLY; + if (fileio_open_flags & FILEIO_O_WRONLY) + open_flags |= O_WRONLY; + if (fileio_open_flags & FILEIO_O_RDWR) + open_flags |= O_RDWR; + /* On systems supporting binary and text mode, always open files + in binary mode. */ +#ifdef O_BINARY + open_flags |= O_BINARY; +#endif + + *open_flags_p = open_flags; + return 0; +} + +/* See fileio.h. */ + +int +fileio_to_host_mode (int fileio_mode, mode_t *mode_p) +{ + mode_t mode = 0; + + if (fileio_mode & ~FILEIO_S_SUPPORTED) + return -1; + + if (fileio_mode & FILEIO_S_IFREG) + mode |= S_IFREG; + if (fileio_mode & FILEIO_S_IFDIR) + mode |= S_IFDIR; + if (fileio_mode & FILEIO_S_IFCHR) + mode |= S_IFCHR; + if (fileio_mode & FILEIO_S_IRUSR) + mode |= S_IRUSR; + if (fileio_mode & FILEIO_S_IWUSR) + mode |= S_IWUSR; + if (fileio_mode & FILEIO_S_IXUSR) + mode |= S_IXUSR; +#ifdef S_IRGRP + if (fileio_mode & FILEIO_S_IRGRP) + mode |= S_IRGRP; +#endif +#ifdef S_IWGRP + if (fileio_mode & FILEIO_S_IWGRP) + mode |= S_IWGRP; +#endif +#ifdef S_IXGRP + if (fileio_mode & FILEIO_S_IXGRP) + mode |= S_IXGRP; +#endif + if (fileio_mode & FILEIO_S_IROTH) + mode |= S_IROTH; +#ifdef S_IWOTH + if (fileio_mode & FILEIO_S_IWOTH) + mode |= S_IWOTH; +#endif +#ifdef S_IXOTH + if (fileio_mode & FILEIO_S_IXOTH) + mode |= S_IXOTH; +#endif + + *mode_p = mode; + return 0; +} + +/* Convert a host-format mode_t into a bitmask of File-I/O flags. */ + +static LONGEST +fileio_mode_pack (mode_t mode) +{ + mode_t tmode = 0; + + if (S_ISREG (mode)) + tmode |= FILEIO_S_IFREG; + if (S_ISDIR (mode)) + tmode |= FILEIO_S_IFDIR; + if (S_ISCHR (mode)) + tmode |= FILEIO_S_IFCHR; + if (mode & S_IRUSR) + tmode |= FILEIO_S_IRUSR; + if (mode & S_IWUSR) + tmode |= FILEIO_S_IWUSR; + if (mode & S_IXUSR) + tmode |= FILEIO_S_IXUSR; +#ifdef S_IRGRP + if (mode & S_IRGRP) + tmode |= FILEIO_S_IRGRP; +#endif +#ifdef S_IWGRP + if (mode & S_IWGRP) + tmode |= FILEIO_S_IWGRP; +#endif +#ifdef S_IXGRP + if (mode & S_IXGRP) + tmode |= FILEIO_S_IXGRP; +#endif + if (mode & S_IROTH) + tmode |= FILEIO_S_IROTH; +#ifdef S_IWOTH + if (mode & S_IWOTH) + tmode |= FILEIO_S_IWOTH; +#endif +#ifdef S_IXOTH + if (mode & S_IXOTH) + tmode |= FILEIO_S_IXOTH; +#endif + return tmode; +} + +/* Pack a host-format mode_t into an fio_mode_t. */ + +static void +host_to_fileio_mode (mode_t num, fio_mode_t fnum) +{ + host_to_bigendian (fileio_mode_pack (num), (char *) fnum, 4); +} + +/* Pack a host-format integer into an fio_ulong_t. */ + +static void +host_to_fileio_ulong (LONGEST num, fio_ulong_t fnum) +{ + host_to_bigendian (num, (char *) fnum, 8); +} + +/* See fileio.h. */ + +void +host_to_fileio_stat (struct stat *st, struct fio_stat *fst) +{ + LONGEST blksize; + + host_to_fileio_uint ((long) st->st_dev, fst->fst_dev); + host_to_fileio_uint ((long) st->st_ino, fst->fst_ino); + host_to_fileio_mode (st->st_mode, fst->fst_mode); + host_to_fileio_uint ((long) st->st_nlink, fst->fst_nlink); + host_to_fileio_uint ((long) st->st_uid, fst->fst_uid); + host_to_fileio_uint ((long) st->st_gid, fst->fst_gid); + host_to_fileio_uint ((long) st->st_rdev, fst->fst_rdev); + host_to_fileio_ulong ((LONGEST) st->st_size, fst->fst_size); +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + blksize = st->st_blksize; +#else + blksize = 512; +#endif + host_to_fileio_ulong (blksize, fst->fst_blksize); +#if HAVE_STRUCT_STAT_ST_BLOCKS + host_to_fileio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks); +#else + /* FIXME: This is correct for DJGPP, but other systems that don't + have st_blocks, if any, might prefer 512 instead of st_blksize. + (eliz, 30-12-2003) */ + host_to_fileio_ulong (((LONGEST) st->st_size + blksize - 1) + / blksize, + fst->fst_blocks); +#endif + host_to_fileio_time (st->st_atime, fst->fst_atime); + host_to_fileio_time (st->st_mtime, fst->fst_mtime); + host_to_fileio_time (st->st_ctime, fst->fst_ctime); +} diff --git a/gdbsupport/filestuff.c b/gdbsupport/filestuff.c deleted file mode 100644 index 179c425..0000000 --- a/gdbsupport/filestuff.c +++ /dev/null @@ -1,503 +0,0 @@ -/* Low-level file-handling. - Copyright (C) 2012-2020 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 . */ - -#include "common-defs.h" -#include "filestuff.h" -#include "gdb_vecs.h" -#include -#include -#include -#include -#include - -#ifdef USE_WIN32API -#include -#include -#define HAVE_SOCKETS 1 -#elif defined HAVE_SYS_SOCKET_H -#include -/* Define HAVE_F_GETFD if we plan to use F_GETFD. */ -#define HAVE_F_GETFD F_GETFD -#define HAVE_SOCKETS 1 -#endif - -#ifdef HAVE_KINFO_GETFILE -#include -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif /* HAVE_SYS_RESOURCE_H */ - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#ifndef O_NOINHERIT -#define O_NOINHERIT 0 -#endif - -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif - - - -#ifndef HAVE_FDWALK - -#include - -/* Replacement for fdwalk, if the system doesn't define it. Walks all - open file descriptors (though this implementation may walk closed - ones as well, depending on the host platform's capabilities) and - call FUNC with ARG. If FUNC returns non-zero, stops immediately - and returns the same value. Otherwise, returns zero when - finished. */ - -static int -fdwalk (int (*func) (void *, int), void *arg) -{ - /* Checking __linux__ isn't great but it isn't clear what would be - better. There doesn't seem to be a good way to check for this in - configure. */ -#ifdef __linux__ - DIR *dir; - - dir = opendir ("/proc/self/fd"); - if (dir != NULL) - { - struct dirent *entry; - int result = 0; - - for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) - { - long fd; - char *tail; - - errno = 0; - fd = strtol (entry->d_name, &tail, 10); - if (*tail != '\0' || errno != 0) - continue; - if ((int) fd != fd) - { - /* What can we do here really? */ - continue; - } - - if (fd == dirfd (dir)) - continue; - - result = func (arg, fd); - if (result != 0) - break; - } - - closedir (dir); - return result; - } - /* We may fall through to the next case. */ -#endif -#ifdef HAVE_KINFO_GETFILE - int nfd; - gdb::unique_xmalloc_ptr fdtbl - (kinfo_getfile (getpid (), &nfd)); - if (fdtbl != NULL) - { - for (int i = 0; i < nfd; i++) - { - if (fdtbl[i].kf_fd >= 0) - { - int result = func (arg, fdtbl[i].kf_fd); - if (result != 0) - return result; - } - } - return 0; - } - /* We may fall through to the next case. */ -#endif - - { - int max, fd; - -#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) - struct rlimit rlim; - - if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY) - max = rlim.rlim_max; - else -#endif - { -#ifdef _SC_OPEN_MAX - max = sysconf (_SC_OPEN_MAX); -#else - /* Whoops. */ - return 0; -#endif /* _SC_OPEN_MAX */ - } - - for (fd = 0; fd < max; ++fd) - { - struct stat sb; - int result; - - /* Only call FUNC for open fds. */ - if (fstat (fd, &sb) == -1) - continue; - - result = func (arg, fd); - if (result != 0) - return result; - } - - return 0; - } -} - -#endif /* HAVE_FDWALK */ - - - -/* A vector holding all the fds open when notice_open_fds was called. We - don't use a hashtab because we don't expect there to be many open fds. */ - -static std::vector open_fds; - -/* An fdwalk callback function used by notice_open_fds. It puts the - given file descriptor into the vec. */ - -static int -do_mark_open_fd (void *ignore, int fd) -{ - open_fds.push_back (fd); - return 0; -} - -/* See filestuff.h. */ - -void -notice_open_fds (void) -{ - fdwalk (do_mark_open_fd, NULL); -} - -/* See filestuff.h. */ - -void -mark_fd_no_cloexec (int fd) -{ - do_mark_open_fd (NULL, fd); -} - -/* See filestuff.h. */ - -void -unmark_fd_no_cloexec (int fd) -{ - auto it = std::remove (open_fds.begin (), open_fds.end (), fd); - - if (it != open_fds.end ()) - open_fds.erase (it); - else - gdb_assert_not_reached (_("fd not found in open_fds")); -} - -/* Helper function for close_most_fds that closes the file descriptor - if appropriate. */ - -static int -do_close (void *ignore, int fd) -{ - for (int val : open_fds) - { - if (fd == val) - { - /* Keep this one open. */ - return 0; - } - } - - close (fd); - return 0; -} - -/* See filestuff.h. */ - -void -close_most_fds (void) -{ - fdwalk (do_close, NULL); -} - - - -/* This is a tri-state flag. When zero it means we haven't yet tried - O_CLOEXEC. When positive it means that O_CLOEXEC works on this - host. When negative, it means that O_CLOEXEC doesn't work. We - track this state because, while gdb might have been compiled - against a libc that supplies O_CLOEXEC, there is no guarantee that - the kernel supports it. */ - -static int trust_o_cloexec; - -/* Mark FD as close-on-exec, ignoring errors. Update - TRUST_O_CLOEXEC. */ - -static void -mark_cloexec (int fd) -{ -#ifdef HAVE_F_GETFD - int old = fcntl (fd, F_GETFD, 0); - - if (old != -1) - { - fcntl (fd, F_SETFD, old | FD_CLOEXEC); - - if (trust_o_cloexec == 0) - { - if ((old & FD_CLOEXEC) != 0) - trust_o_cloexec = 1; - else - trust_o_cloexec = -1; - } - } -#endif /* HAVE_F_GETFD */ -} - -/* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */ - -static void -maybe_mark_cloexec (int fd) -{ - if (trust_o_cloexec <= 0) - mark_cloexec (fd); -} - -#ifdef HAVE_SOCKETS - -/* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */ - -static void -socket_mark_cloexec (int fd) -{ - if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0) - mark_cloexec (fd); -} - -#endif - - - -/* See filestuff.h. */ - -int -gdb_open_cloexec (const char *filename, int flags, unsigned long mode) -{ - int fd = open (filename, flags | O_CLOEXEC, mode); - - if (fd >= 0) - maybe_mark_cloexec (fd); - - return fd; -} - -/* See filestuff.h. */ - -gdb_file_up -gdb_fopen_cloexec (const char *filename, const char *opentype) -{ - FILE *result; - /* Probe for "e" support once. But, if we can tell the operating - system doesn't know about close on exec mode "e" without probing, - skip it. E.g., the Windows runtime issues an "Invalid parameter - passed to C runtime function" OutputDebugString warning for - unknown modes. Assume that if O_CLOEXEC is zero, then "e" isn't - supported. On MinGW, O_CLOEXEC is an alias of O_NOINHERIT, and - "e" isn't supported. */ - static int fopen_e_ever_failed_einval = - O_CLOEXEC == 0 || O_CLOEXEC == O_NOINHERIT; - - if (!fopen_e_ever_failed_einval) - { - char *copy; - - copy = (char *) alloca (strlen (opentype) + 2); - strcpy (copy, opentype); - /* This is a glibc extension but we try it unconditionally on - this path. */ - strcat (copy, "e"); - result = fopen (filename, copy); - - if (result == NULL && errno == EINVAL) - { - result = fopen (filename, opentype); - if (result != NULL) - fopen_e_ever_failed_einval = 1; - } - } - else - result = fopen (filename, opentype); - - if (result != NULL) - maybe_mark_cloexec (fileno (result)); - - return gdb_file_up (result); -} - -#ifdef HAVE_SOCKETS -/* See filestuff.h. */ - -int -gdb_socketpair_cloexec (int domain, int style, int protocol, - int filedes[2]) -{ -#ifdef HAVE_SOCKETPAIR - int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes); - - if (result != -1) - { - socket_mark_cloexec (filedes[0]); - socket_mark_cloexec (filedes[1]); - } - - return result; -#else - gdb_assert_not_reached (_("socketpair not available on this host")); -#endif -} - -/* See filestuff.h. */ - -int -gdb_socket_cloexec (int domain, int style, int protocol) -{ - int result = socket (domain, style | SOCK_CLOEXEC, protocol); - - if (result != -1) - socket_mark_cloexec (result); - - return result; -} -#endif - -/* See filestuff.h. */ - -int -gdb_pipe_cloexec (int filedes[2]) -{ - int result; - -#ifdef HAVE_PIPE2 - result = pipe2 (filedes, O_CLOEXEC); - if (result != -1) - { - maybe_mark_cloexec (filedes[0]); - maybe_mark_cloexec (filedes[1]); - } -#else -#ifdef HAVE_PIPE - result = pipe (filedes); - if (result != -1) - { - mark_cloexec (filedes[0]); - mark_cloexec (filedes[1]); - } -#else /* HAVE_PIPE */ - gdb_assert_not_reached (_("pipe not available on this host")); -#endif /* HAVE_PIPE */ -#endif /* HAVE_PIPE2 */ - - return result; -} - -/* See gdbsupport/filestuff.h. */ - -bool -is_regular_file (const char *name, int *errno_ptr) -{ - struct stat st; - const int status = stat (name, &st); - - /* Stat should never fail except when the file does not exist. - If stat fails, analyze the source of error and return true - unless the file does not exist, to avoid returning false results - on obscure systems where stat does not work as expected. */ - - if (status != 0) - { - if (errno != ENOENT) - return true; - *errno_ptr = ENOENT; - return false; - } - - if (S_ISREG (st.st_mode)) - return true; - - if (S_ISDIR (st.st_mode)) - *errno_ptr = EISDIR; - else - *errno_ptr = EINVAL; - return false; -} - -/* See gdbsupport/filestuff.h. */ - -bool -mkdir_recursive (const char *dir) -{ - auto holder = make_unique_xstrdup (dir); - char * const start = holder.get (); - char *component_start = start; - char *component_end = start; - - while (1) - { - /* Find the beginning of the next component. */ - while (*component_start == '/') - component_start++; - - /* Are we done? */ - if (*component_start == '\0') - return true; - - /* Find the slash or null-terminator after this component. */ - component_end = component_start; - while (*component_end != '/' && *component_end != '\0') - component_end++; - - /* Temporarily replace the slash with a null terminator, so we can create - the directory up to this component. */ - char saved_char = *component_end; - *component_end = '\0'; - - /* If we get EEXIST and the existing path is a directory, then we're - happy. If it exists, but it's a regular file and this is not the last - component, we'll fail at the next component. If this is the last - component, the caller will fail with ENOTDIR when trying to - open/create a file under that path. */ - if (mkdir (start, 0700) != 0) - if (errno != EEXIST) - return false; - - /* Restore the overwritten char. */ - *component_end = saved_char; - component_start = component_end; - } -} diff --git a/gdbsupport/filestuff.cc b/gdbsupport/filestuff.cc new file mode 100644 index 0000000..179c425 --- /dev/null +++ b/gdbsupport/filestuff.cc @@ -0,0 +1,503 @@ +/* Low-level file-handling. + Copyright (C) 2012-2020 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 . */ + +#include "common-defs.h" +#include "filestuff.h" +#include "gdb_vecs.h" +#include +#include +#include +#include +#include + +#ifdef USE_WIN32API +#include +#include +#define HAVE_SOCKETS 1 +#elif defined HAVE_SYS_SOCKET_H +#include +/* Define HAVE_F_GETFD if we plan to use F_GETFD. */ +#define HAVE_F_GETFD F_GETFD +#define HAVE_SOCKETS 1 +#endif + +#ifdef HAVE_KINFO_GETFILE +#include +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef O_NOINHERIT +#define O_NOINHERIT 0 +#endif + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + + + +#ifndef HAVE_FDWALK + +#include + +/* Replacement for fdwalk, if the system doesn't define it. Walks all + open file descriptors (though this implementation may walk closed + ones as well, depending on the host platform's capabilities) and + call FUNC with ARG. If FUNC returns non-zero, stops immediately + and returns the same value. Otherwise, returns zero when + finished. */ + +static int +fdwalk (int (*func) (void *, int), void *arg) +{ + /* Checking __linux__ isn't great but it isn't clear what would be + better. There doesn't seem to be a good way to check for this in + configure. */ +#ifdef __linux__ + DIR *dir; + + dir = opendir ("/proc/self/fd"); + if (dir != NULL) + { + struct dirent *entry; + int result = 0; + + for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) + { + long fd; + char *tail; + + errno = 0; + fd = strtol (entry->d_name, &tail, 10); + if (*tail != '\0' || errno != 0) + continue; + if ((int) fd != fd) + { + /* What can we do here really? */ + continue; + } + + if (fd == dirfd (dir)) + continue; + + result = func (arg, fd); + if (result != 0) + break; + } + + closedir (dir); + return result; + } + /* We may fall through to the next case. */ +#endif +#ifdef HAVE_KINFO_GETFILE + int nfd; + gdb::unique_xmalloc_ptr fdtbl + (kinfo_getfile (getpid (), &nfd)); + if (fdtbl != NULL) + { + for (int i = 0; i < nfd; i++) + { + if (fdtbl[i].kf_fd >= 0) + { + int result = func (arg, fdtbl[i].kf_fd); + if (result != 0) + return result; + } + } + return 0; + } + /* We may fall through to the next case. */ +#endif + + { + int max, fd; + +#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit rlim; + + if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY) + max = rlim.rlim_max; + else +#endif + { +#ifdef _SC_OPEN_MAX + max = sysconf (_SC_OPEN_MAX); +#else + /* Whoops. */ + return 0; +#endif /* _SC_OPEN_MAX */ + } + + for (fd = 0; fd < max; ++fd) + { + struct stat sb; + int result; + + /* Only call FUNC for open fds. */ + if (fstat (fd, &sb) == -1) + continue; + + result = func (arg, fd); + if (result != 0) + return result; + } + + return 0; + } +} + +#endif /* HAVE_FDWALK */ + + + +/* A vector holding all the fds open when notice_open_fds was called. We + don't use a hashtab because we don't expect there to be many open fds. */ + +static std::vector open_fds; + +/* An fdwalk callback function used by notice_open_fds. It puts the + given file descriptor into the vec. */ + +static int +do_mark_open_fd (void *ignore, int fd) +{ + open_fds.push_back (fd); + return 0; +} + +/* See filestuff.h. */ + +void +notice_open_fds (void) +{ + fdwalk (do_mark_open_fd, NULL); +} + +/* See filestuff.h. */ + +void +mark_fd_no_cloexec (int fd) +{ + do_mark_open_fd (NULL, fd); +} + +/* See filestuff.h. */ + +void +unmark_fd_no_cloexec (int fd) +{ + auto it = std::remove (open_fds.begin (), open_fds.end (), fd); + + if (it != open_fds.end ()) + open_fds.erase (it); + else + gdb_assert_not_reached (_("fd not found in open_fds")); +} + +/* Helper function for close_most_fds that closes the file descriptor + if appropriate. */ + +static int +do_close (void *ignore, int fd) +{ + for (int val : open_fds) + { + if (fd == val) + { + /* Keep this one open. */ + return 0; + } + } + + close (fd); + return 0; +} + +/* See filestuff.h. */ + +void +close_most_fds (void) +{ + fdwalk (do_close, NULL); +} + + + +/* This is a tri-state flag. When zero it means we haven't yet tried + O_CLOEXEC. When positive it means that O_CLOEXEC works on this + host. When negative, it means that O_CLOEXEC doesn't work. We + track this state because, while gdb might have been compiled + against a libc that supplies O_CLOEXEC, there is no guarantee that + the kernel supports it. */ + +static int trust_o_cloexec; + +/* Mark FD as close-on-exec, ignoring errors. Update + TRUST_O_CLOEXEC. */ + +static void +mark_cloexec (int fd) +{ +#ifdef HAVE_F_GETFD + int old = fcntl (fd, F_GETFD, 0); + + if (old != -1) + { + fcntl (fd, F_SETFD, old | FD_CLOEXEC); + + if (trust_o_cloexec == 0) + { + if ((old & FD_CLOEXEC) != 0) + trust_o_cloexec = 1; + else + trust_o_cloexec = -1; + } + } +#endif /* HAVE_F_GETFD */ +} + +/* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */ + +static void +maybe_mark_cloexec (int fd) +{ + if (trust_o_cloexec <= 0) + mark_cloexec (fd); +} + +#ifdef HAVE_SOCKETS + +/* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */ + +static void +socket_mark_cloexec (int fd) +{ + if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0) + mark_cloexec (fd); +} + +#endif + + + +/* See filestuff.h. */ + +int +gdb_open_cloexec (const char *filename, int flags, unsigned long mode) +{ + int fd = open (filename, flags | O_CLOEXEC, mode); + + if (fd >= 0) + maybe_mark_cloexec (fd); + + return fd; +} + +/* See filestuff.h. */ + +gdb_file_up +gdb_fopen_cloexec (const char *filename, const char *opentype) +{ + FILE *result; + /* Probe for "e" support once. But, if we can tell the operating + system doesn't know about close on exec mode "e" without probing, + skip it. E.g., the Windows runtime issues an "Invalid parameter + passed to C runtime function" OutputDebugString warning for + unknown modes. Assume that if O_CLOEXEC is zero, then "e" isn't + supported. On MinGW, O_CLOEXEC is an alias of O_NOINHERIT, and + "e" isn't supported. */ + static int fopen_e_ever_failed_einval = + O_CLOEXEC == 0 || O_CLOEXEC == O_NOINHERIT; + + if (!fopen_e_ever_failed_einval) + { + char *copy; + + copy = (char *) alloca (strlen (opentype) + 2); + strcpy (copy, opentype); + /* This is a glibc extension but we try it unconditionally on + this path. */ + strcat (copy, "e"); + result = fopen (filename, copy); + + if (result == NULL && errno == EINVAL) + { + result = fopen (filename, opentype); + if (result != NULL) + fopen_e_ever_failed_einval = 1; + } + } + else + result = fopen (filename, opentype); + + if (result != NULL) + maybe_mark_cloexec (fileno (result)); + + return gdb_file_up (result); +} + +#ifdef HAVE_SOCKETS +/* See filestuff.h. */ + +int +gdb_socketpair_cloexec (int domain, int style, int protocol, + int filedes[2]) +{ +#ifdef HAVE_SOCKETPAIR + int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes); + + if (result != -1) + { + socket_mark_cloexec (filedes[0]); + socket_mark_cloexec (filedes[1]); + } + + return result; +#else + gdb_assert_not_reached (_("socketpair not available on this host")); +#endif +} + +/* See filestuff.h. */ + +int +gdb_socket_cloexec (int domain, int style, int protocol) +{ + int result = socket (domain, style | SOCK_CLOEXEC, protocol); + + if (result != -1) + socket_mark_cloexec (result); + + return result; +} +#endif + +/* See filestuff.h. */ + +int +gdb_pipe_cloexec (int filedes[2]) +{ + int result; + +#ifdef HAVE_PIPE2 + result = pipe2 (filedes, O_CLOEXEC); + if (result != -1) + { + maybe_mark_cloexec (filedes[0]); + maybe_mark_cloexec (filedes[1]); + } +#else +#ifdef HAVE_PIPE + result = pipe (filedes); + if (result != -1) + { + mark_cloexec (filedes[0]); + mark_cloexec (filedes[1]); + } +#else /* HAVE_PIPE */ + gdb_assert_not_reached (_("pipe not available on this host")); +#endif /* HAVE_PIPE */ +#endif /* HAVE_PIPE2 */ + + return result; +} + +/* See gdbsupport/filestuff.h. */ + +bool +is_regular_file (const char *name, int *errno_ptr) +{ + struct stat st; + const int status = stat (name, &st); + + /* Stat should never fail except when the file does not exist. + If stat fails, analyze the source of error and return true + unless the file does not exist, to avoid returning false results + on obscure systems where stat does not work as expected. */ + + if (status != 0) + { + if (errno != ENOENT) + return true; + *errno_ptr = ENOENT; + return false; + } + + if (S_ISREG (st.st_mode)) + return true; + + if (S_ISDIR (st.st_mode)) + *errno_ptr = EISDIR; + else + *errno_ptr = EINVAL; + return false; +} + +/* See gdbsupport/filestuff.h. */ + +bool +mkdir_recursive (const char *dir) +{ + auto holder = make_unique_xstrdup (dir); + char * const start = holder.get (); + char *component_start = start; + char *component_end = start; + + while (1) + { + /* Find the beginning of the next component. */ + while (*component_start == '/') + component_start++; + + /* Are we done? */ + if (*component_start == '\0') + return true; + + /* Find the slash or null-terminator after this component. */ + component_end = component_start; + while (*component_end != '/' && *component_end != '\0') + component_end++; + + /* Temporarily replace the slash with a null terminator, so we can create + the directory up to this component. */ + char saved_char = *component_end; + *component_end = '\0'; + + /* If we get EEXIST and the existing path is a directory, then we're + happy. If it exists, but it's a regular file and this is not the last + component, we'll fail at the next component. If this is the last + component, the caller will fail with ENOTDIR when trying to + open/create a file under that path. */ + if (mkdir (start, 0700) != 0) + if (errno != EEXIST) + return false; + + /* Restore the overwritten char. */ + *component_end = saved_char; + component_start = component_end; + } +} diff --git a/gdbsupport/format.c b/gdbsupport/format.c deleted file mode 100644 index b05ccf6..0000000 --- a/gdbsupport/format.c +++ /dev/null @@ -1,412 +0,0 @@ -/* Parse a printf-style format string. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "format.h" - -format_pieces::format_pieces (const char **arg, bool gdb_extensions) -{ - const char *s; - const char *string; - const char *prev_start; - const char *percent_loc; - char *sub_start, *current_substring; - enum argclass this_argclass; - - s = *arg; - - if (gdb_extensions) - { - string = *arg; - *arg += strlen (*arg); - } - else - { - /* Parse the format-control string and copy it into the string STRING, - processing some kinds of escape sequence. */ - - char *f = (char *) alloca (strlen (s) + 1); - string = f; - - while ((gdb_extensions || *s != '"') && *s != '\0') - { - int c = *s++; - switch (c) - { - case '\0': - continue; - - case '\\': - switch (c = *s++) - { - case '\\': - *f++ = '\\'; - break; - case 'a': - *f++ = '\a'; - break; - case 'b': - *f++ = '\b'; - break; - case 'e': - *f++ = '\e'; - break; - case 'f': - *f++ = '\f'; - break; - case 'n': - *f++ = '\n'; - break; - case 'r': - *f++ = '\r'; - break; - case 't': - *f++ = '\t'; - break; - case 'v': - *f++ = '\v'; - break; - case '"': - *f++ = '"'; - break; - default: - /* ??? TODO: handle other escape sequences. */ - error (_("Unrecognized escape character \\%c in format string."), - c); - } - break; - - default: - *f++ = c; - } - } - - /* Terminate our escape-processed copy. */ - *f++ = '\0'; - - /* Whether the format string ended with double-quote or zero, we're - done with it; it's up to callers to complain about syntax. */ - *arg = s; - } - - /* Need extra space for the '\0's. Doubling the size is sufficient. */ - - current_substring = (char *) xmalloc (strlen (string) * 2 + 1000); - m_storage.reset (current_substring); - - /* Now scan the string for %-specs and see what kinds of args they want. - argclass classifies the %-specs so we can give printf-type functions - something of the right size. */ - - const char *f = string; - prev_start = string; - while (*f) - if (*f++ == '%') - { - int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0; - int seen_space = 0, seen_plus = 0; - int seen_big_l = 0, seen_h = 0, seen_big_h = 0; - int seen_big_d = 0, seen_double_big_d = 0; - int seen_size_t = 0; - int bad = 0; - int n_int_args = 0; - bool seen_i64 = false; - - /* Skip over "%%", it will become part of a literal piece. */ - if (*f == '%') - { - f++; - continue; - } - - sub_start = current_substring; - - strncpy (current_substring, prev_start, f - 1 - prev_start); - current_substring += f - 1 - prev_start; - *current_substring++ = '\0'; - - if (*sub_start != '\0') - m_pieces.emplace_back (sub_start, literal_piece, 0); - - percent_loc = f - 1; - - /* Check the validity of the format specifier, and work - out what argument it expects. We only accept C89 - format strings, with the exception of long long (which - we autoconf for). */ - - /* The first part of a format specifier is a set of flag - characters. */ - while (*f != '\0' && strchr ("0-+ #", *f)) - { - if (*f == '#') - seen_hash = 1; - else if (*f == '0') - seen_zero = 1; - else if (*f == ' ') - seen_space = 1; - else if (*f == '+') - seen_plus = 1; - f++; - } - - /* The next part of a format specifier is a width. */ - if (gdb_extensions && *f == '*') - { - ++f; - ++n_int_args; - } - else - { - while (*f != '\0' && strchr ("0123456789", *f)) - f++; - } - - /* The next part of a format specifier is a precision. */ - if (*f == '.') - { - seen_prec = 1; - f++; - if (gdb_extensions && *f == '*') - { - ++f; - ++n_int_args; - } - else - { - while (*f != '\0' && strchr ("0123456789", *f)) - f++; - } - } - - /* The next part of a format specifier is a length modifier. */ - switch (*f) - { - case 'h': - seen_h = 1; - f++; - break; - case 'l': - f++; - lcount++; - if (*f == 'l') - { - f++; - lcount++; - } - break; - case 'L': - seen_big_l = 1; - f++; - break; - case 'H': - /* Decimal32 modifier. */ - seen_big_h = 1; - f++; - break; - case 'D': - /* Decimal64 and Decimal128 modifiers. */ - f++; - - /* Check for a Decimal128. */ - if (*f == 'D') - { - f++; - seen_double_big_d = 1; - } - else - seen_big_d = 1; - break; - case 'z': - /* For size_t or ssize_t. */ - seen_size_t = 1; - f++; - break; - case 'I': - /* Support the Windows '%I64' extension, because an - earlier call to format_pieces might have converted %lld - to %I64d. */ - if (f[1] == '6' && f[2] == '4') - { - f += 3; - lcount = 2; - seen_i64 = true; - } - break; - } - - switch (*f) - { - case 'u': - if (seen_hash) - bad = 1; - /* FALLTHROUGH */ - - case 'o': - case 'x': - case 'X': - if (seen_space || seen_plus) - bad = 1; - /* FALLTHROUGH */ - - case 'd': - case 'i': - if (seen_size_t) - this_argclass = size_t_arg; - else if (lcount == 0) - this_argclass = int_arg; - else if (lcount == 1) - this_argclass = long_arg; - else - this_argclass = long_long_arg; - - if (seen_big_l) - bad = 1; - break; - - case 'c': - this_argclass = lcount == 0 ? int_arg : wide_char_arg; - if (lcount > 1 || seen_h || seen_big_l) - bad = 1; - if (seen_prec || seen_zero || seen_space || seen_plus) - bad = 1; - break; - - case 'p': - this_argclass = ptr_arg; - if (lcount || seen_h || seen_big_l) - bad = 1; - if (seen_prec) - bad = 1; - if (seen_hash || seen_zero || seen_space || seen_plus) - bad = 1; - - if (gdb_extensions) - { - switch (f[1]) - { - case 's': - case 'F': - case '[': - case ']': - f++; - break; - } - } - - break; - - case 's': - this_argclass = lcount == 0 ? string_arg : wide_string_arg; - if (lcount > 1 || seen_h || seen_big_l) - bad = 1; - if (seen_zero || seen_space || seen_plus) - bad = 1; - break; - - case 'e': - case 'f': - case 'g': - case 'E': - case 'G': - if (seen_double_big_d) - this_argclass = dec128float_arg; - else if (seen_big_d) - this_argclass = dec64float_arg; - else if (seen_big_h) - this_argclass = dec32float_arg; - else if (seen_big_l) - this_argclass = long_double_arg; - else - this_argclass = double_arg; - - if (lcount || seen_h) - bad = 1; - break; - - case '*': - error (_("`*' not supported for precision or width in printf")); - - case 'n': - error (_("Format specifier `n' not supported in printf")); - - case '\0': - error (_("Incomplete format specifier at end of format string")); - - default: - error (_("Unrecognized format specifier '%c' in printf"), *f); - } - - if (bad) - error (_("Inappropriate modifiers to " - "format specifier '%c' in printf"), - *f); - - f++; - - sub_start = current_substring; - - if (lcount > 1 && !seen_i64 && USE_PRINTF_I64) - { - /* Windows' printf does support long long, but not the usual way. - Convert %lld to %I64d. */ - int length_before_ll = f - percent_loc - 1 - lcount; - - strncpy (current_substring, percent_loc, length_before_ll); - strcpy (current_substring + length_before_ll, "I64"); - current_substring[length_before_ll + 3] = - percent_loc[length_before_ll + lcount]; - current_substring += length_before_ll + 4; - } - else if (this_argclass == wide_string_arg - || this_argclass == wide_char_arg) - { - /* Convert %ls or %lc to %s. */ - int length_before_ls = f - percent_loc - 2; - - strncpy (current_substring, percent_loc, length_before_ls); - strcpy (current_substring + length_before_ls, "s"); - current_substring += length_before_ls + 2; - } - else - { - strncpy (current_substring, percent_loc, f - percent_loc); - current_substring += f - percent_loc; - } - - *current_substring++ = '\0'; - - prev_start = f; - - m_pieces.emplace_back (sub_start, this_argclass, n_int_args); - } - - /* Record the remainder of the string. */ - - if (f > prev_start) - { - sub_start = current_substring; - - strncpy (current_substring, prev_start, f - prev_start); - current_substring += f - prev_start; - *current_substring++ = '\0'; - - m_pieces.emplace_back (sub_start, literal_piece, 0); - } -} diff --git a/gdbsupport/format.cc b/gdbsupport/format.cc new file mode 100644 index 0000000..b05ccf6 --- /dev/null +++ b/gdbsupport/format.cc @@ -0,0 +1,412 @@ +/* Parse a printf-style format string. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "format.h" + +format_pieces::format_pieces (const char **arg, bool gdb_extensions) +{ + const char *s; + const char *string; + const char *prev_start; + const char *percent_loc; + char *sub_start, *current_substring; + enum argclass this_argclass; + + s = *arg; + + if (gdb_extensions) + { + string = *arg; + *arg += strlen (*arg); + } + else + { + /* Parse the format-control string and copy it into the string STRING, + processing some kinds of escape sequence. */ + + char *f = (char *) alloca (strlen (s) + 1); + string = f; + + while ((gdb_extensions || *s != '"') && *s != '\0') + { + int c = *s++; + switch (c) + { + case '\0': + continue; + + case '\\': + switch (c = *s++) + { + case '\\': + *f++ = '\\'; + break; + case 'a': + *f++ = '\a'; + break; + case 'b': + *f++ = '\b'; + break; + case 'e': + *f++ = '\e'; + break; + case 'f': + *f++ = '\f'; + break; + case 'n': + *f++ = '\n'; + break; + case 'r': + *f++ = '\r'; + break; + case 't': + *f++ = '\t'; + break; + case 'v': + *f++ = '\v'; + break; + case '"': + *f++ = '"'; + break; + default: + /* ??? TODO: handle other escape sequences. */ + error (_("Unrecognized escape character \\%c in format string."), + c); + } + break; + + default: + *f++ = c; + } + } + + /* Terminate our escape-processed copy. */ + *f++ = '\0'; + + /* Whether the format string ended with double-quote or zero, we're + done with it; it's up to callers to complain about syntax. */ + *arg = s; + } + + /* Need extra space for the '\0's. Doubling the size is sufficient. */ + + current_substring = (char *) xmalloc (strlen (string) * 2 + 1000); + m_storage.reset (current_substring); + + /* Now scan the string for %-specs and see what kinds of args they want. + argclass classifies the %-specs so we can give printf-type functions + something of the right size. */ + + const char *f = string; + prev_start = string; + while (*f) + if (*f++ == '%') + { + int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0; + int seen_space = 0, seen_plus = 0; + int seen_big_l = 0, seen_h = 0, seen_big_h = 0; + int seen_big_d = 0, seen_double_big_d = 0; + int seen_size_t = 0; + int bad = 0; + int n_int_args = 0; + bool seen_i64 = false; + + /* Skip over "%%", it will become part of a literal piece. */ + if (*f == '%') + { + f++; + continue; + } + + sub_start = current_substring; + + strncpy (current_substring, prev_start, f - 1 - prev_start); + current_substring += f - 1 - prev_start; + *current_substring++ = '\0'; + + if (*sub_start != '\0') + m_pieces.emplace_back (sub_start, literal_piece, 0); + + percent_loc = f - 1; + + /* Check the validity of the format specifier, and work + out what argument it expects. We only accept C89 + format strings, with the exception of long long (which + we autoconf for). */ + + /* The first part of a format specifier is a set of flag + characters. */ + while (*f != '\0' && strchr ("0-+ #", *f)) + { + if (*f == '#') + seen_hash = 1; + else if (*f == '0') + seen_zero = 1; + else if (*f == ' ') + seen_space = 1; + else if (*f == '+') + seen_plus = 1; + f++; + } + + /* The next part of a format specifier is a width. */ + if (gdb_extensions && *f == '*') + { + ++f; + ++n_int_args; + } + else + { + while (*f != '\0' && strchr ("0123456789", *f)) + f++; + } + + /* The next part of a format specifier is a precision. */ + if (*f == '.') + { + seen_prec = 1; + f++; + if (gdb_extensions && *f == '*') + { + ++f; + ++n_int_args; + } + else + { + while (*f != '\0' && strchr ("0123456789", *f)) + f++; + } + } + + /* The next part of a format specifier is a length modifier. */ + switch (*f) + { + case 'h': + seen_h = 1; + f++; + break; + case 'l': + f++; + lcount++; + if (*f == 'l') + { + f++; + lcount++; + } + break; + case 'L': + seen_big_l = 1; + f++; + break; + case 'H': + /* Decimal32 modifier. */ + seen_big_h = 1; + f++; + break; + case 'D': + /* Decimal64 and Decimal128 modifiers. */ + f++; + + /* Check for a Decimal128. */ + if (*f == 'D') + { + f++; + seen_double_big_d = 1; + } + else + seen_big_d = 1; + break; + case 'z': + /* For size_t or ssize_t. */ + seen_size_t = 1; + f++; + break; + case 'I': + /* Support the Windows '%I64' extension, because an + earlier call to format_pieces might have converted %lld + to %I64d. */ + if (f[1] == '6' && f[2] == '4') + { + f += 3; + lcount = 2; + seen_i64 = true; + } + break; + } + + switch (*f) + { + case 'u': + if (seen_hash) + bad = 1; + /* FALLTHROUGH */ + + case 'o': + case 'x': + case 'X': + if (seen_space || seen_plus) + bad = 1; + /* FALLTHROUGH */ + + case 'd': + case 'i': + if (seen_size_t) + this_argclass = size_t_arg; + else if (lcount == 0) + this_argclass = int_arg; + else if (lcount == 1) + this_argclass = long_arg; + else + this_argclass = long_long_arg; + + if (seen_big_l) + bad = 1; + break; + + case 'c': + this_argclass = lcount == 0 ? int_arg : wide_char_arg; + if (lcount > 1 || seen_h || seen_big_l) + bad = 1; + if (seen_prec || seen_zero || seen_space || seen_plus) + bad = 1; + break; + + case 'p': + this_argclass = ptr_arg; + if (lcount || seen_h || seen_big_l) + bad = 1; + if (seen_prec) + bad = 1; + if (seen_hash || seen_zero || seen_space || seen_plus) + bad = 1; + + if (gdb_extensions) + { + switch (f[1]) + { + case 's': + case 'F': + case '[': + case ']': + f++; + break; + } + } + + break; + + case 's': + this_argclass = lcount == 0 ? string_arg : wide_string_arg; + if (lcount > 1 || seen_h || seen_big_l) + bad = 1; + if (seen_zero || seen_space || seen_plus) + bad = 1; + break; + + case 'e': + case 'f': + case 'g': + case 'E': + case 'G': + if (seen_double_big_d) + this_argclass = dec128float_arg; + else if (seen_big_d) + this_argclass = dec64float_arg; + else if (seen_big_h) + this_argclass = dec32float_arg; + else if (seen_big_l) + this_argclass = long_double_arg; + else + this_argclass = double_arg; + + if (lcount || seen_h) + bad = 1; + break; + + case '*': + error (_("`*' not supported for precision or width in printf")); + + case 'n': + error (_("Format specifier `n' not supported in printf")); + + case '\0': + error (_("Incomplete format specifier at end of format string")); + + default: + error (_("Unrecognized format specifier '%c' in printf"), *f); + } + + if (bad) + error (_("Inappropriate modifiers to " + "format specifier '%c' in printf"), + *f); + + f++; + + sub_start = current_substring; + + if (lcount > 1 && !seen_i64 && USE_PRINTF_I64) + { + /* Windows' printf does support long long, but not the usual way. + Convert %lld to %I64d. */ + int length_before_ll = f - percent_loc - 1 - lcount; + + strncpy (current_substring, percent_loc, length_before_ll); + strcpy (current_substring + length_before_ll, "I64"); + current_substring[length_before_ll + 3] = + percent_loc[length_before_ll + lcount]; + current_substring += length_before_ll + 4; + } + else if (this_argclass == wide_string_arg + || this_argclass == wide_char_arg) + { + /* Convert %ls or %lc to %s. */ + int length_before_ls = f - percent_loc - 2; + + strncpy (current_substring, percent_loc, length_before_ls); + strcpy (current_substring + length_before_ls, "s"); + current_substring += length_before_ls + 2; + } + else + { + strncpy (current_substring, percent_loc, f - percent_loc); + current_substring += f - percent_loc; + } + + *current_substring++ = '\0'; + + prev_start = f; + + m_pieces.emplace_back (sub_start, this_argclass, n_int_args); + } + + /* Record the remainder of the string. */ + + if (f > prev_start) + { + sub_start = current_substring; + + strncpy (current_substring, prev_start, f - prev_start); + current_substring += f - prev_start; + *current_substring++ = '\0'; + + m_pieces.emplace_back (sub_start, literal_piece, 0); + } +} diff --git a/gdbsupport/gdb-dlfcn.c b/gdbsupport/gdb-dlfcn.c deleted file mode 100644 index 1a755bd..0000000 --- a/gdbsupport/gdb-dlfcn.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Platform independent shared object routines for GDB. - - Copyright (C) 2011-2020 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 . */ - -#include "common-defs.h" -#include "gdb-dlfcn.h" - -#ifdef HAVE_DLFCN_H -#include -#elif __MINGW32__ -#include -#else -/* Unsupported configuration. */ -#define NO_SHARED_LIB -#endif - -#ifdef NO_SHARED_LIB - -gdb_dlhandle_up -gdb_dlopen (const char *filename) -{ - gdb_assert_not_reached ("gdb_dlopen should not be called on this platform."); -} - -void * -gdb_dlsym (const gdb_dlhandle_up &handle, const char *symbol) -{ - gdb_assert_not_reached ("gdb_dlsym should not be called on this platform."); -} - -void -dlclose_deleter::operator() (void *handle) const -{ - gdb_assert_not_reached ("gdb_dlclose should not be called on this platform."); -} - -int -is_dl_available (void) -{ - return 0; -} - -#else /* NO_SHARED_LIB */ - -gdb_dlhandle_up -gdb_dlopen (const char *filename) -{ - void *result; -#ifdef HAVE_DLFCN_H - result = dlopen (filename, RTLD_NOW); -#elif __MINGW32__ - result = (void *) LoadLibrary (filename); -#endif - if (result != NULL) - return gdb_dlhandle_up (result); - -#ifdef HAVE_DLFCN_H - error (_("Could not load %s: %s"), filename, dlerror()); -#else - { - LPVOID buffer; - DWORD dw; - - dw = GetLastError(); - - FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &buffer, - 0, NULL); - - error (_("Could not load %s: %s"), filename, (char *) buffer); - } -#endif -} - -void * -gdb_dlsym (const gdb_dlhandle_up &handle, const char *symbol) -{ -#ifdef HAVE_DLFCN_H - return dlsym (handle.get (), symbol); -#elif __MINGW32__ - return (void *) GetProcAddress ((HMODULE) handle.get (), symbol); -#endif -} - -void -dlclose_deleter::operator() (void *handle) const -{ -#ifdef HAVE_DLFCN_H - dlclose (handle); -#elif __MINGW32__ - FreeLibrary ((HMODULE) handle); -#endif -} - -int -is_dl_available (void) -{ - return 1; -} - -#endif /* NO_SHARED_LIB */ diff --git a/gdbsupport/gdb-dlfcn.cc b/gdbsupport/gdb-dlfcn.cc new file mode 100644 index 0000000..1a755bd --- /dev/null +++ b/gdbsupport/gdb-dlfcn.cc @@ -0,0 +1,118 @@ +/* Platform independent shared object routines for GDB. + + Copyright (C) 2011-2020 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 . */ + +#include "common-defs.h" +#include "gdb-dlfcn.h" + +#ifdef HAVE_DLFCN_H +#include +#elif __MINGW32__ +#include +#else +/* Unsupported configuration. */ +#define NO_SHARED_LIB +#endif + +#ifdef NO_SHARED_LIB + +gdb_dlhandle_up +gdb_dlopen (const char *filename) +{ + gdb_assert_not_reached ("gdb_dlopen should not be called on this platform."); +} + +void * +gdb_dlsym (const gdb_dlhandle_up &handle, const char *symbol) +{ + gdb_assert_not_reached ("gdb_dlsym should not be called on this platform."); +} + +void +dlclose_deleter::operator() (void *handle) const +{ + gdb_assert_not_reached ("gdb_dlclose should not be called on this platform."); +} + +int +is_dl_available (void) +{ + return 0; +} + +#else /* NO_SHARED_LIB */ + +gdb_dlhandle_up +gdb_dlopen (const char *filename) +{ + void *result; +#ifdef HAVE_DLFCN_H + result = dlopen (filename, RTLD_NOW); +#elif __MINGW32__ + result = (void *) LoadLibrary (filename); +#endif + if (result != NULL) + return gdb_dlhandle_up (result); + +#ifdef HAVE_DLFCN_H + error (_("Could not load %s: %s"), filename, dlerror()); +#else + { + LPVOID buffer; + DWORD dw; + + dw = GetLastError(); + + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buffer, + 0, NULL); + + error (_("Could not load %s: %s"), filename, (char *) buffer); + } +#endif +} + +void * +gdb_dlsym (const gdb_dlhandle_up &handle, const char *symbol) +{ +#ifdef HAVE_DLFCN_H + return dlsym (handle.get (), symbol); +#elif __MINGW32__ + return (void *) GetProcAddress ((HMODULE) handle.get (), symbol); +#endif +} + +void +dlclose_deleter::operator() (void *handle) const +{ +#ifdef HAVE_DLFCN_H + dlclose (handle); +#elif __MINGW32__ + FreeLibrary ((HMODULE) handle); +#endif +} + +int +is_dl_available (void) +{ + return 1; +} + +#endif /* NO_SHARED_LIB */ diff --git a/gdbsupport/gdb_tilde_expand.c b/gdbsupport/gdb_tilde_expand.c deleted file mode 100644 index 6671629..0000000 --- a/gdbsupport/gdb_tilde_expand.c +++ /dev/null @@ -1,95 +0,0 @@ -/* Perform tilde expansion on paths for GDB and gdbserver. - - Copyright (C) 2017-2020 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 . */ - -#include "common-defs.h" -#include "gdb_tilde_expand.h" -#include - -/* RAII-style class wrapping "glob". */ - -class gdb_glob -{ -public: - /* Construct a "gdb_glob" object by calling "glob" with the provided - parameters. This function can throw if "glob" fails. */ - gdb_glob (const char *pattern, int flags, - int (*errfunc) (const char *epath, int eerrno)) - { - int ret = glob (pattern, flags, errfunc, &m_glob); - - if (ret != 0) - { - if (ret == GLOB_NOMATCH) - error (_("Could not find a match for '%s'."), pattern); - else - error (_("glob could not process pattern '%s'."), - pattern); - } - } - - /* Destroy the object and free M_GLOB. */ - ~gdb_glob () - { - globfree (&m_glob); - } - - /* Return the GL_PATHC component of M_GLOB. */ - int pathc () const - { - return m_glob.gl_pathc; - } - - /* Return the GL_PATHV component of M_GLOB. */ - char **pathv () const - { - return m_glob.gl_pathv; - } - -private: - /* The actual glob object we're dealing with. */ - glob_t m_glob; -}; - -/* See gdbsupport/gdb_tilde_expand.h. */ - -std::string -gdb_tilde_expand (const char *dir) -{ - gdb_glob glob (dir, GLOB_TILDE_CHECK, NULL); - - gdb_assert (glob.pathc () > 0); - /* "glob" may return more than one match to the path provided by the - user, but we are only interested in the first match. */ - std::string expanded_dir = glob.pathv ()[0]; - - return expanded_dir; -} - -/* See gdbsupport/gdb_tilde_expand.h. */ - -gdb::unique_xmalloc_ptr -gdb_tilde_expand_up (const char *dir) -{ - gdb_glob glob (dir, GLOB_TILDE_CHECK, NULL); - - gdb_assert (glob.pathc () > 0); - /* "glob" may return more than one match to the path provided by the - user, but we are only interested in the first match. */ - return make_unique_xstrdup (glob.pathv ()[0]); -} diff --git a/gdbsupport/gdb_tilde_expand.cc b/gdbsupport/gdb_tilde_expand.cc new file mode 100644 index 0000000..6671629 --- /dev/null +++ b/gdbsupport/gdb_tilde_expand.cc @@ -0,0 +1,95 @@ +/* Perform tilde expansion on paths for GDB and gdbserver. + + Copyright (C) 2017-2020 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 . */ + +#include "common-defs.h" +#include "gdb_tilde_expand.h" +#include + +/* RAII-style class wrapping "glob". */ + +class gdb_glob +{ +public: + /* Construct a "gdb_glob" object by calling "glob" with the provided + parameters. This function can throw if "glob" fails. */ + gdb_glob (const char *pattern, int flags, + int (*errfunc) (const char *epath, int eerrno)) + { + int ret = glob (pattern, flags, errfunc, &m_glob); + + if (ret != 0) + { + if (ret == GLOB_NOMATCH) + error (_("Could not find a match for '%s'."), pattern); + else + error (_("glob could not process pattern '%s'."), + pattern); + } + } + + /* Destroy the object and free M_GLOB. */ + ~gdb_glob () + { + globfree (&m_glob); + } + + /* Return the GL_PATHC component of M_GLOB. */ + int pathc () const + { + return m_glob.gl_pathc; + } + + /* Return the GL_PATHV component of M_GLOB. */ + char **pathv () const + { + return m_glob.gl_pathv; + } + +private: + /* The actual glob object we're dealing with. */ + glob_t m_glob; +}; + +/* See gdbsupport/gdb_tilde_expand.h. */ + +std::string +gdb_tilde_expand (const char *dir) +{ + gdb_glob glob (dir, GLOB_TILDE_CHECK, NULL); + + gdb_assert (glob.pathc () > 0); + /* "glob" may return more than one match to the path provided by the + user, but we are only interested in the first match. */ + std::string expanded_dir = glob.pathv ()[0]; + + return expanded_dir; +} + +/* See gdbsupport/gdb_tilde_expand.h. */ + +gdb::unique_xmalloc_ptr +gdb_tilde_expand_up (const char *dir) +{ + gdb_glob glob (dir, GLOB_TILDE_CHECK, NULL); + + gdb_assert (glob.pathc () > 0); + /* "glob" may return more than one match to the path provided by the + user, but we are only interested in the first match. */ + return make_unique_xstrdup (glob.pathv ()[0]); +} diff --git a/gdbsupport/gdb_vecs.c b/gdbsupport/gdb_vecs.c deleted file mode 100644 index bb81396..0000000 --- a/gdbsupport/gdb_vecs.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Some commonly-used VEC types. - - Copyright (C) 2012-2020 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 . */ - -#include "common-defs.h" -#include "gdb_vecs.h" -#include "host-defs.h" - -/* Worker function to split character delimiter separated string of fields - STR into a char pointer vector. */ - -static void -delim_string_to_char_ptr_vec_append - (std::vector> *vecp, const char *str, - char delimiter) -{ - do - { - size_t this_len; - const char *next_field; - char *this_field; - - next_field = strchr (str, delimiter); - if (next_field == NULL) - this_len = strlen (str); - else - { - this_len = next_field - str; - next_field++; - } - - this_field = (char *) xmalloc (this_len + 1); - memcpy (this_field, str, this_len); - this_field[this_len] = '\0'; - vecp->emplace_back (this_field); - - str = next_field; - } - while (str != NULL); -} - -/* See gdb_vecs.h. */ - -std::vector> -delim_string_to_char_ptr_vec (const char *str, char delimiter) -{ - std::vector> retval; - - delim_string_to_char_ptr_vec_append (&retval, str, delimiter); - - return retval; -} - -/* See gdb_vecs.h. */ - -void -dirnames_to_char_ptr_vec_append - (std::vector> *vecp, const char *dirnames) -{ - delim_string_to_char_ptr_vec_append (vecp, dirnames, DIRNAME_SEPARATOR); -} - -/* See gdb_vecs.h. */ - -std::vector> -dirnames_to_char_ptr_vec (const char *dirnames) -{ - std::vector> retval; - - dirnames_to_char_ptr_vec_append (&retval, dirnames); - - return retval; -} diff --git a/gdbsupport/gdb_vecs.cc b/gdbsupport/gdb_vecs.cc new file mode 100644 index 0000000..bb81396 --- /dev/null +++ b/gdbsupport/gdb_vecs.cc @@ -0,0 +1,88 @@ +/* Some commonly-used VEC types. + + Copyright (C) 2012-2020 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 . */ + +#include "common-defs.h" +#include "gdb_vecs.h" +#include "host-defs.h" + +/* Worker function to split character delimiter separated string of fields + STR into a char pointer vector. */ + +static void +delim_string_to_char_ptr_vec_append + (std::vector> *vecp, const char *str, + char delimiter) +{ + do + { + size_t this_len; + const char *next_field; + char *this_field; + + next_field = strchr (str, delimiter); + if (next_field == NULL) + this_len = strlen (str); + else + { + this_len = next_field - str; + next_field++; + } + + this_field = (char *) xmalloc (this_len + 1); + memcpy (this_field, str, this_len); + this_field[this_len] = '\0'; + vecp->emplace_back (this_field); + + str = next_field; + } + while (str != NULL); +} + +/* See gdb_vecs.h. */ + +std::vector> +delim_string_to_char_ptr_vec (const char *str, char delimiter) +{ + std::vector> retval; + + delim_string_to_char_ptr_vec_append (&retval, str, delimiter); + + return retval; +} + +/* See gdb_vecs.h. */ + +void +dirnames_to_char_ptr_vec_append + (std::vector> *vecp, const char *dirnames) +{ + delim_string_to_char_ptr_vec_append (vecp, dirnames, DIRNAME_SEPARATOR); +} + +/* See gdb_vecs.h. */ + +std::vector> +dirnames_to_char_ptr_vec (const char *dirnames) +{ + std::vector> retval; + + dirnames_to_char_ptr_vec_append (&retval, dirnames); + + return retval; +} diff --git a/gdbsupport/gdb_wait.c b/gdbsupport/gdb_wait.c deleted file mode 100644 index 3213994..0000000 --- a/gdbsupport/gdb_wait.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Support code for standard wait macros in gdb_wait.h. - - Copyright (C) 2019 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 . */ - -#include "common-defs.h" - -#include "gdb_wait.h" - -#ifdef __MINGW32__ - -/* The underlying idea is that when a Windows program is terminated by - a fatal exception, its exit code is the value of that exception, as - defined by the various EXCEPTION_* symbols in the Windows API - headers. We thus emulate WTERMSIG etc. by translating the fatal - exception codes to more-or-less equivalent Posix signals. - - The translation below is not perfect, because a program could - legitimately exit normally with a status whose value happens to - have the high bits set, but that's extremely rare, to say the - least, and it is deemed such a negligibly small probability of - false positives is justified by the utility of reporting the - terminating signal in the "normal" cases. */ - -# include - -# define WIN32_LEAN_AND_MEAN -# include /* for EXCEPTION_* constants */ - -struct xlate_status -{ - /* The exit status (actually, fatal exception code). */ - DWORD status; - - /* The corresponding signal value. */ - int sig; -}; - -int -windows_status_to_termsig (unsigned long status) -{ - static const xlate_status status_xlate_tbl[] = - { - {EXCEPTION_ACCESS_VIOLATION, SIGSEGV}, - {EXCEPTION_IN_PAGE_ERROR, SIGSEGV}, - {EXCEPTION_INVALID_HANDLE, SIGSEGV}, - {EXCEPTION_ILLEGAL_INSTRUCTION, SIGILL}, - {EXCEPTION_NONCONTINUABLE_EXCEPTION, SIGILL}, - {EXCEPTION_ARRAY_BOUNDS_EXCEEDED, SIGSEGV}, - {EXCEPTION_FLT_DENORMAL_OPERAND, SIGFPE}, - {EXCEPTION_FLT_DIVIDE_BY_ZERO, SIGFPE}, - {EXCEPTION_FLT_INEXACT_RESULT, SIGFPE}, - {EXCEPTION_FLT_INVALID_OPERATION, SIGFPE}, - {EXCEPTION_FLT_OVERFLOW, SIGFPE}, - {EXCEPTION_FLT_STACK_CHECK, SIGFPE}, - {EXCEPTION_FLT_UNDERFLOW, SIGFPE}, - {EXCEPTION_INT_DIVIDE_BY_ZERO, SIGFPE}, - {EXCEPTION_INT_OVERFLOW, SIGFPE}, - {EXCEPTION_PRIV_INSTRUCTION, SIGILL}, - {EXCEPTION_STACK_OVERFLOW, SIGSEGV}, - {CONTROL_C_EXIT, SIGTERM} - }; - - for (const xlate_status &x : status_xlate_tbl) - if (x.status == status) - return x.sig; - - return -1; -} - -#endif /* __MINGW32__ */ diff --git a/gdbsupport/gdb_wait.cc b/gdbsupport/gdb_wait.cc new file mode 100644 index 0000000..3213994 --- /dev/null +++ b/gdbsupport/gdb_wait.cc @@ -0,0 +1,85 @@ +/* Support code for standard wait macros in gdb_wait.h. + + Copyright (C) 2019 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 . */ + +#include "common-defs.h" + +#include "gdb_wait.h" + +#ifdef __MINGW32__ + +/* The underlying idea is that when a Windows program is terminated by + a fatal exception, its exit code is the value of that exception, as + defined by the various EXCEPTION_* symbols in the Windows API + headers. We thus emulate WTERMSIG etc. by translating the fatal + exception codes to more-or-less equivalent Posix signals. + + The translation below is not perfect, because a program could + legitimately exit normally with a status whose value happens to + have the high bits set, but that's extremely rare, to say the + least, and it is deemed such a negligibly small probability of + false positives is justified by the utility of reporting the + terminating signal in the "normal" cases. */ + +# include + +# define WIN32_LEAN_AND_MEAN +# include /* for EXCEPTION_* constants */ + +struct xlate_status +{ + /* The exit status (actually, fatal exception code). */ + DWORD status; + + /* The corresponding signal value. */ + int sig; +}; + +int +windows_status_to_termsig (unsigned long status) +{ + static const xlate_status status_xlate_tbl[] = + { + {EXCEPTION_ACCESS_VIOLATION, SIGSEGV}, + {EXCEPTION_IN_PAGE_ERROR, SIGSEGV}, + {EXCEPTION_INVALID_HANDLE, SIGSEGV}, + {EXCEPTION_ILLEGAL_INSTRUCTION, SIGILL}, + {EXCEPTION_NONCONTINUABLE_EXCEPTION, SIGILL}, + {EXCEPTION_ARRAY_BOUNDS_EXCEEDED, SIGSEGV}, + {EXCEPTION_FLT_DENORMAL_OPERAND, SIGFPE}, + {EXCEPTION_FLT_DIVIDE_BY_ZERO, SIGFPE}, + {EXCEPTION_FLT_INEXACT_RESULT, SIGFPE}, + {EXCEPTION_FLT_INVALID_OPERATION, SIGFPE}, + {EXCEPTION_FLT_OVERFLOW, SIGFPE}, + {EXCEPTION_FLT_STACK_CHECK, SIGFPE}, + {EXCEPTION_FLT_UNDERFLOW, SIGFPE}, + {EXCEPTION_INT_DIVIDE_BY_ZERO, SIGFPE}, + {EXCEPTION_INT_OVERFLOW, SIGFPE}, + {EXCEPTION_PRIV_INSTRUCTION, SIGILL}, + {EXCEPTION_STACK_OVERFLOW, SIGSEGV}, + {CONTROL_C_EXIT, SIGTERM} + }; + + for (const xlate_status &x : status_xlate_tbl) + if (x.status == status) + return x.sig; + + return -1; +} + +#endif /* __MINGW32__ */ diff --git a/gdbsupport/job-control.c b/gdbsupport/job-control.c deleted file mode 100644 index 381c5f0..0000000 --- a/gdbsupport/job-control.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Job control and terminal related functions, for GDB and gdbserver - when running under Unix. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "job-control.h" -#ifdef HAVE_TERMIOS_H -#include -#endif -#include - -/* Nonzero if we have job control. */ -int job_control; - -/* Set the process group ID of the inferior. - - Just using job_control only does part of it because setpgid or - setpgrp might not exist on a system without job control. - - For a more clean implementation, in libiberty, put a setpgid which merely - calls setpgrp and a setpgrp which does nothing (any system with job control - will have one or the other). */ - -int -gdb_setpgid () -{ - int retval = 0; - - if (job_control) - { -#ifdef HAVE_SETPGID - /* The call setpgid (0, 0) is supposed to work and mean the same - thing as this, but on Ultrix 4.2A it fails with EPERM (and - setpgid (getpid (), getpid ()) succeeds). */ - retval = setpgid (getpid (), getpid ()); -#else -#ifdef HAVE_SETPGRP -#ifdef SETPGRP_VOID - retval = setpgrp (); -#else - retval = setpgrp (getpid (), getpid ()); -#endif -#endif /* HAVE_SETPGRP */ -#endif /* HAVE_SETPGID */ - } - - return retval; -} - -/* See gdbsupport/common-terminal.h. */ - -void -have_job_control () -{ - /* OK, figure out whether we have job control. If termios is not - available, leave job_control 0. */ -#if defined (HAVE_TERMIOS_H) - /* Do all systems with termios have the POSIX way of identifying job - control? I hope so. */ -#ifdef _POSIX_JOB_CONTROL - job_control = 1; -#else -#ifdef _SC_JOB_CONTROL - job_control = sysconf (_SC_JOB_CONTROL); -#else - job_control = 0; /* Have to assume the worst. */ -#endif /* _SC_JOB_CONTROL */ -#endif /* _POSIX_JOB_CONTROL */ -#endif /* HAVE_TERMIOS_H */ -} diff --git a/gdbsupport/job-control.cc b/gdbsupport/job-control.cc new file mode 100644 index 0000000..381c5f0 --- /dev/null +++ b/gdbsupport/job-control.cc @@ -0,0 +1,86 @@ +/* Job control and terminal related functions, for GDB and gdbserver + when running under Unix. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "job-control.h" +#ifdef HAVE_TERMIOS_H +#include +#endif +#include + +/* Nonzero if we have job control. */ +int job_control; + +/* Set the process group ID of the inferior. + + Just using job_control only does part of it because setpgid or + setpgrp might not exist on a system without job control. + + For a more clean implementation, in libiberty, put a setpgid which merely + calls setpgrp and a setpgrp which does nothing (any system with job control + will have one or the other). */ + +int +gdb_setpgid () +{ + int retval = 0; + + if (job_control) + { +#ifdef HAVE_SETPGID + /* The call setpgid (0, 0) is supposed to work and mean the same + thing as this, but on Ultrix 4.2A it fails with EPERM (and + setpgid (getpid (), getpid ()) succeeds). */ + retval = setpgid (getpid (), getpid ()); +#else +#ifdef HAVE_SETPGRP +#ifdef SETPGRP_VOID + retval = setpgrp (); +#else + retval = setpgrp (getpid (), getpid ()); +#endif +#endif /* HAVE_SETPGRP */ +#endif /* HAVE_SETPGID */ + } + + return retval; +} + +/* See gdbsupport/common-terminal.h. */ + +void +have_job_control () +{ + /* OK, figure out whether we have job control. If termios is not + available, leave job_control 0. */ +#if defined (HAVE_TERMIOS_H) + /* Do all systems with termios have the POSIX way of identifying job + control? I hope so. */ +#ifdef _POSIX_JOB_CONTROL + job_control = 1; +#else +#ifdef _SC_JOB_CONTROL + job_control = sysconf (_SC_JOB_CONTROL); +#else + job_control = 0; /* Have to assume the worst. */ +#endif /* _SC_JOB_CONTROL */ +#endif /* _POSIX_JOB_CONTROL */ +#endif /* HAVE_TERMIOS_H */ +} diff --git a/gdbsupport/netstuff.c b/gdbsupport/netstuff.c deleted file mode 100644 index 1bf8f4b..0000000 --- a/gdbsupport/netstuff.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Operations on network stuff. - Copyright (C) 2018-2020 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 . */ - -#include "common-defs.h" -#include "netstuff.h" -#include - -#ifdef USE_WIN32API -#include -#else -#include -#include -#include -#include -#include -#endif - -/* See gdbsupport/netstuff.h. */ - -scoped_free_addrinfo::~scoped_free_addrinfo () -{ - freeaddrinfo (m_res); -} - -/* See gdbsupport/netstuff.h. */ - -parsed_connection_spec -parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint) -{ - parsed_connection_spec ret; - size_t last_colon_pos = 0; - /* We're dealing with IPv6 if: - - - ai_family is AF_INET6, or - - ai_family is not AF_INET, and - - spec[0] is '[', or - - the number of ':' on spec is greater than 1. */ - bool is_ipv6 = (hint->ai_family == AF_INET6 - || (hint->ai_family != AF_INET - && (spec[0] == '[' - || std::count (spec.begin (), - spec.end (), ':') > 1))); - - if (is_ipv6) - { - if (spec[0] == '[') - { - /* IPv6 addresses can be written as '[ADDR]:PORT', and we - support this notation. */ - size_t close_bracket_pos = spec.find_first_of (']'); - - if (close_bracket_pos == std::string::npos) - error (_("Missing close bracket in hostname '%s'"), - spec.c_str ()); - - hint->ai_family = AF_INET6; - - const char c = spec[close_bracket_pos + 1]; - - if (c == '\0') - last_colon_pos = std::string::npos; - else if (c != ':') - error (_("Invalid cruft after close bracket in '%s'"), - spec.c_str ()); - - /* Erase both '[' and ']'. */ - spec.erase (0, 1); - spec.erase (close_bracket_pos - 1, 1); - } - else if (spec.find_first_of (']') != std::string::npos) - error (_("Missing open bracket in hostname '%s'"), - spec.c_str ()); - } - - if (last_colon_pos == 0) - last_colon_pos = spec.find_last_of (':'); - - /* The length of the hostname part. */ - size_t host_len; - - if (last_colon_pos != std::string::npos) - { - /* The user has provided a port. */ - host_len = last_colon_pos; - ret.port_str = spec.substr (last_colon_pos + 1); - } - else - host_len = spec.size (); - - ret.host_str = spec.substr (0, host_len); - - /* Default hostname is localhost. */ - if (ret.host_str.empty ()) - ret.host_str = "localhost"; - - return ret; -} - -/* See gdbsupport/netstuff.h. */ - -parsed_connection_spec -parse_connection_spec (const char *spec, struct addrinfo *hint) -{ - /* Struct to hold the association between valid prefixes, their - family and socktype. */ - struct host_prefix - { - /* The prefix. */ - const char *prefix; - - /* The 'ai_family'. */ - int family; - - /* The 'ai_socktype'. */ - int socktype; - }; - static const struct host_prefix prefixes[] = - { - { "udp:", AF_UNSPEC, SOCK_DGRAM }, - { "tcp:", AF_UNSPEC, SOCK_STREAM }, - { "udp4:", AF_INET, SOCK_DGRAM }, - { "tcp4:", AF_INET, SOCK_STREAM }, - { "udp6:", AF_INET6, SOCK_DGRAM }, - { "tcp6:", AF_INET6, SOCK_STREAM }, - }; - - for (const host_prefix prefix : prefixes) - if (startswith (spec, prefix.prefix)) - { - spec += strlen (prefix.prefix); - hint->ai_family = prefix.family; - hint->ai_socktype = prefix.socktype; - hint->ai_protocol - = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; - break; - } - - return parse_connection_spec_without_prefix (spec, hint); -} diff --git a/gdbsupport/netstuff.cc b/gdbsupport/netstuff.cc new file mode 100644 index 0000000..1bf8f4b --- /dev/null +++ b/gdbsupport/netstuff.cc @@ -0,0 +1,154 @@ +/* Operations on network stuff. + Copyright (C) 2018-2020 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 . */ + +#include "common-defs.h" +#include "netstuff.h" +#include + +#ifdef USE_WIN32API +#include +#else +#include +#include +#include +#include +#include +#endif + +/* See gdbsupport/netstuff.h. */ + +scoped_free_addrinfo::~scoped_free_addrinfo () +{ + freeaddrinfo (m_res); +} + +/* See gdbsupport/netstuff.h. */ + +parsed_connection_spec +parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint) +{ + parsed_connection_spec ret; + size_t last_colon_pos = 0; + /* We're dealing with IPv6 if: + + - ai_family is AF_INET6, or + - ai_family is not AF_INET, and + - spec[0] is '[', or + - the number of ':' on spec is greater than 1. */ + bool is_ipv6 = (hint->ai_family == AF_INET6 + || (hint->ai_family != AF_INET + && (spec[0] == '[' + || std::count (spec.begin (), + spec.end (), ':') > 1))); + + if (is_ipv6) + { + if (spec[0] == '[') + { + /* IPv6 addresses can be written as '[ADDR]:PORT', and we + support this notation. */ + size_t close_bracket_pos = spec.find_first_of (']'); + + if (close_bracket_pos == std::string::npos) + error (_("Missing close bracket in hostname '%s'"), + spec.c_str ()); + + hint->ai_family = AF_INET6; + + const char c = spec[close_bracket_pos + 1]; + + if (c == '\0') + last_colon_pos = std::string::npos; + else if (c != ':') + error (_("Invalid cruft after close bracket in '%s'"), + spec.c_str ()); + + /* Erase both '[' and ']'. */ + spec.erase (0, 1); + spec.erase (close_bracket_pos - 1, 1); + } + else if (spec.find_first_of (']') != std::string::npos) + error (_("Missing open bracket in hostname '%s'"), + spec.c_str ()); + } + + if (last_colon_pos == 0) + last_colon_pos = spec.find_last_of (':'); + + /* The length of the hostname part. */ + size_t host_len; + + if (last_colon_pos != std::string::npos) + { + /* The user has provided a port. */ + host_len = last_colon_pos; + ret.port_str = spec.substr (last_colon_pos + 1); + } + else + host_len = spec.size (); + + ret.host_str = spec.substr (0, host_len); + + /* Default hostname is localhost. */ + if (ret.host_str.empty ()) + ret.host_str = "localhost"; + + return ret; +} + +/* See gdbsupport/netstuff.h. */ + +parsed_connection_spec +parse_connection_spec (const char *spec, struct addrinfo *hint) +{ + /* Struct to hold the association between valid prefixes, their + family and socktype. */ + struct host_prefix + { + /* The prefix. */ + const char *prefix; + + /* The 'ai_family'. */ + int family; + + /* The 'ai_socktype'. */ + int socktype; + }; + static const struct host_prefix prefixes[] = + { + { "udp:", AF_UNSPEC, SOCK_DGRAM }, + { "tcp:", AF_UNSPEC, SOCK_STREAM }, + { "udp4:", AF_INET, SOCK_DGRAM }, + { "tcp4:", AF_INET, SOCK_STREAM }, + { "udp6:", AF_INET6, SOCK_DGRAM }, + { "tcp6:", AF_INET6, SOCK_STREAM }, + }; + + for (const host_prefix prefix : prefixes) + if (startswith (spec, prefix.prefix)) + { + spec += strlen (prefix.prefix); + hint->ai_family = prefix.family; + hint->ai_socktype = prefix.socktype; + hint->ai_protocol + = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; + break; + } + + return parse_connection_spec_without_prefix (spec, hint); +} diff --git a/gdbsupport/new-op.c b/gdbsupport/new-op.c deleted file mode 100644 index cf2525c..0000000 --- a/gdbsupport/new-op.c +++ /dev/null @@ -1,95 +0,0 @@ -/* Replace operator new/new[], for GDB, the GNU debugger. - - Copyright (C) 2016-2020 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 . */ - -/* GCC does not understand __has_feature. */ -#if !defined(__has_feature) -# define __has_feature(x) 0 -#endif - -#if !__has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) -#include "common-defs.h" -#include "host-defs.h" -#include - -/* Override operator new / operator new[], in order to internal_error - on allocation failure and thus query the user for abort/core - dump/continue, just like xmalloc does. We don't do this from a - new-handler function instead (std::set_new_handler) because we want - to catch allocation errors from within global constructors too. - - Skip overriding if building with -fsanitize=address though. - Address sanitizer wants to override operator new/delete too in - order to detect malloc+delete and new+free mismatches. Our - versions would mask out ASan's, with the result of losing that - useful mismatch detection. - - Note that C++ implementations could either have their throw - versions call the nothrow versions (libstdc++), or the other way - around (clang/libc++). For that reason, we replace both throw and - nothrow variants and call malloc directly. */ - -void * -operator new (std::size_t sz) -{ - /* malloc (0) is unpredictable; avoid it. */ - if (sz == 0) - sz = 1; - - void *p = malloc (sz); /* ARI: malloc */ - if (p == NULL) - { - /* If the user decides to continue debugging, throw a - gdb_quit_bad_alloc exception instead of a regular QUIT - gdb_exception. The former extends both std::bad_alloc and a - QUIT gdb_exception. This is necessary because operator new - can only ever throw std::bad_alloc, or something that extends - it. */ - try - { - malloc_failure (sz); - } - catch (gdb_exception &ex) - { - throw gdb_quit_bad_alloc (std::move (ex)); - } - } - return p; -} - -void * -operator new (std::size_t sz, const std::nothrow_t&) noexcept -{ - /* malloc (0) is unpredictable; avoid it. */ - if (sz == 0) - sz = 1; - return malloc (sz); /* ARI: malloc */ -} - -void * -operator new[] (std::size_t sz) -{ - return ::operator new (sz); -} - -void* -operator new[] (std::size_t sz, const std::nothrow_t&) noexcept -{ - return ::operator new (sz, std::nothrow); -} -#endif diff --git a/gdbsupport/new-op.cc b/gdbsupport/new-op.cc new file mode 100644 index 0000000..cf2525c --- /dev/null +++ b/gdbsupport/new-op.cc @@ -0,0 +1,95 @@ +/* Replace operator new/new[], for GDB, the GNU debugger. + + Copyright (C) 2016-2020 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 . */ + +/* GCC does not understand __has_feature. */ +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif + +#if !__has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) +#include "common-defs.h" +#include "host-defs.h" +#include + +/* Override operator new / operator new[], in order to internal_error + on allocation failure and thus query the user for abort/core + dump/continue, just like xmalloc does. We don't do this from a + new-handler function instead (std::set_new_handler) because we want + to catch allocation errors from within global constructors too. + + Skip overriding if building with -fsanitize=address though. + Address sanitizer wants to override operator new/delete too in + order to detect malloc+delete and new+free mismatches. Our + versions would mask out ASan's, with the result of losing that + useful mismatch detection. + + Note that C++ implementations could either have their throw + versions call the nothrow versions (libstdc++), or the other way + around (clang/libc++). For that reason, we replace both throw and + nothrow variants and call malloc directly. */ + +void * +operator new (std::size_t sz) +{ + /* malloc (0) is unpredictable; avoid it. */ + if (sz == 0) + sz = 1; + + void *p = malloc (sz); /* ARI: malloc */ + if (p == NULL) + { + /* If the user decides to continue debugging, throw a + gdb_quit_bad_alloc exception instead of a regular QUIT + gdb_exception. The former extends both std::bad_alloc and a + QUIT gdb_exception. This is necessary because operator new + can only ever throw std::bad_alloc, or something that extends + it. */ + try + { + malloc_failure (sz); + } + catch (gdb_exception &ex) + { + throw gdb_quit_bad_alloc (std::move (ex)); + } + } + return p; +} + +void * +operator new (std::size_t sz, const std::nothrow_t&) noexcept +{ + /* malloc (0) is unpredictable; avoid it. */ + if (sz == 0) + sz = 1; + return malloc (sz); /* ARI: malloc */ +} + +void * +operator new[] (std::size_t sz) +{ + return ::operator new (sz); +} + +void* +operator new[] (std::size_t sz, const std::nothrow_t&) noexcept +{ + return ::operator new (sz, std::nothrow); +} +#endif diff --git a/gdbsupport/pathstuff.c b/gdbsupport/pathstuff.c deleted file mode 100644 index 1f60fd0..0000000 --- a/gdbsupport/pathstuff.c +++ /dev/null @@ -1,290 +0,0 @@ -/* Path manipulation routines for GDB and gdbserver. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "pathstuff.h" -#include "host-defs.h" -#include "filenames.h" -#include "gdb_tilde_expand.h" - -#ifdef USE_WIN32API -#include -#endif - -/* See gdbsupport/pathstuff.h. */ - -gdb::unique_xmalloc_ptr -gdb_realpath (const char *filename) -{ -/* On most hosts, we rely on canonicalize_file_name to compute - the FILENAME's realpath. - - But the situation is slightly more complex on Windows, due to some - versions of GCC which were reported to generate paths where - backlashes (the directory separator) were doubled. For instance: - c:\\some\\double\\slashes\\dir - ... instead of ... - c:\some\double\slashes\dir - Those double-slashes were getting in the way when comparing paths, - for instance when trying to insert a breakpoint as follow: - (gdb) b c:/some/double/slashes/dir/foo.c:4 - No source file named c:/some/double/slashes/dir/foo.c:4. - (gdb) b c:\some\double\slashes\dir\foo.c:4 - No source file named c:\some\double\slashes\dir\foo.c:4. - To prevent this from happening, we need this function to always - strip those extra backslashes. While canonicalize_file_name does - perform this simplification, it only works when the path is valid. - Since the simplification would be useful even if the path is not - valid (one can always set a breakpoint on a file, even if the file - does not exist locally), we rely instead on GetFullPathName to - perform the canonicalization. */ - -#if defined (_WIN32) - { - char buf[MAX_PATH]; - DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL); - - /* The file system is case-insensitive but case-preserving. - So it is important we do not lowercase the path. Otherwise, - we might not be able to display the original casing in a given - path. */ - if (len > 0 && len < MAX_PATH) - return make_unique_xstrdup (buf); - } -#else - { - char *rp = canonicalize_file_name (filename); - - if (rp != NULL) - return gdb::unique_xmalloc_ptr (rp); - } -#endif - - /* This system is a lost cause, just dup the buffer. */ - return make_unique_xstrdup (filename); -} - -/* See gdbsupport/pathstuff.h. */ - -gdb::unique_xmalloc_ptr -gdb_realpath_keepfile (const char *filename) -{ - const char *base_name = lbasename (filename); - char *dir_name; - char *result; - - /* Extract the basename of filename, and return immediately - a copy of filename if it does not contain any directory prefix. */ - if (base_name == filename) - return make_unique_xstrdup (filename); - - dir_name = (char *) alloca ((size_t) (base_name - filename + 2)); - /* Allocate enough space to store the dir_name + plus one extra - character sometimes needed under Windows (see below), and - then the closing \000 character. */ - strncpy (dir_name, filename, base_name - filename); - dir_name[base_name - filename] = '\000'; - -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - /* We need to be careful when filename is of the form 'd:foo', which - is equivalent of d:./foo, which is totally different from d:/foo. */ - if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':') - { - dir_name[2] = '.'; - dir_name[3] = '\000'; - } -#endif - - /* Canonicalize the directory prefix, and build the resulting - filename. If the dirname realpath already contains an ending - directory separator, avoid doubling it. */ - gdb::unique_xmalloc_ptr path_storage = gdb_realpath (dir_name); - const char *real_path = path_storage.get (); - if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1])) - result = concat (real_path, base_name, (char *) NULL); - else - result = concat (real_path, SLASH_STRING, base_name, (char *) NULL); - - return gdb::unique_xmalloc_ptr (result); -} - -/* See gdbsupport/pathstuff.h. */ - -gdb::unique_xmalloc_ptr -gdb_abspath (const char *path) -{ - gdb_assert (path != NULL && path[0] != '\0'); - - if (path[0] == '~') - return gdb_tilde_expand_up (path); - - if (IS_ABSOLUTE_PATH (path) || current_directory == NULL) - return make_unique_xstrdup (path); - - /* Beware the // my son, the Emacs barfs, the botch that catch... */ - return gdb::unique_xmalloc_ptr - (concat (current_directory, - IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) - ? "" : SLASH_STRING, - path, (char *) NULL)); -} - -/* See gdbsupport/pathstuff.h. */ - -const char * -child_path (const char *parent, const char *child) -{ - /* The child path must start with the parent path. */ - size_t parent_len = strlen (parent); - if (filename_ncmp (parent, child, parent_len) != 0) - return NULL; - - /* The parent path must be a directory and the child must contain at - least one component underneath the parent. */ - const char *child_component; - if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1])) - { - /* The parent path ends in a directory separator, so it is a - directory. The first child component starts after the common - prefix. */ - child_component = child + parent_len; - } - else - { - /* The parent path does not end in a directory separator. The - first character in the child after the common prefix must be - a directory separator. - - Note that CHILD must hold at least parent_len characters for - filename_ncmp to return zero. If the character at parent_len - is nul due to CHILD containing the same path as PARENT, the - IS_DIR_SEPARATOR check will fail here. */ - if (!IS_DIR_SEPARATOR (child[parent_len])) - return NULL; - - /* The first child component starts after the separator after the - common prefix. */ - child_component = child + parent_len + 1; - } - - /* The child must contain at least one non-separator character after - the parent. */ - while (*child_component != '\0') - { - if (!IS_DIR_SEPARATOR (*child_component)) - return child_component; - - child_component++; - } - return NULL; -} - -/* See gdbsupport/pathstuff.h. */ - -bool -contains_dir_separator (const char *path) -{ - for (; *path != '\0'; path++) - { - if (IS_DIR_SEPARATOR (*path)) - return true; - } - - return false; -} - -/* See gdbsupport/pathstuff.h. */ - -std::string -get_standard_cache_dir () -{ -#ifdef __APPLE__ -#define HOME_CACHE_DIR "Library/Caches" -#else -#define HOME_CACHE_DIR ".cache" -#endif - -#ifndef __APPLE__ - const char *xdg_cache_home = getenv ("XDG_CACHE_HOME"); - if (xdg_cache_home != NULL) - { - /* Make sure the path is absolute and tilde-expanded. */ - gdb::unique_xmalloc_ptr abs (gdb_abspath (xdg_cache_home)); - return string_printf ("%s/gdb", abs.get ()); - } -#endif - - const char *home = getenv ("HOME"); - if (home != NULL) - { - /* Make sure the path is absolute and tilde-expanded. */ - gdb::unique_xmalloc_ptr abs (gdb_abspath (home)); - return string_printf ("%s/" HOME_CACHE_DIR "/gdb", abs.get ()); - } - - return {}; -} - -/* See gdbsupport/pathstuff.h. */ - -std::string -get_standard_temp_dir () -{ -#ifdef WIN32 - const char *tmp = getenv ("TMP"); - if (tmp != nullptr) - return tmp; - - tmp = getenv ("TEMP"); - if (tmp != nullptr) - return tmp; - - error (_("Couldn't find temp dir path, both TMP and TEMP are unset.")); - -#else - const char *tmp = getenv ("TMPDIR"); - if (tmp != nullptr) - return tmp; - - return "/tmp"; -#endif -} - -/* See gdbsupport/pathstuff.h. */ - -const char * -get_shell () -{ - const char *ret = getenv ("SHELL"); - if (ret == NULL) - ret = "/bin/sh"; - - return ret; -} - -/* See gdbsupport/pathstuff.h. */ - -gdb::char_vector -make_temp_filename (const std::string &f) -{ - gdb::char_vector filename_temp (f.length () + 8); - strcpy (filename_temp.data (), f.c_str ()); - strcat (filename_temp.data () + f.size (), "-XXXXXX"); - return filename_temp; -} diff --git a/gdbsupport/pathstuff.cc b/gdbsupport/pathstuff.cc new file mode 100644 index 0000000..1f60fd0 --- /dev/null +++ b/gdbsupport/pathstuff.cc @@ -0,0 +1,290 @@ +/* Path manipulation routines for GDB and gdbserver. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "pathstuff.h" +#include "host-defs.h" +#include "filenames.h" +#include "gdb_tilde_expand.h" + +#ifdef USE_WIN32API +#include +#endif + +/* See gdbsupport/pathstuff.h. */ + +gdb::unique_xmalloc_ptr +gdb_realpath (const char *filename) +{ +/* On most hosts, we rely on canonicalize_file_name to compute + the FILENAME's realpath. + + But the situation is slightly more complex on Windows, due to some + versions of GCC which were reported to generate paths where + backlashes (the directory separator) were doubled. For instance: + c:\\some\\double\\slashes\\dir + ... instead of ... + c:\some\double\slashes\dir + Those double-slashes were getting in the way when comparing paths, + for instance when trying to insert a breakpoint as follow: + (gdb) b c:/some/double/slashes/dir/foo.c:4 + No source file named c:/some/double/slashes/dir/foo.c:4. + (gdb) b c:\some\double\slashes\dir\foo.c:4 + No source file named c:\some\double\slashes\dir\foo.c:4. + To prevent this from happening, we need this function to always + strip those extra backslashes. While canonicalize_file_name does + perform this simplification, it only works when the path is valid. + Since the simplification would be useful even if the path is not + valid (one can always set a breakpoint on a file, even if the file + does not exist locally), we rely instead on GetFullPathName to + perform the canonicalization. */ + +#if defined (_WIN32) + { + char buf[MAX_PATH]; + DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL); + + /* The file system is case-insensitive but case-preserving. + So it is important we do not lowercase the path. Otherwise, + we might not be able to display the original casing in a given + path. */ + if (len > 0 && len < MAX_PATH) + return make_unique_xstrdup (buf); + } +#else + { + char *rp = canonicalize_file_name (filename); + + if (rp != NULL) + return gdb::unique_xmalloc_ptr (rp); + } +#endif + + /* This system is a lost cause, just dup the buffer. */ + return make_unique_xstrdup (filename); +} + +/* See gdbsupport/pathstuff.h. */ + +gdb::unique_xmalloc_ptr +gdb_realpath_keepfile (const char *filename) +{ + const char *base_name = lbasename (filename); + char *dir_name; + char *result; + + /* Extract the basename of filename, and return immediately + a copy of filename if it does not contain any directory prefix. */ + if (base_name == filename) + return make_unique_xstrdup (filename); + + dir_name = (char *) alloca ((size_t) (base_name - filename + 2)); + /* Allocate enough space to store the dir_name + plus one extra + character sometimes needed under Windows (see below), and + then the closing \000 character. */ + strncpy (dir_name, filename, base_name - filename); + dir_name[base_name - filename] = '\000'; + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + /* We need to be careful when filename is of the form 'd:foo', which + is equivalent of d:./foo, which is totally different from d:/foo. */ + if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':') + { + dir_name[2] = '.'; + dir_name[3] = '\000'; + } +#endif + + /* Canonicalize the directory prefix, and build the resulting + filename. If the dirname realpath already contains an ending + directory separator, avoid doubling it. */ + gdb::unique_xmalloc_ptr path_storage = gdb_realpath (dir_name); + const char *real_path = path_storage.get (); + if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1])) + result = concat (real_path, base_name, (char *) NULL); + else + result = concat (real_path, SLASH_STRING, base_name, (char *) NULL); + + return gdb::unique_xmalloc_ptr (result); +} + +/* See gdbsupport/pathstuff.h. */ + +gdb::unique_xmalloc_ptr +gdb_abspath (const char *path) +{ + gdb_assert (path != NULL && path[0] != '\0'); + + if (path[0] == '~') + return gdb_tilde_expand_up (path); + + if (IS_ABSOLUTE_PATH (path) || current_directory == NULL) + return make_unique_xstrdup (path); + + /* Beware the // my son, the Emacs barfs, the botch that catch... */ + return gdb::unique_xmalloc_ptr + (concat (current_directory, + IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) + ? "" : SLASH_STRING, + path, (char *) NULL)); +} + +/* See gdbsupport/pathstuff.h. */ + +const char * +child_path (const char *parent, const char *child) +{ + /* The child path must start with the parent path. */ + size_t parent_len = strlen (parent); + if (filename_ncmp (parent, child, parent_len) != 0) + return NULL; + + /* The parent path must be a directory and the child must contain at + least one component underneath the parent. */ + const char *child_component; + if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1])) + { + /* The parent path ends in a directory separator, so it is a + directory. The first child component starts after the common + prefix. */ + child_component = child + parent_len; + } + else + { + /* The parent path does not end in a directory separator. The + first character in the child after the common prefix must be + a directory separator. + + Note that CHILD must hold at least parent_len characters for + filename_ncmp to return zero. If the character at parent_len + is nul due to CHILD containing the same path as PARENT, the + IS_DIR_SEPARATOR check will fail here. */ + if (!IS_DIR_SEPARATOR (child[parent_len])) + return NULL; + + /* The first child component starts after the separator after the + common prefix. */ + child_component = child + parent_len + 1; + } + + /* The child must contain at least one non-separator character after + the parent. */ + while (*child_component != '\0') + { + if (!IS_DIR_SEPARATOR (*child_component)) + return child_component; + + child_component++; + } + return NULL; +} + +/* See gdbsupport/pathstuff.h. */ + +bool +contains_dir_separator (const char *path) +{ + for (; *path != '\0'; path++) + { + if (IS_DIR_SEPARATOR (*path)) + return true; + } + + return false; +} + +/* See gdbsupport/pathstuff.h. */ + +std::string +get_standard_cache_dir () +{ +#ifdef __APPLE__ +#define HOME_CACHE_DIR "Library/Caches" +#else +#define HOME_CACHE_DIR ".cache" +#endif + +#ifndef __APPLE__ + const char *xdg_cache_home = getenv ("XDG_CACHE_HOME"); + if (xdg_cache_home != NULL) + { + /* Make sure the path is absolute and tilde-expanded. */ + gdb::unique_xmalloc_ptr abs (gdb_abspath (xdg_cache_home)); + return string_printf ("%s/gdb", abs.get ()); + } +#endif + + const char *home = getenv ("HOME"); + if (home != NULL) + { + /* Make sure the path is absolute and tilde-expanded. */ + gdb::unique_xmalloc_ptr abs (gdb_abspath (home)); + return string_printf ("%s/" HOME_CACHE_DIR "/gdb", abs.get ()); + } + + return {}; +} + +/* See gdbsupport/pathstuff.h. */ + +std::string +get_standard_temp_dir () +{ +#ifdef WIN32 + const char *tmp = getenv ("TMP"); + if (tmp != nullptr) + return tmp; + + tmp = getenv ("TEMP"); + if (tmp != nullptr) + return tmp; + + error (_("Couldn't find temp dir path, both TMP and TEMP are unset.")); + +#else + const char *tmp = getenv ("TMPDIR"); + if (tmp != nullptr) + return tmp; + + return "/tmp"; +#endif +} + +/* See gdbsupport/pathstuff.h. */ + +const char * +get_shell () +{ + const char *ret = getenv ("SHELL"); + if (ret == NULL) + ret = "/bin/sh"; + + return ret; +} + +/* See gdbsupport/pathstuff.h. */ + +gdb::char_vector +make_temp_filename (const std::string &f) +{ + gdb::char_vector filename_temp (f.length () + 8); + strcpy (filename_temp.data (), f.c_str ()); + strcat (filename_temp.data () + f.size (), "-XXXXXX"); + return filename_temp; +} diff --git a/gdbsupport/print-utils.c b/gdbsupport/print-utils.c deleted file mode 100644 index a8d8681..0000000 --- a/gdbsupport/print-utils.c +++ /dev/null @@ -1,326 +0,0 @@ -/* Cell-based print utility routines for GDB, the GNU debugger. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "print-utils.h" -/* Temporary storage using circular buffer. */ - -/* Number of cells in the circular buffer. */ -#define NUMCELLS 16 - -/* Return the next entry in the circular buffer. */ - -char * -get_print_cell (void) -{ - static char buf[NUMCELLS][PRINT_CELL_SIZE]; - static int cell = 0; - - if (++cell >= NUMCELLS) - cell = 0; - return buf[cell]; -} - -static char * -decimal2str (const char *sign, ULONGEST addr, int width) -{ - /* Steal code from valprint.c:print_decimal(). Should this worry - about the real size of addr as the above does? */ - unsigned long temp[3]; - char *str = get_print_cell (); - int i = 0; - - do - { - temp[i] = addr % (1000 * 1000 * 1000); - addr /= (1000 * 1000 * 1000); - i++; - width -= 9; - } - while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); - - width += 9; - if (width < 0) - width = 0; - - switch (i) - { - case 1: - xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu", sign, width, temp[0]); - break; - case 2: - xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu", sign, width, - temp[1], temp[0]); - break; - case 3: - xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu%09lu", sign, width, - temp[2], temp[1], temp[0]); - break; - default: - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - } - - return str; -} - -static char * -octal2str (ULONGEST addr, int width) -{ - unsigned long temp[3]; - char *str = get_print_cell (); - int i = 0; - - do - { - temp[i] = addr % (0100000 * 0100000); - addr /= (0100000 * 0100000); - i++; - width -= 10; - } - while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); - - width += 10; - if (width < 0) - width = 0; - - switch (i) - { - case 1: - if (temp[0] == 0) - xsnprintf (str, PRINT_CELL_SIZE, "%*o", width, 0); - else - xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo", width, temp[0]); - break; - case 2: - xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo", width, temp[1], temp[0]); - break; - case 3: - xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo%010lo", width, - temp[2], temp[1], temp[0]); - break; - default: - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - } - - return str; -} - -/* See print-utils.h. */ - -char * -pulongest (ULONGEST u) -{ - return decimal2str ("", u, 0); -} - -/* See print-utils.h. */ - -char * -plongest (LONGEST l) -{ - if (l < 0) - return decimal2str ("-", -l, 0); - else - return decimal2str ("", l, 0); -} - -/* Eliminate warning from compiler on 32-bit systems. */ -static int thirty_two = 32; - -/* See print-utils.h. */ - -char * -phex (ULONGEST l, int sizeof_l) -{ - char *str; - - switch (sizeof_l) - { - case 8: - str = get_print_cell (); - xsnprintf (str, PRINT_CELL_SIZE, "%08lx%08lx", - (unsigned long) (l >> thirty_two), - (unsigned long) (l & 0xffffffff)); - break; - case 4: - str = get_print_cell (); - xsnprintf (str, PRINT_CELL_SIZE, "%08lx", (unsigned long) l); - break; - case 2: - str = get_print_cell (); - xsnprintf (str, PRINT_CELL_SIZE, "%04x", (unsigned short) (l & 0xffff)); - break; - default: - str = phex (l, sizeof (l)); - break; - } - - return str; -} - -/* See print-utils.h. */ - -char * -phex_nz (ULONGEST l, int sizeof_l) -{ - char *str; - - switch (sizeof_l) - { - case 8: - { - unsigned long high = (unsigned long) (l >> thirty_two); - - str = get_print_cell (); - if (high == 0) - xsnprintf (str, PRINT_CELL_SIZE, "%lx", - (unsigned long) (l & 0xffffffff)); - else - xsnprintf (str, PRINT_CELL_SIZE, "%lx%08lx", high, - (unsigned long) (l & 0xffffffff)); - break; - } - case 4: - str = get_print_cell (); - xsnprintf (str, PRINT_CELL_SIZE, "%lx", (unsigned long) l); - break; - case 2: - str = get_print_cell (); - xsnprintf (str, PRINT_CELL_SIZE, "%x", (unsigned short) (l & 0xffff)); - break; - default: - str = phex_nz (l, sizeof (l)); - break; - } - - return str; -} - -/* See print-utils.h. */ - -char * -hex_string (LONGEST num) -{ - char *result = get_print_cell (); - - xsnprintf (result, PRINT_CELL_SIZE, "0x%s", phex_nz (num, sizeof (num))); - return result; -} - -/* See print-utils.h. */ - -char * -hex_string_custom (LONGEST num, int width) -{ - char *result = get_print_cell (); - char *result_end = result + PRINT_CELL_SIZE - 1; - const char *hex = phex_nz (num, sizeof (num)); - int hex_len = strlen (hex); - - if (hex_len > width) - width = hex_len; - if (width + 2 >= PRINT_CELL_SIZE) - internal_error (__FILE__, __LINE__, _("\ -hex_string_custom: insufficient space to store result")); - - strcpy (result_end - width - 2, "0x"); - memset (result_end - width, '0', width); - strcpy (result_end - hex_len, hex); - return result_end - width - 2; -} - -/* See print-utils.h. */ - -char * -int_string (LONGEST val, int radix, int is_signed, int width, - int use_c_format) -{ - switch (radix) - { - case 16: - { - char *result; - - if (width == 0) - result = hex_string (val); - else - result = hex_string_custom (val, width); - if (! use_c_format) - result += 2; - return result; - } - case 10: - { - if (is_signed && val < 0) - return decimal2str ("-", -val, width); - else - return decimal2str ("", val, width); - } - case 8: - { - char *result = octal2str (val, width); - - if (use_c_format || val == 0) - return result; - else - return result + 1; - } - default: - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - } -} - -/* See print-utils.h. */ - -const char * -core_addr_to_string (const CORE_ADDR addr) -{ - char *str = get_print_cell (); - - strcpy (str, "0x"); - strcat (str, phex (addr, sizeof (addr))); - return str; -} - -/* See print-utils.h. */ - -const char * -core_addr_to_string_nz (const CORE_ADDR addr) -{ - char *str = get_print_cell (); - - strcpy (str, "0x"); - strcat (str, phex_nz (addr, sizeof (addr))); - return str; -} - -/* See print-utils.h. */ - -const char * -host_address_to_string_1 (const void *addr) -{ - char *str = get_print_cell (); - - xsnprintf (str, PRINT_CELL_SIZE, "0x%s", - phex_nz ((uintptr_t) addr, sizeof (addr))); - return str; -} diff --git a/gdbsupport/print-utils.cc b/gdbsupport/print-utils.cc new file mode 100644 index 0000000..a8d8681 --- /dev/null +++ b/gdbsupport/print-utils.cc @@ -0,0 +1,326 @@ +/* Cell-based print utility routines for GDB, the GNU debugger. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "print-utils.h" +/* Temporary storage using circular buffer. */ + +/* Number of cells in the circular buffer. */ +#define NUMCELLS 16 + +/* Return the next entry in the circular buffer. */ + +char * +get_print_cell (void) +{ + static char buf[NUMCELLS][PRINT_CELL_SIZE]; + static int cell = 0; + + if (++cell >= NUMCELLS) + cell = 0; + return buf[cell]; +} + +static char * +decimal2str (const char *sign, ULONGEST addr, int width) +{ + /* Steal code from valprint.c:print_decimal(). Should this worry + about the real size of addr as the above does? */ + unsigned long temp[3]; + char *str = get_print_cell (); + int i = 0; + + do + { + temp[i] = addr % (1000 * 1000 * 1000); + addr /= (1000 * 1000 * 1000); + i++; + width -= 9; + } + while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); + + width += 9; + if (width < 0) + width = 0; + + switch (i) + { + case 1: + xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu", sign, width, temp[0]); + break; + case 2: + xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu", sign, width, + temp[1], temp[0]); + break; + case 3: + xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu%09lu", sign, width, + temp[2], temp[1], temp[0]); + break; + default: + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + } + + return str; +} + +static char * +octal2str (ULONGEST addr, int width) +{ + unsigned long temp[3]; + char *str = get_print_cell (); + int i = 0; + + do + { + temp[i] = addr % (0100000 * 0100000); + addr /= (0100000 * 0100000); + i++; + width -= 10; + } + while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); + + width += 10; + if (width < 0) + width = 0; + + switch (i) + { + case 1: + if (temp[0] == 0) + xsnprintf (str, PRINT_CELL_SIZE, "%*o", width, 0); + else + xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo", width, temp[0]); + break; + case 2: + xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo", width, temp[1], temp[0]); + break; + case 3: + xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo%010lo", width, + temp[2], temp[1], temp[0]); + break; + default: + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + } + + return str; +} + +/* See print-utils.h. */ + +char * +pulongest (ULONGEST u) +{ + return decimal2str ("", u, 0); +} + +/* See print-utils.h. */ + +char * +plongest (LONGEST l) +{ + if (l < 0) + return decimal2str ("-", -l, 0); + else + return decimal2str ("", l, 0); +} + +/* Eliminate warning from compiler on 32-bit systems. */ +static int thirty_two = 32; + +/* See print-utils.h. */ + +char * +phex (ULONGEST l, int sizeof_l) +{ + char *str; + + switch (sizeof_l) + { + case 8: + str = get_print_cell (); + xsnprintf (str, PRINT_CELL_SIZE, "%08lx%08lx", + (unsigned long) (l >> thirty_two), + (unsigned long) (l & 0xffffffff)); + break; + case 4: + str = get_print_cell (); + xsnprintf (str, PRINT_CELL_SIZE, "%08lx", (unsigned long) l); + break; + case 2: + str = get_print_cell (); + xsnprintf (str, PRINT_CELL_SIZE, "%04x", (unsigned short) (l & 0xffff)); + break; + default: + str = phex (l, sizeof (l)); + break; + } + + return str; +} + +/* See print-utils.h. */ + +char * +phex_nz (ULONGEST l, int sizeof_l) +{ + char *str; + + switch (sizeof_l) + { + case 8: + { + unsigned long high = (unsigned long) (l >> thirty_two); + + str = get_print_cell (); + if (high == 0) + xsnprintf (str, PRINT_CELL_SIZE, "%lx", + (unsigned long) (l & 0xffffffff)); + else + xsnprintf (str, PRINT_CELL_SIZE, "%lx%08lx", high, + (unsigned long) (l & 0xffffffff)); + break; + } + case 4: + str = get_print_cell (); + xsnprintf (str, PRINT_CELL_SIZE, "%lx", (unsigned long) l); + break; + case 2: + str = get_print_cell (); + xsnprintf (str, PRINT_CELL_SIZE, "%x", (unsigned short) (l & 0xffff)); + break; + default: + str = phex_nz (l, sizeof (l)); + break; + } + + return str; +} + +/* See print-utils.h. */ + +char * +hex_string (LONGEST num) +{ + char *result = get_print_cell (); + + xsnprintf (result, PRINT_CELL_SIZE, "0x%s", phex_nz (num, sizeof (num))); + return result; +} + +/* See print-utils.h. */ + +char * +hex_string_custom (LONGEST num, int width) +{ + char *result = get_print_cell (); + char *result_end = result + PRINT_CELL_SIZE - 1; + const char *hex = phex_nz (num, sizeof (num)); + int hex_len = strlen (hex); + + if (hex_len > width) + width = hex_len; + if (width + 2 >= PRINT_CELL_SIZE) + internal_error (__FILE__, __LINE__, _("\ +hex_string_custom: insufficient space to store result")); + + strcpy (result_end - width - 2, "0x"); + memset (result_end - width, '0', width); + strcpy (result_end - hex_len, hex); + return result_end - width - 2; +} + +/* See print-utils.h. */ + +char * +int_string (LONGEST val, int radix, int is_signed, int width, + int use_c_format) +{ + switch (radix) + { + case 16: + { + char *result; + + if (width == 0) + result = hex_string (val); + else + result = hex_string_custom (val, width); + if (! use_c_format) + result += 2; + return result; + } + case 10: + { + if (is_signed && val < 0) + return decimal2str ("-", -val, width); + else + return decimal2str ("", val, width); + } + case 8: + { + char *result = octal2str (val, width); + + if (use_c_format || val == 0) + return result; + else + return result + 1; + } + default: + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + } +} + +/* See print-utils.h. */ + +const char * +core_addr_to_string (const CORE_ADDR addr) +{ + char *str = get_print_cell (); + + strcpy (str, "0x"); + strcat (str, phex (addr, sizeof (addr))); + return str; +} + +/* See print-utils.h. */ + +const char * +core_addr_to_string_nz (const CORE_ADDR addr) +{ + char *str = get_print_cell (); + + strcpy (str, "0x"); + strcat (str, phex_nz (addr, sizeof (addr))); + return str; +} + +/* See print-utils.h. */ + +const char * +host_address_to_string_1 (const void *addr) +{ + char *str = get_print_cell (); + + xsnprintf (str, PRINT_CELL_SIZE, "0x%s", + phex_nz ((uintptr_t) addr, sizeof (addr))); + return str; +} diff --git a/gdbsupport/ptid.c b/gdbsupport/ptid.c deleted file mode 100644 index 9638943..0000000 --- a/gdbsupport/ptid.c +++ /dev/null @@ -1,26 +0,0 @@ -/* The ptid_t type and common functions operating on it. - - Copyright (C) 1986-2020 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 . */ - -#include "common-defs.h" -#include "ptid.h" - -/* See ptid.h for these. */ - -ptid_t const null_ptid = ptid_t::make_null (); -ptid_t const minus_one_ptid = ptid_t::make_minus_one (); diff --git a/gdbsupport/ptid.cc b/gdbsupport/ptid.cc new file mode 100644 index 0000000..9638943 --- /dev/null +++ b/gdbsupport/ptid.cc @@ -0,0 +1,26 @@ +/* The ptid_t type and common functions operating on it. + + Copyright (C) 1986-2020 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 . */ + +#include "common-defs.h" +#include "ptid.h" + +/* See ptid.h for these. */ + +ptid_t const null_ptid = ptid_t::make_null (); +ptid_t const minus_one_ptid = ptid_t::make_minus_one (); diff --git a/gdbsupport/rsp-low.c b/gdbsupport/rsp-low.c deleted file mode 100644 index 9bb1660..0000000 --- a/gdbsupport/rsp-low.c +++ /dev/null @@ -1,307 +0,0 @@ -/* Low-level RSP routines for GDB, the GNU debugger. - - Copyright (C) 1988-2020 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 . */ - -#include "common-defs.h" -#include "rsp-low.h" - -/* See rsp-low.h. */ - -int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - else - error (_("Reply contains invalid hex digit %d"), a); -} - -/* See rsp-low.h. */ - -int -tohex (int nib) -{ - if (nib < 10) - return '0' + nib; - else - return 'a' + nib - 10; -} - -/* Encode 64 bits in 16 chars of hex. */ - -static const char hexchars[] = "0123456789abcdef"; - -static int -ishex (int ch, int *val) -{ - if ((ch >= 'a') && (ch <= 'f')) - { - *val = ch - 'a' + 10; - return 1; - } - if ((ch >= 'A') && (ch <= 'F')) - { - *val = ch - 'A' + 10; - return 1; - } - if ((ch >= '0') && (ch <= '9')) - { - *val = ch - '0'; - return 1; - } - return 0; -} - -/* See rsp-low.h. */ - -char * -pack_nibble (char *buf, int nibble) -{ - *buf++ = hexchars[(nibble & 0x0f)]; - return buf; -} - -/* See rsp-low.h. */ - -char * -pack_hex_byte (char *pkt, int byte) -{ - *pkt++ = hexchars[(byte >> 4) & 0xf]; - *pkt++ = hexchars[(byte & 0xf)]; - return pkt; -} - -/* See rsp-low.h. */ - -const char * -unpack_varlen_hex (const char *buff, /* packet to parse */ - ULONGEST *result) -{ - int nibble; - ULONGEST retval = 0; - - while (ishex (*buff, &nibble)) - { - buff++; - retval = retval << 4; - retval |= nibble & 0x0f; - } - *result = retval; - return buff; -} - -/* See rsp-low.h. */ - -int -hex2bin (const char *hex, gdb_byte *bin, int count) -{ - int i; - - for (i = 0; i < count; i++) - { - if (hex[0] == 0 || hex[1] == 0) - { - /* Hex string is short, or of uneven length. - Return the count that has been converted so far. */ - return i; - } - *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); - hex += 2; - } - return i; -} - -/* See rsp-low.h. */ - -gdb::byte_vector -hex2bin (const char *hex) -{ - size_t bin_len = strlen (hex) / 2; - gdb::byte_vector bin (bin_len); - - hex2bin (hex, bin.data (), bin_len); - - return bin; -} - -/* See rsp-low.h. */ - -std::string -hex2str (const char *hex) -{ - return hex2str (hex, strlen (hex)); -} - -/* See rsp-low.h. */ - -std::string -hex2str (const char *hex, int count) -{ - std::string ret; - - ret.reserve (count); - for (size_t i = 0; i < count; ++i) - { - if (hex[0] == '\0' || hex[1] == '\0') - { - /* Hex string is short, or of uneven length. Return what we - have so far. */ - return ret; - } - ret += fromhex (hex[0]) * 16 + fromhex (hex[1]); - hex += 2; - } - - return ret; -} - -/* See rsp-low.h. */ - -int -bin2hex (const gdb_byte *bin, char *hex, int count) -{ - int i; - - for (i = 0; i < count; i++) - { - *hex++ = tohex ((*bin >> 4) & 0xf); - *hex++ = tohex (*bin++ & 0xf); - } - *hex = 0; - return i; -} - -/* See rsp-low.h. */ - -std::string -bin2hex (const gdb_byte *bin, int count) -{ - std::string ret; - - ret.reserve (count * 2); - for (int i = 0; i < count; ++i) - { - ret += tohex ((*bin >> 4) & 0xf); - ret += tohex (*bin++ & 0xf); - } - - return ret; -} - -/* Return whether byte B needs escaping when sent as part of binary data. */ - -static int -needs_escaping (gdb_byte b) -{ - return b == '$' || b == '#' || b == '}' || b == '*'; -} - -/* See rsp-low.h. */ - -int -remote_escape_output (const gdb_byte *buffer, int len_units, int unit_size, - gdb_byte *out_buf, int *out_len_units, - int out_maxlen_bytes) -{ - int input_unit_index, output_byte_index = 0, byte_index_in_unit; - int number_escape_bytes_needed; - - /* Try to copy integral addressable memory units until - (1) we run out of space or - (2) we copied all of them. */ - for (input_unit_index = 0; - input_unit_index < len_units; - input_unit_index++) - { - /* Find out how many escape bytes we need for this unit. */ - number_escape_bytes_needed = 0; - for (byte_index_in_unit = 0; - byte_index_in_unit < unit_size; - byte_index_in_unit++) - { - int idx = input_unit_index * unit_size + byte_index_in_unit; - gdb_byte b = buffer[idx]; - if (needs_escaping (b)) - number_escape_bytes_needed++; - } - - /* Check if we have room to fit this escaped unit. */ - if (output_byte_index + unit_size + number_escape_bytes_needed > - out_maxlen_bytes) - break; - - /* Copy the unit byte per byte, adding escapes. */ - for (byte_index_in_unit = 0; - byte_index_in_unit < unit_size; - byte_index_in_unit++) - { - int idx = input_unit_index * unit_size + byte_index_in_unit; - gdb_byte b = buffer[idx]; - if (needs_escaping (b)) - { - out_buf[output_byte_index++] = '}'; - out_buf[output_byte_index++] = b ^ 0x20; - } - else - out_buf[output_byte_index++] = b; - } - } - - *out_len_units = input_unit_index; - return output_byte_index; -} - -/* See rsp-low.h. */ - -int -remote_unescape_input (const gdb_byte *buffer, int len, - gdb_byte *out_buf, int out_maxlen) -{ - int input_index, output_index; - int escaped; - - output_index = 0; - escaped = 0; - for (input_index = 0; input_index < len; input_index++) - { - gdb_byte b = buffer[input_index]; - - if (output_index + 1 > out_maxlen) - error (_("Received too much data from the target.")); - - if (escaped) - { - out_buf[output_index++] = b ^ 0x20; - escaped = 0; - } - else if (b == '}') - escaped = 1; - else - out_buf[output_index++] = b; - } - - if (escaped) - error (_("Unmatched escape character in target response.")); - - return output_index; -} - diff --git a/gdbsupport/rsp-low.cc b/gdbsupport/rsp-low.cc new file mode 100644 index 0000000..9bb1660 --- /dev/null +++ b/gdbsupport/rsp-low.cc @@ -0,0 +1,307 @@ +/* Low-level RSP routines for GDB, the GNU debugger. + + Copyright (C) 1988-2020 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 . */ + +#include "common-defs.h" +#include "rsp-low.h" + +/* See rsp-low.h. */ + +int +fromhex (int a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else + error (_("Reply contains invalid hex digit %d"), a); +} + +/* See rsp-low.h. */ + +int +tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +/* Encode 64 bits in 16 chars of hex. */ + +static const char hexchars[] = "0123456789abcdef"; + +static int +ishex (int ch, int *val) +{ + if ((ch >= 'a') && (ch <= 'f')) + { + *val = ch - 'a' + 10; + return 1; + } + if ((ch >= 'A') && (ch <= 'F')) + { + *val = ch - 'A' + 10; + return 1; + } + if ((ch >= '0') && (ch <= '9')) + { + *val = ch - '0'; + return 1; + } + return 0; +} + +/* See rsp-low.h. */ + +char * +pack_nibble (char *buf, int nibble) +{ + *buf++ = hexchars[(nibble & 0x0f)]; + return buf; +} + +/* See rsp-low.h. */ + +char * +pack_hex_byte (char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +/* See rsp-low.h. */ + +const char * +unpack_varlen_hex (const char *buff, /* packet to parse */ + ULONGEST *result) +{ + int nibble; + ULONGEST retval = 0; + + while (ishex (*buff, &nibble)) + { + buff++; + retval = retval << 4; + retval |= nibble & 0x0f; + } + *result = retval; + return buff; +} + +/* See rsp-low.h. */ + +int +hex2bin (const char *hex, gdb_byte *bin, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + if (hex[0] == 0 || hex[1] == 0) + { + /* Hex string is short, or of uneven length. + Return the count that has been converted so far. */ + return i; + } + *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + return i; +} + +/* See rsp-low.h. */ + +gdb::byte_vector +hex2bin (const char *hex) +{ + size_t bin_len = strlen (hex) / 2; + gdb::byte_vector bin (bin_len); + + hex2bin (hex, bin.data (), bin_len); + + return bin; +} + +/* See rsp-low.h. */ + +std::string +hex2str (const char *hex) +{ + return hex2str (hex, strlen (hex)); +} + +/* See rsp-low.h. */ + +std::string +hex2str (const char *hex, int count) +{ + std::string ret; + + ret.reserve (count); + for (size_t i = 0; i < count; ++i) + { + if (hex[0] == '\0' || hex[1] == '\0') + { + /* Hex string is short, or of uneven length. Return what we + have so far. */ + return ret; + } + ret += fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + + return ret; +} + +/* See rsp-low.h. */ + +int +bin2hex (const gdb_byte *bin, char *hex, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + +/* See rsp-low.h. */ + +std::string +bin2hex (const gdb_byte *bin, int count) +{ + std::string ret; + + ret.reserve (count * 2); + for (int i = 0; i < count; ++i) + { + ret += tohex ((*bin >> 4) & 0xf); + ret += tohex (*bin++ & 0xf); + } + + return ret; +} + +/* Return whether byte B needs escaping when sent as part of binary data. */ + +static int +needs_escaping (gdb_byte b) +{ + return b == '$' || b == '#' || b == '}' || b == '*'; +} + +/* See rsp-low.h. */ + +int +remote_escape_output (const gdb_byte *buffer, int len_units, int unit_size, + gdb_byte *out_buf, int *out_len_units, + int out_maxlen_bytes) +{ + int input_unit_index, output_byte_index = 0, byte_index_in_unit; + int number_escape_bytes_needed; + + /* Try to copy integral addressable memory units until + (1) we run out of space or + (2) we copied all of them. */ + for (input_unit_index = 0; + input_unit_index < len_units; + input_unit_index++) + { + /* Find out how many escape bytes we need for this unit. */ + number_escape_bytes_needed = 0; + for (byte_index_in_unit = 0; + byte_index_in_unit < unit_size; + byte_index_in_unit++) + { + int idx = input_unit_index * unit_size + byte_index_in_unit; + gdb_byte b = buffer[idx]; + if (needs_escaping (b)) + number_escape_bytes_needed++; + } + + /* Check if we have room to fit this escaped unit. */ + if (output_byte_index + unit_size + number_escape_bytes_needed > + out_maxlen_bytes) + break; + + /* Copy the unit byte per byte, adding escapes. */ + for (byte_index_in_unit = 0; + byte_index_in_unit < unit_size; + byte_index_in_unit++) + { + int idx = input_unit_index * unit_size + byte_index_in_unit; + gdb_byte b = buffer[idx]; + if (needs_escaping (b)) + { + out_buf[output_byte_index++] = '}'; + out_buf[output_byte_index++] = b ^ 0x20; + } + else + out_buf[output_byte_index++] = b; + } + } + + *out_len_units = input_unit_index; + return output_byte_index; +} + +/* See rsp-low.h. */ + +int +remote_unescape_input (const gdb_byte *buffer, int len, + gdb_byte *out_buf, int out_maxlen) +{ + int input_index, output_index; + int escaped; + + output_index = 0; + escaped = 0; + for (input_index = 0; input_index < len; input_index++) + { + gdb_byte b = buffer[input_index]; + + if (output_index + 1 > out_maxlen) + error (_("Received too much data from the target.")); + + if (escaped) + { + out_buf[output_index++] = b ^ 0x20; + escaped = 0; + } + else if (b == '}') + escaped = 1; + else + out_buf[output_index++] = b; + } + + if (escaped) + error (_("Unmatched escape character in target response.")); + + return output_index; +} + diff --git a/gdbsupport/run-time-clock.c b/gdbsupport/run-time-clock.c deleted file mode 100644 index 24dc19c..0000000 --- a/gdbsupport/run-time-clock.c +++ /dev/null @@ -1,58 +0,0 @@ -/* User/system CPU time clocks that follow the std::chrono interface. - Copyright (C) 2016-2020 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 . */ - -#include "common-defs.h" -#include "run-time-clock.h" -#if defined HAVE_SYS_RESOURCE_H -#include -#endif - -using namespace std::chrono; - -run_time_clock::time_point -run_time_clock::now () noexcept -{ - return time_point (microseconds (get_run_time ())); -} - -#ifdef HAVE_GETRUSAGE -static std::chrono::microseconds -timeval_to_microseconds (struct timeval *tv) -{ - return (seconds (tv->tv_sec) + microseconds (tv->tv_usec)); -} -#endif - -void -run_time_clock::now (user_cpu_time_clock::time_point &user, - system_cpu_time_clock::time_point &system) noexcept -{ -#ifdef HAVE_GETRUSAGE - struct rusage rusage; - - getrusage (RUSAGE_SELF, &rusage); - - microseconds utime = timeval_to_microseconds (&rusage.ru_utime); - microseconds stime = timeval_to_microseconds (&rusage.ru_stime); - user = user_cpu_time_clock::time_point (utime); - system = system_cpu_time_clock::time_point (stime); -#else - user = user_cpu_time_clock::time_point (microseconds (get_run_time ())); - system = system_cpu_time_clock::time_point (microseconds::zero ()); -#endif -} diff --git a/gdbsupport/run-time-clock.cc b/gdbsupport/run-time-clock.cc new file mode 100644 index 0000000..24dc19c --- /dev/null +++ b/gdbsupport/run-time-clock.cc @@ -0,0 +1,58 @@ +/* User/system CPU time clocks that follow the std::chrono interface. + Copyright (C) 2016-2020 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 . */ + +#include "common-defs.h" +#include "run-time-clock.h" +#if defined HAVE_SYS_RESOURCE_H +#include +#endif + +using namespace std::chrono; + +run_time_clock::time_point +run_time_clock::now () noexcept +{ + return time_point (microseconds (get_run_time ())); +} + +#ifdef HAVE_GETRUSAGE +static std::chrono::microseconds +timeval_to_microseconds (struct timeval *tv) +{ + return (seconds (tv->tv_sec) + microseconds (tv->tv_usec)); +} +#endif + +void +run_time_clock::now (user_cpu_time_clock::time_point &user, + system_cpu_time_clock::time_point &system) noexcept +{ +#ifdef HAVE_GETRUSAGE + struct rusage rusage; + + getrusage (RUSAGE_SELF, &rusage); + + microseconds utime = timeval_to_microseconds (&rusage.ru_utime); + microseconds stime = timeval_to_microseconds (&rusage.ru_stime); + user = user_cpu_time_clock::time_point (utime); + system = system_cpu_time_clock::time_point (stime); +#else + user = user_cpu_time_clock::time_point (microseconds (get_run_time ())); + system = system_cpu_time_clock::time_point (microseconds::zero ()); +#endif +} diff --git a/gdbsupport/safe-strerror.c b/gdbsupport/safe-strerror.c deleted file mode 100644 index 5804621..0000000 --- a/gdbsupport/safe-strerror.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Safe version of strerror for GDB, the GNU debugger. - - Copyright (C) 2006-2020 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 . */ - -#include "common-defs.h" -#include - -/* There are two different versions of strerror_r; one is GNU-specific, the - other XSI-compliant. They differ in the return type. This overload lets - us choose the right behavior for each return type. We cannot rely on Gnulib - to solve this for us because IPA does not use Gnulib but uses this - function. */ - -/* Called if we have a XSI-compliant strerror_r. */ -ATTRIBUTE_UNUSED static char * -select_strerror_r (int res, char *buf) -{ - return res == 0 ? buf : nullptr; -} - -/* Called if we have a GNU strerror_r. */ -ATTRIBUTE_UNUSED static char * -select_strerror_r (char *res, char *) -{ - return res; -} - -/* Implementation of safe_strerror as defined in common-utils.h. */ - -const char * -safe_strerror (int errnum) -{ - static thread_local char buf[1024]; - - char *res = select_strerror_r (strerror_r (errnum, buf, sizeof (buf)), buf); - if (res != nullptr) - return res; - - xsnprintf (buf, sizeof buf, "(undocumented errno %d)", errnum); - return buf; -} diff --git a/gdbsupport/safe-strerror.cc b/gdbsupport/safe-strerror.cc new file mode 100644 index 0000000..5804621 --- /dev/null +++ b/gdbsupport/safe-strerror.cc @@ -0,0 +1,56 @@ +/* Safe version of strerror for GDB, the GNU debugger. + + Copyright (C) 2006-2020 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 . */ + +#include "common-defs.h" +#include + +/* There are two different versions of strerror_r; one is GNU-specific, the + other XSI-compliant. They differ in the return type. This overload lets + us choose the right behavior for each return type. We cannot rely on Gnulib + to solve this for us because IPA does not use Gnulib but uses this + function. */ + +/* Called if we have a XSI-compliant strerror_r. */ +ATTRIBUTE_UNUSED static char * +select_strerror_r (int res, char *buf) +{ + return res == 0 ? buf : nullptr; +} + +/* Called if we have a GNU strerror_r. */ +ATTRIBUTE_UNUSED static char * +select_strerror_r (char *res, char *) +{ + return res; +} + +/* Implementation of safe_strerror as defined in common-utils.h. */ + +const char * +safe_strerror (int errnum) +{ + static thread_local char buf[1024]; + + char *res = select_strerror_r (strerror_r (errnum, buf, sizeof (buf)), buf); + if (res != nullptr) + return res; + + xsnprintf (buf, sizeof buf, "(undocumented errno %d)", errnum); + return buf; +} diff --git a/gdbsupport/scoped_mmap.c b/gdbsupport/scoped_mmap.c deleted file mode 100644 index 6b424dc..0000000 --- a/gdbsupport/scoped_mmap.c +++ /dev/null @@ -1,49 +0,0 @@ -/* scoped_mmap, automatically unmap files - - Copyright (C) 2018-2020 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 . */ - -#include "common-defs.h" -#include "scoped_mmap.h" -#include "scoped_fd.h" -#include "gdbsupport/filestuff.h" - -#ifdef HAVE_SYS_MMAN_H - -scoped_mmap -mmap_file (const char *filename) -{ - scoped_fd fd (gdb_open_cloexec (filename, O_RDONLY, 0)); - if (fd.get () < 0) - perror_with_name (("open")); - - off_t size = lseek (fd.get (), 0, SEEK_END); - if (size < 0) - perror_with_name (("lseek")); - - /* We can't map an empty file. */ - if (size == 0) - error (_("file to mmap is empty")); - - scoped_mmap mmapped_file (nullptr, size, PROT_READ, MAP_PRIVATE, fd.get (), 0); - if (mmapped_file.get () == MAP_FAILED) - perror_with_name (("mmap")); - - return mmapped_file; -} - -#endif /* HAVE_SYS_MMAN_H */ diff --git a/gdbsupport/scoped_mmap.cc b/gdbsupport/scoped_mmap.cc new file mode 100644 index 0000000..6b424dc --- /dev/null +++ b/gdbsupport/scoped_mmap.cc @@ -0,0 +1,49 @@ +/* scoped_mmap, automatically unmap files + + Copyright (C) 2018-2020 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 . */ + +#include "common-defs.h" +#include "scoped_mmap.h" +#include "scoped_fd.h" +#include "gdbsupport/filestuff.h" + +#ifdef HAVE_SYS_MMAN_H + +scoped_mmap +mmap_file (const char *filename) +{ + scoped_fd fd (gdb_open_cloexec (filename, O_RDONLY, 0)); + if (fd.get () < 0) + perror_with_name (("open")); + + off_t size = lseek (fd.get (), 0, SEEK_END); + if (size < 0) + perror_with_name (("lseek")); + + /* We can't map an empty file. */ + if (size == 0) + error (_("file to mmap is empty")); + + scoped_mmap mmapped_file (nullptr, size, PROT_READ, MAP_PRIVATE, fd.get (), 0); + if (mmapped_file.get () == MAP_FAILED) + perror_with_name (("mmap")); + + return mmapped_file; +} + +#endif /* HAVE_SYS_MMAN_H */ diff --git a/gdbsupport/selftest.c b/gdbsupport/selftest.c deleted file mode 100644 index 8ab63be..0000000 --- a/gdbsupport/selftest.c +++ /dev/null @@ -1,111 +0,0 @@ -/* GDB self-testing. - Copyright (C) 2016-2020 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 . */ - -#include "common-defs.h" -#include "common-exceptions.h" -#include "common-debug.h" -#include "selftest.h" -#include - -namespace selftests -{ -/* All the tests that have been registered. Using an std::map allows keeping - the order of tests stable and easily looking up whether a test name - exists. */ - -static std::map> tests; - -/* A selftest that calls the test function without arguments. */ - -struct simple_selftest : public selftest -{ - simple_selftest (self_test_function *function_) - : function (function_) - {} - - void operator() () const override - { - function (); - } - - self_test_function *function; -}; - -/* See selftest.h. */ - -void -register_test (const std::string &name, selftest *test) -{ - /* Check that no test with this name already exist. */ - gdb_assert (tests.find (name) == tests.end ()); - - tests[name] = std::unique_ptr (test); -} - -/* See selftest.h. */ - -void -register_test (const std::string &name, self_test_function *function) -{ - register_test (name, new simple_selftest (function)); -} - -/* See selftest.h. */ - -void -run_tests (const char *filter) -{ - int ran = 0, failed = 0; - - for (const auto &pair : tests) - { - const std::string &name = pair.first; - const std::unique_ptr &test = pair.second; - - if (filter != NULL && *filter != '\0' - && name.find (filter) == std::string::npos) - continue; - - try - { - debug_printf (_("Running selftest %s.\n"), name.c_str ()); - ++ran; - (*test) (); - } - catch (const gdb_exception_error &ex) - { - ++failed; - debug_printf ("Self test failed: %s\n", ex.what ()); - } - - reset (); - } - - debug_printf (_("Ran %d unit tests, %d failed\n"), - ran, failed); -} - -/* See selftest.h. */ - -void for_each_selftest (for_each_selftest_ftype func) -{ - for (const auto &pair : tests) - func (pair.first); -} - -} // namespace selftests diff --git a/gdbsupport/selftest.cc b/gdbsupport/selftest.cc new file mode 100644 index 0000000..8ab63be --- /dev/null +++ b/gdbsupport/selftest.cc @@ -0,0 +1,111 @@ +/* GDB self-testing. + Copyright (C) 2016-2020 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 . */ + +#include "common-defs.h" +#include "common-exceptions.h" +#include "common-debug.h" +#include "selftest.h" +#include + +namespace selftests +{ +/* All the tests that have been registered. Using an std::map allows keeping + the order of tests stable and easily looking up whether a test name + exists. */ + +static std::map> tests; + +/* A selftest that calls the test function without arguments. */ + +struct simple_selftest : public selftest +{ + simple_selftest (self_test_function *function_) + : function (function_) + {} + + void operator() () const override + { + function (); + } + + self_test_function *function; +}; + +/* See selftest.h. */ + +void +register_test (const std::string &name, selftest *test) +{ + /* Check that no test with this name already exist. */ + gdb_assert (tests.find (name) == tests.end ()); + + tests[name] = std::unique_ptr (test); +} + +/* See selftest.h. */ + +void +register_test (const std::string &name, self_test_function *function) +{ + register_test (name, new simple_selftest (function)); +} + +/* See selftest.h. */ + +void +run_tests (const char *filter) +{ + int ran = 0, failed = 0; + + for (const auto &pair : tests) + { + const std::string &name = pair.first; + const std::unique_ptr &test = pair.second; + + if (filter != NULL && *filter != '\0' + && name.find (filter) == std::string::npos) + continue; + + try + { + debug_printf (_("Running selftest %s.\n"), name.c_str ()); + ++ran; + (*test) (); + } + catch (const gdb_exception_error &ex) + { + ++failed; + debug_printf ("Self test failed: %s\n", ex.what ()); + } + + reset (); + } + + debug_printf (_("Ran %d unit tests, %d failed\n"), + ran, failed); +} + +/* See selftest.h. */ + +void for_each_selftest (for_each_selftest_ftype func) +{ + for (const auto &pair : tests) + func (pair.first); +} + +} // namespace selftests diff --git a/gdbsupport/signals-state-save-restore.c b/gdbsupport/signals-state-save-restore.c deleted file mode 100644 index c292d49..0000000 --- a/gdbsupport/signals-state-save-restore.c +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (C) 2016-2020 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 . */ - -#include "common-defs.h" -#include "signals-state-save-restore.h" -#include "gdbsupport/gdb-sigmask.h" - -#include - -/* The original signal actions and mask. */ - -#ifdef HAVE_SIGACTION -static struct sigaction original_signal_actions[NSIG]; - -static sigset_t original_signal_mask; -#endif - -/* See signals-state-save-restore.h. */ - -void -save_original_signals_state (bool quiet) -{ -#ifdef HAVE_SIGACTION - int i; - int res; - - res = gdb_sigmask (0, NULL, &original_signal_mask); - if (res == -1) - perror_with_name (("sigprocmask")); - - bool found_preinstalled = false; - - for (i = 1; i < NSIG; i++) - { - struct sigaction *oldact = &original_signal_actions[i]; - - res = sigaction (i, NULL, oldact); - if (res == -1 && errno == EINVAL) - { - /* Some signal numbers in the range are invalid. */ - continue; - } - else if (res == -1) - perror_with_name (("sigaction")); - - /* If we find a custom signal handler already installed, then - this function was called too late. This is a warning instead - of an internal error because this can also happen if you - LD_PRELOAD a library that installs a signal handler early via - __attribute__((constructor)), like libSegFault.so. */ - if (!quiet - && oldact->sa_handler != SIG_DFL - && oldact->sa_handler != SIG_IGN) - { - found_preinstalled = true; - - /* Use raw fprintf here because we're being called in early - startup, before GDB's filtered streams are created. */ - fprintf (stderr, - _("warning: Found custom handler for signal " - "%d (%s) preinstalled.\n"), i, - strsignal (i)); - } - } - - if (found_preinstalled) - { - fprintf (stderr, _("\ -Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)\n\ -won't be propagated to spawned programs.\n")); - } -#endif -} - -/* See signals-state-save-restore.h. */ - -void -restore_original_signals_state (void) -{ -#ifdef HAVE_SIGACTION - int i; - int res; - - for (i = 1; i < NSIG; i++) - { - res = sigaction (i, &original_signal_actions[i], NULL); - if (res == -1 && errno == EINVAL) - { - /* Some signal numbers in the range are invalid. */ - continue; - } - else if (res == -1) - perror_with_name (("sigaction")); - } - - res = gdb_sigmask (SIG_SETMASK, &original_signal_mask, NULL); - if (res == -1) - perror_with_name (("sigprocmask")); -#endif -} diff --git a/gdbsupport/signals-state-save-restore.cc b/gdbsupport/signals-state-save-restore.cc new file mode 100644 index 0000000..c292d49 --- /dev/null +++ b/gdbsupport/signals-state-save-restore.cc @@ -0,0 +1,114 @@ +/* Copyright (C) 2016-2020 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 . */ + +#include "common-defs.h" +#include "signals-state-save-restore.h" +#include "gdbsupport/gdb-sigmask.h" + +#include + +/* The original signal actions and mask. */ + +#ifdef HAVE_SIGACTION +static struct sigaction original_signal_actions[NSIG]; + +static sigset_t original_signal_mask; +#endif + +/* See signals-state-save-restore.h. */ + +void +save_original_signals_state (bool quiet) +{ +#ifdef HAVE_SIGACTION + int i; + int res; + + res = gdb_sigmask (0, NULL, &original_signal_mask); + if (res == -1) + perror_with_name (("sigprocmask")); + + bool found_preinstalled = false; + + for (i = 1; i < NSIG; i++) + { + struct sigaction *oldact = &original_signal_actions[i]; + + res = sigaction (i, NULL, oldact); + if (res == -1 && errno == EINVAL) + { + /* Some signal numbers in the range are invalid. */ + continue; + } + else if (res == -1) + perror_with_name (("sigaction")); + + /* If we find a custom signal handler already installed, then + this function was called too late. This is a warning instead + of an internal error because this can also happen if you + LD_PRELOAD a library that installs a signal handler early via + __attribute__((constructor)), like libSegFault.so. */ + if (!quiet + && oldact->sa_handler != SIG_DFL + && oldact->sa_handler != SIG_IGN) + { + found_preinstalled = true; + + /* Use raw fprintf here because we're being called in early + startup, before GDB's filtered streams are created. */ + fprintf (stderr, + _("warning: Found custom handler for signal " + "%d (%s) preinstalled.\n"), i, + strsignal (i)); + } + } + + if (found_preinstalled) + { + fprintf (stderr, _("\ +Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)\n\ +won't be propagated to spawned programs.\n")); + } +#endif +} + +/* See signals-state-save-restore.h. */ + +void +restore_original_signals_state (void) +{ +#ifdef HAVE_SIGACTION + int i; + int res; + + for (i = 1; i < NSIG; i++) + { + res = sigaction (i, &original_signal_actions[i], NULL); + if (res == -1 && errno == EINVAL) + { + /* Some signal numbers in the range are invalid. */ + continue; + } + else if (res == -1) + perror_with_name (("sigaction")); + } + + res = gdb_sigmask (SIG_SETMASK, &original_signal_mask, NULL); + if (res == -1) + perror_with_name (("sigprocmask")); +#endif +} diff --git a/gdbsupport/signals.c b/gdbsupport/signals.c deleted file mode 100644 index 485e0f0..0000000 --- a/gdbsupport/signals.c +++ /dev/null @@ -1,653 +0,0 @@ -/* Target signal translation functions for GDB. - Copyright (C) 1990-2020 Free Software Foundation, Inc. - Contributed by Cygnus Support. - - 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 . */ - -#include "common-defs.h" - -#ifdef HAVE_SIGNAL_H -#include -#endif - -#include "gdb_signals.h" - -struct gdbarch; - -/* Always use __SIGRTMIN if it's available. SIGRTMIN is the lowest - _available_ realtime signal, not the lowest supported; glibc takes - several for its own use. */ - -#ifndef REALTIME_LO -# if defined(__SIGRTMIN) -# define REALTIME_LO __SIGRTMIN -# define REALTIME_HI (__SIGRTMAX + 1) -# elif defined(SIGRTMIN) -# define REALTIME_LO SIGRTMIN -# define REALTIME_HI (SIGRTMAX + 1) -# endif -#endif - -/* This table must match in order and size the signals in enum - gdb_signal. */ - -static const struct { - const char *symbol; - const char *name; - const char *string; - } signals [] = -{ -#define SET(symbol, constant, name, string) { #symbol, name, string }, -#include "gdb/signals.def" -#undef SET -}; - -const char * -gdb_signal_to_symbol_string (enum gdb_signal sig) -{ - gdb_assert ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST); - - return signals[sig].symbol; -} - -/* Return the string for a signal. */ -const char * -gdb_signal_to_string (enum gdb_signal sig) -{ - if ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST) - return signals[sig].string; - else - return signals[GDB_SIGNAL_UNKNOWN].string; -} - -/* Return the name for a signal. */ -const char * -gdb_signal_to_name (enum gdb_signal sig) -{ - if ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST - && signals[sig].name != NULL) - return signals[sig].name; - else - /* I think the code which prints this will always print it along - with the string, so no need to be verbose (very old comment). */ - return "?"; -} - -/* Given a name, return its signal. */ -enum gdb_signal -gdb_signal_from_name (const char *name) -{ - enum gdb_signal sig; - - /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD" - for GDB_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more - questionable; seems like by now people should call it SIGABRT - instead. */ - - /* This ugly cast brought to you by the native VAX compiler. */ - for (sig = GDB_SIGNAL_HUP; - sig < GDB_SIGNAL_LAST; - sig = (enum gdb_signal) ((int) sig + 1)) - if (signals[sig].name != NULL - && strcmp (name, signals[sig].name) == 0) - return sig; - return GDB_SIGNAL_UNKNOWN; -} - -/* The following functions are to help certain targets deal - with the signal/waitstatus stuff. They could just as well be in - a file called native-utils.c or unixwaitstatus-utils.c or whatever. */ - -/* Convert host signal to our signals. */ -enum gdb_signal -gdb_signal_from_host (int hostsig) -{ - /* A switch statement would make sense but would require special - kludges to deal with the cases where more than one signal has the - same number. Signals are ordered ANSI-standard signals first, - other signals second, with signals in each block ordered by their - numerical values on a typical POSIX platform. */ - - if (hostsig == 0) - return GDB_SIGNAL_0; - - /* SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV and SIGTERM - are ANSI-standard signals and are always available. */ - if (hostsig == SIGINT) - return GDB_SIGNAL_INT; - if (hostsig == SIGILL) - return GDB_SIGNAL_ILL; - if (hostsig == SIGABRT) - return GDB_SIGNAL_ABRT; - if (hostsig == SIGFPE) - return GDB_SIGNAL_FPE; - if (hostsig == SIGSEGV) - return GDB_SIGNAL_SEGV; - if (hostsig == SIGTERM) - return GDB_SIGNAL_TERM; - - /* All other signals need preprocessor conditionals. */ -#if defined (SIGHUP) - if (hostsig == SIGHUP) - return GDB_SIGNAL_HUP; -#endif -#if defined (SIGQUIT) - if (hostsig == SIGQUIT) - return GDB_SIGNAL_QUIT; -#endif -#if defined (SIGTRAP) - if (hostsig == SIGTRAP) - return GDB_SIGNAL_TRAP; -#endif -#if defined (SIGEMT) - if (hostsig == SIGEMT) - return GDB_SIGNAL_EMT; -#endif -#if defined (SIGKILL) - if (hostsig == SIGKILL) - return GDB_SIGNAL_KILL; -#endif -#if defined (SIGBUS) - if (hostsig == SIGBUS) - return GDB_SIGNAL_BUS; -#endif -#if defined (SIGSYS) - if (hostsig == SIGSYS) - return GDB_SIGNAL_SYS; -#endif -#if defined (SIGPIPE) - if (hostsig == SIGPIPE) - return GDB_SIGNAL_PIPE; -#endif -#if defined (SIGALRM) - if (hostsig == SIGALRM) - return GDB_SIGNAL_ALRM; -#endif -#if defined (SIGUSR1) - if (hostsig == SIGUSR1) - return GDB_SIGNAL_USR1; -#endif -#if defined (SIGUSR2) - if (hostsig == SIGUSR2) - return GDB_SIGNAL_USR2; -#endif -#if defined (SIGCLD) - if (hostsig == SIGCLD) - return GDB_SIGNAL_CHLD; -#endif -#if defined (SIGCHLD) - if (hostsig == SIGCHLD) - return GDB_SIGNAL_CHLD; -#endif -#if defined (SIGPWR) - if (hostsig == SIGPWR) - return GDB_SIGNAL_PWR; -#endif -#if defined (SIGWINCH) - if (hostsig == SIGWINCH) - return GDB_SIGNAL_WINCH; -#endif -#if defined (SIGURG) - if (hostsig == SIGURG) - return GDB_SIGNAL_URG; -#endif -#if defined (SIGIO) - if (hostsig == SIGIO) - return GDB_SIGNAL_IO; -#endif -#if defined (SIGPOLL) - if (hostsig == SIGPOLL) - return GDB_SIGNAL_POLL; -#endif -#if defined (SIGSTOP) - if (hostsig == SIGSTOP) - return GDB_SIGNAL_STOP; -#endif -#if defined (SIGTSTP) - if (hostsig == SIGTSTP) - return GDB_SIGNAL_TSTP; -#endif -#if defined (SIGCONT) - if (hostsig == SIGCONT) - return GDB_SIGNAL_CONT; -#endif -#if defined (SIGTTIN) - if (hostsig == SIGTTIN) - return GDB_SIGNAL_TTIN; -#endif -#if defined (SIGTTOU) - if (hostsig == SIGTTOU) - return GDB_SIGNAL_TTOU; -#endif -#if defined (SIGVTALRM) - if (hostsig == SIGVTALRM) - return GDB_SIGNAL_VTALRM; -#endif -#if defined (SIGPROF) - if (hostsig == SIGPROF) - return GDB_SIGNAL_PROF; -#endif -#if defined (SIGXCPU) - if (hostsig == SIGXCPU) - return GDB_SIGNAL_XCPU; -#endif -#if defined (SIGXFSZ) - if (hostsig == SIGXFSZ) - return GDB_SIGNAL_XFSZ; -#endif -#if defined (SIGWIND) - if (hostsig == SIGWIND) - return GDB_SIGNAL_WIND; -#endif -#if defined (SIGPHONE) - if (hostsig == SIGPHONE) - return GDB_SIGNAL_PHONE; -#endif -#if defined (SIGLOST) - if (hostsig == SIGLOST) - return GDB_SIGNAL_LOST; -#endif -#if defined (SIGWAITING) - if (hostsig == SIGWAITING) - return GDB_SIGNAL_WAITING; -#endif -#if defined (SIGCANCEL) - if (hostsig == SIGCANCEL) - return GDB_SIGNAL_CANCEL; -#endif -#if defined (SIGLWP) - if (hostsig == SIGLWP) - return GDB_SIGNAL_LWP; -#endif -#if defined (SIGDANGER) - if (hostsig == SIGDANGER) - return GDB_SIGNAL_DANGER; -#endif -#if defined (SIGGRANT) - if (hostsig == SIGGRANT) - return GDB_SIGNAL_GRANT; -#endif -#if defined (SIGRETRACT) - if (hostsig == SIGRETRACT) - return GDB_SIGNAL_RETRACT; -#endif -#if defined (SIGMSG) - if (hostsig == SIGMSG) - return GDB_SIGNAL_MSG; -#endif -#if defined (SIGSOUND) - if (hostsig == SIGSOUND) - return GDB_SIGNAL_SOUND; -#endif -#if defined (SIGSAK) - if (hostsig == SIGSAK) - return GDB_SIGNAL_SAK; -#endif -#if defined (SIGPRIO) - if (hostsig == SIGPRIO) - return GDB_SIGNAL_PRIO; -#endif - - /* Mach exceptions. Assumes that the values for EXC_ are positive! */ -#if defined (EXC_BAD_ACCESS) && defined (_NSIG) - if (hostsig == _NSIG + EXC_BAD_ACCESS) - return GDB_EXC_BAD_ACCESS; -#endif -#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG) - if (hostsig == _NSIG + EXC_BAD_INSTRUCTION) - return GDB_EXC_BAD_INSTRUCTION; -#endif -#if defined (EXC_ARITHMETIC) && defined (_NSIG) - if (hostsig == _NSIG + EXC_ARITHMETIC) - return GDB_EXC_ARITHMETIC; -#endif -#if defined (EXC_EMULATION) && defined (_NSIG) - if (hostsig == _NSIG + EXC_EMULATION) - return GDB_EXC_EMULATION; -#endif -#if defined (EXC_SOFTWARE) && defined (_NSIG) - if (hostsig == _NSIG + EXC_SOFTWARE) - return GDB_EXC_SOFTWARE; -#endif -#if defined (EXC_BREAKPOINT) && defined (_NSIG) - if (hostsig == _NSIG + EXC_BREAKPOINT) - return GDB_EXC_BREAKPOINT; -#endif - -#if defined (SIGINFO) - if (hostsig == SIGINFO) - return GDB_SIGNAL_INFO; -#endif -#if defined (SIGLIBRT) - if (hostsig == SIGLIBRT) - return GDB_SIGNAL_LIBRT; -#endif - -#if defined (REALTIME_LO) - if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI) - { - /* This block of GDB_SIGNAL_REALTIME value is in order. */ - if (33 <= hostsig && hostsig <= 63) - return (enum gdb_signal) - (hostsig - 33 + (int) GDB_SIGNAL_REALTIME_33); - else if (hostsig == 32) - return GDB_SIGNAL_REALTIME_32; - else if (64 <= hostsig && hostsig <= 127) - return (enum gdb_signal) - (hostsig - 64 + (int) GDB_SIGNAL_REALTIME_64); - else - error (_("GDB bug: target.c (gdb_signal_from_host): " - "unrecognized real-time signal")); - } -#endif - - return GDB_SIGNAL_UNKNOWN; -} - -/* Convert a OURSIG (an enum gdb_signal) to the form used by the - target operating system (refered to as the ``host'') or zero if the - equivalent host signal is not available. Set/clear OURSIG_OK - accordingly. */ - -static int -do_gdb_signal_to_host (enum gdb_signal oursig, - int *oursig_ok) -{ - int retsig; - /* Silence the 'not used' warning, for targets that - do not support signals. */ - (void) retsig; - - /* Signals are ordered ANSI-standard signals first, other signals - second, with signals in each block ordered by their numerical - values on a typical POSIX platform. */ - - *oursig_ok = 1; - switch (oursig) - { - case GDB_SIGNAL_0: - return 0; - - /* SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV and SIGTERM - are ANSI-standard signals and are always available. */ - case GDB_SIGNAL_INT: - return SIGINT; - case GDB_SIGNAL_ILL: - return SIGILL; - case GDB_SIGNAL_ABRT: - return SIGABRT; - case GDB_SIGNAL_FPE: - return SIGFPE; - case GDB_SIGNAL_SEGV: - return SIGSEGV; - case GDB_SIGNAL_TERM: - return SIGTERM; - - /* All other signals need preprocessor conditionals. */ -#if defined (SIGHUP) - case GDB_SIGNAL_HUP: - return SIGHUP; -#endif -#if defined (SIGQUIT) - case GDB_SIGNAL_QUIT: - return SIGQUIT; -#endif -#if defined (SIGTRAP) - case GDB_SIGNAL_TRAP: - return SIGTRAP; -#endif -#if defined (SIGEMT) - case GDB_SIGNAL_EMT: - return SIGEMT; -#endif -#if defined (SIGKILL) - case GDB_SIGNAL_KILL: - return SIGKILL; -#endif -#if defined (SIGBUS) - case GDB_SIGNAL_BUS: - return SIGBUS; -#endif -#if defined (SIGSYS) - case GDB_SIGNAL_SYS: - return SIGSYS; -#endif -#if defined (SIGPIPE) - case GDB_SIGNAL_PIPE: - return SIGPIPE; -#endif -#if defined (SIGALRM) - case GDB_SIGNAL_ALRM: - return SIGALRM; -#endif -#if defined (SIGUSR1) - case GDB_SIGNAL_USR1: - return SIGUSR1; -#endif -#if defined (SIGUSR2) - case GDB_SIGNAL_USR2: - return SIGUSR2; -#endif -#if defined (SIGCHLD) || defined (SIGCLD) - case GDB_SIGNAL_CHLD: -#if defined (SIGCHLD) - return SIGCHLD; -#else - return SIGCLD; -#endif -#endif /* SIGCLD or SIGCHLD */ -#if defined (SIGPWR) - case GDB_SIGNAL_PWR: - return SIGPWR; -#endif -#if defined (SIGWINCH) - case GDB_SIGNAL_WINCH: - return SIGWINCH; -#endif -#if defined (SIGURG) - case GDB_SIGNAL_URG: - return SIGURG; -#endif -#if defined (SIGIO) - case GDB_SIGNAL_IO: - return SIGIO; -#endif -#if defined (SIGPOLL) - case GDB_SIGNAL_POLL: - return SIGPOLL; -#endif -#if defined (SIGSTOP) - case GDB_SIGNAL_STOP: - return SIGSTOP; -#endif -#if defined (SIGTSTP) - case GDB_SIGNAL_TSTP: - return SIGTSTP; -#endif -#if defined (SIGCONT) - case GDB_SIGNAL_CONT: - return SIGCONT; -#endif -#if defined (SIGTTIN) - case GDB_SIGNAL_TTIN: - return SIGTTIN; -#endif -#if defined (SIGTTOU) - case GDB_SIGNAL_TTOU: - return SIGTTOU; -#endif -#if defined (SIGVTALRM) - case GDB_SIGNAL_VTALRM: - return SIGVTALRM; -#endif -#if defined (SIGPROF) - case GDB_SIGNAL_PROF: - return SIGPROF; -#endif -#if defined (SIGXCPU) - case GDB_SIGNAL_XCPU: - return SIGXCPU; -#endif -#if defined (SIGXFSZ) - case GDB_SIGNAL_XFSZ: - return SIGXFSZ; -#endif -#if defined (SIGWIND) - case GDB_SIGNAL_WIND: - return SIGWIND; -#endif -#if defined (SIGPHONE) - case GDB_SIGNAL_PHONE: - return SIGPHONE; -#endif -#if defined (SIGLOST) - case GDB_SIGNAL_LOST: - return SIGLOST; -#endif -#if defined (SIGWAITING) - case GDB_SIGNAL_WAITING: - return SIGWAITING; -#endif -#if defined (SIGCANCEL) - case GDB_SIGNAL_CANCEL: - return SIGCANCEL; -#endif -#if defined (SIGLWP) - case GDB_SIGNAL_LWP: - return SIGLWP; -#endif -#if defined (SIGDANGER) - case GDB_SIGNAL_DANGER: - return SIGDANGER; -#endif -#if defined (SIGGRANT) - case GDB_SIGNAL_GRANT: - return SIGGRANT; -#endif -#if defined (SIGRETRACT) - case GDB_SIGNAL_RETRACT: - return SIGRETRACT; -#endif -#if defined (SIGMSG) - case GDB_SIGNAL_MSG: - return SIGMSG; -#endif -#if defined (SIGSOUND) - case GDB_SIGNAL_SOUND: - return SIGSOUND; -#endif -#if defined (SIGSAK) - case GDB_SIGNAL_SAK: - return SIGSAK; -#endif -#if defined (SIGPRIO) - case GDB_SIGNAL_PRIO: - return SIGPRIO; -#endif - - /* Mach exceptions. Assumes that the values for EXC_ are positive! */ -#if defined (EXC_BAD_ACCESS) && defined (_NSIG) - case GDB_EXC_BAD_ACCESS: - return _NSIG + EXC_BAD_ACCESS; -#endif -#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG) - case GDB_EXC_BAD_INSTRUCTION: - return _NSIG + EXC_BAD_INSTRUCTION; -#endif -#if defined (EXC_ARITHMETIC) && defined (_NSIG) - case GDB_EXC_ARITHMETIC: - return _NSIG + EXC_ARITHMETIC; -#endif -#if defined (EXC_EMULATION) && defined (_NSIG) - case GDB_EXC_EMULATION: - return _NSIG + EXC_EMULATION; -#endif -#if defined (EXC_SOFTWARE) && defined (_NSIG) - case GDB_EXC_SOFTWARE: - return _NSIG + EXC_SOFTWARE; -#endif -#if defined (EXC_BREAKPOINT) && defined (_NSIG) - case GDB_EXC_BREAKPOINT: - return _NSIG + EXC_BREAKPOINT; -#endif - -#if defined (SIGINFO) - case GDB_SIGNAL_INFO: - return SIGINFO; -#endif -#if defined (SIGLIBRT) - case GDB_SIGNAL_LIBRT: - return SIGLIBRT; -#endif - - default: -#if defined (REALTIME_LO) - retsig = 0; - - if (oursig >= GDB_SIGNAL_REALTIME_33 - && oursig <= GDB_SIGNAL_REALTIME_63) - { - /* This block of signals is continuous, and - GDB_SIGNAL_REALTIME_33 is 33 by definition. */ - retsig = (int) oursig - (int) GDB_SIGNAL_REALTIME_33 + 33; - } - else if (oursig == GDB_SIGNAL_REALTIME_32) - { - /* GDB_SIGNAL_REALTIME_32 isn't contiguous with - GDB_SIGNAL_REALTIME_33. It is 32 by definition. */ - retsig = 32; - } - else if (oursig >= GDB_SIGNAL_REALTIME_64 - && oursig <= GDB_SIGNAL_REALTIME_127) - { - /* This block of signals is continuous, and - GDB_SIGNAL_REALTIME_64 is 64 by definition. */ - retsig = (int) oursig - (int) GDB_SIGNAL_REALTIME_64 + 64; - } - - if (retsig >= REALTIME_LO && retsig < REALTIME_HI) - return retsig; -#endif - - *oursig_ok = 0; - return 0; - } -} - -int -gdb_signal_to_host_p (enum gdb_signal oursig) -{ - int oursig_ok; - do_gdb_signal_to_host (oursig, &oursig_ok); - return oursig_ok; -} - -int -gdb_signal_to_host (enum gdb_signal oursig) -{ - int oursig_ok; - int targ_signo = do_gdb_signal_to_host (oursig, &oursig_ok); - if (!oursig_ok) - { - /* The user might be trying to do "signal SIGSAK" where this system - doesn't have SIGSAK. */ - warning (_("Signal %s does not exist on this system."), - gdb_signal_to_name (oursig)); - return 0; - } - else - return targ_signo; -} diff --git a/gdbsupport/signals.cc b/gdbsupport/signals.cc new file mode 100644 index 0000000..485e0f0 --- /dev/null +++ b/gdbsupport/signals.cc @@ -0,0 +1,653 @@ +/* Target signal translation functions for GDB. + Copyright (C) 1990-2020 Free Software Foundation, Inc. + Contributed by Cygnus Support. + + 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 . */ + +#include "common-defs.h" + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include "gdb_signals.h" + +struct gdbarch; + +/* Always use __SIGRTMIN if it's available. SIGRTMIN is the lowest + _available_ realtime signal, not the lowest supported; glibc takes + several for its own use. */ + +#ifndef REALTIME_LO +# if defined(__SIGRTMIN) +# define REALTIME_LO __SIGRTMIN +# define REALTIME_HI (__SIGRTMAX + 1) +# elif defined(SIGRTMIN) +# define REALTIME_LO SIGRTMIN +# define REALTIME_HI (SIGRTMAX + 1) +# endif +#endif + +/* This table must match in order and size the signals in enum + gdb_signal. */ + +static const struct { + const char *symbol; + const char *name; + const char *string; + } signals [] = +{ +#define SET(symbol, constant, name, string) { #symbol, name, string }, +#include "gdb/signals.def" +#undef SET +}; + +const char * +gdb_signal_to_symbol_string (enum gdb_signal sig) +{ + gdb_assert ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST); + + return signals[sig].symbol; +} + +/* Return the string for a signal. */ +const char * +gdb_signal_to_string (enum gdb_signal sig) +{ + if ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST) + return signals[sig].string; + else + return signals[GDB_SIGNAL_UNKNOWN].string; +} + +/* Return the name for a signal. */ +const char * +gdb_signal_to_name (enum gdb_signal sig) +{ + if ((int) sig >= GDB_SIGNAL_FIRST && (int) sig <= GDB_SIGNAL_LAST + && signals[sig].name != NULL) + return signals[sig].name; + else + /* I think the code which prints this will always print it along + with the string, so no need to be verbose (very old comment). */ + return "?"; +} + +/* Given a name, return its signal. */ +enum gdb_signal +gdb_signal_from_name (const char *name) +{ + enum gdb_signal sig; + + /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD" + for GDB_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more + questionable; seems like by now people should call it SIGABRT + instead. */ + + /* This ugly cast brought to you by the native VAX compiler. */ + for (sig = GDB_SIGNAL_HUP; + sig < GDB_SIGNAL_LAST; + sig = (enum gdb_signal) ((int) sig + 1)) + if (signals[sig].name != NULL + && strcmp (name, signals[sig].name) == 0) + return sig; + return GDB_SIGNAL_UNKNOWN; +} + +/* The following functions are to help certain targets deal + with the signal/waitstatus stuff. They could just as well be in + a file called native-utils.c or unixwaitstatus-utils.c or whatever. */ + +/* Convert host signal to our signals. */ +enum gdb_signal +gdb_signal_from_host (int hostsig) +{ + /* A switch statement would make sense but would require special + kludges to deal with the cases where more than one signal has the + same number. Signals are ordered ANSI-standard signals first, + other signals second, with signals in each block ordered by their + numerical values on a typical POSIX platform. */ + + if (hostsig == 0) + return GDB_SIGNAL_0; + + /* SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV and SIGTERM + are ANSI-standard signals and are always available. */ + if (hostsig == SIGINT) + return GDB_SIGNAL_INT; + if (hostsig == SIGILL) + return GDB_SIGNAL_ILL; + if (hostsig == SIGABRT) + return GDB_SIGNAL_ABRT; + if (hostsig == SIGFPE) + return GDB_SIGNAL_FPE; + if (hostsig == SIGSEGV) + return GDB_SIGNAL_SEGV; + if (hostsig == SIGTERM) + return GDB_SIGNAL_TERM; + + /* All other signals need preprocessor conditionals. */ +#if defined (SIGHUP) + if (hostsig == SIGHUP) + return GDB_SIGNAL_HUP; +#endif +#if defined (SIGQUIT) + if (hostsig == SIGQUIT) + return GDB_SIGNAL_QUIT; +#endif +#if defined (SIGTRAP) + if (hostsig == SIGTRAP) + return GDB_SIGNAL_TRAP; +#endif +#if defined (SIGEMT) + if (hostsig == SIGEMT) + return GDB_SIGNAL_EMT; +#endif +#if defined (SIGKILL) + if (hostsig == SIGKILL) + return GDB_SIGNAL_KILL; +#endif +#if defined (SIGBUS) + if (hostsig == SIGBUS) + return GDB_SIGNAL_BUS; +#endif +#if defined (SIGSYS) + if (hostsig == SIGSYS) + return GDB_SIGNAL_SYS; +#endif +#if defined (SIGPIPE) + if (hostsig == SIGPIPE) + return GDB_SIGNAL_PIPE; +#endif +#if defined (SIGALRM) + if (hostsig == SIGALRM) + return GDB_SIGNAL_ALRM; +#endif +#if defined (SIGUSR1) + if (hostsig == SIGUSR1) + return GDB_SIGNAL_USR1; +#endif +#if defined (SIGUSR2) + if (hostsig == SIGUSR2) + return GDB_SIGNAL_USR2; +#endif +#if defined (SIGCLD) + if (hostsig == SIGCLD) + return GDB_SIGNAL_CHLD; +#endif +#if defined (SIGCHLD) + if (hostsig == SIGCHLD) + return GDB_SIGNAL_CHLD; +#endif +#if defined (SIGPWR) + if (hostsig == SIGPWR) + return GDB_SIGNAL_PWR; +#endif +#if defined (SIGWINCH) + if (hostsig == SIGWINCH) + return GDB_SIGNAL_WINCH; +#endif +#if defined (SIGURG) + if (hostsig == SIGURG) + return GDB_SIGNAL_URG; +#endif +#if defined (SIGIO) + if (hostsig == SIGIO) + return GDB_SIGNAL_IO; +#endif +#if defined (SIGPOLL) + if (hostsig == SIGPOLL) + return GDB_SIGNAL_POLL; +#endif +#if defined (SIGSTOP) + if (hostsig == SIGSTOP) + return GDB_SIGNAL_STOP; +#endif +#if defined (SIGTSTP) + if (hostsig == SIGTSTP) + return GDB_SIGNAL_TSTP; +#endif +#if defined (SIGCONT) + if (hostsig == SIGCONT) + return GDB_SIGNAL_CONT; +#endif +#if defined (SIGTTIN) + if (hostsig == SIGTTIN) + return GDB_SIGNAL_TTIN; +#endif +#if defined (SIGTTOU) + if (hostsig == SIGTTOU) + return GDB_SIGNAL_TTOU; +#endif +#if defined (SIGVTALRM) + if (hostsig == SIGVTALRM) + return GDB_SIGNAL_VTALRM; +#endif +#if defined (SIGPROF) + if (hostsig == SIGPROF) + return GDB_SIGNAL_PROF; +#endif +#if defined (SIGXCPU) + if (hostsig == SIGXCPU) + return GDB_SIGNAL_XCPU; +#endif +#if defined (SIGXFSZ) + if (hostsig == SIGXFSZ) + return GDB_SIGNAL_XFSZ; +#endif +#if defined (SIGWIND) + if (hostsig == SIGWIND) + return GDB_SIGNAL_WIND; +#endif +#if defined (SIGPHONE) + if (hostsig == SIGPHONE) + return GDB_SIGNAL_PHONE; +#endif +#if defined (SIGLOST) + if (hostsig == SIGLOST) + return GDB_SIGNAL_LOST; +#endif +#if defined (SIGWAITING) + if (hostsig == SIGWAITING) + return GDB_SIGNAL_WAITING; +#endif +#if defined (SIGCANCEL) + if (hostsig == SIGCANCEL) + return GDB_SIGNAL_CANCEL; +#endif +#if defined (SIGLWP) + if (hostsig == SIGLWP) + return GDB_SIGNAL_LWP; +#endif +#if defined (SIGDANGER) + if (hostsig == SIGDANGER) + return GDB_SIGNAL_DANGER; +#endif +#if defined (SIGGRANT) + if (hostsig == SIGGRANT) + return GDB_SIGNAL_GRANT; +#endif +#if defined (SIGRETRACT) + if (hostsig == SIGRETRACT) + return GDB_SIGNAL_RETRACT; +#endif +#if defined (SIGMSG) + if (hostsig == SIGMSG) + return GDB_SIGNAL_MSG; +#endif +#if defined (SIGSOUND) + if (hostsig == SIGSOUND) + return GDB_SIGNAL_SOUND; +#endif +#if defined (SIGSAK) + if (hostsig == SIGSAK) + return GDB_SIGNAL_SAK; +#endif +#if defined (SIGPRIO) + if (hostsig == SIGPRIO) + return GDB_SIGNAL_PRIO; +#endif + + /* Mach exceptions. Assumes that the values for EXC_ are positive! */ +#if defined (EXC_BAD_ACCESS) && defined (_NSIG) + if (hostsig == _NSIG + EXC_BAD_ACCESS) + return GDB_EXC_BAD_ACCESS; +#endif +#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG) + if (hostsig == _NSIG + EXC_BAD_INSTRUCTION) + return GDB_EXC_BAD_INSTRUCTION; +#endif +#if defined (EXC_ARITHMETIC) && defined (_NSIG) + if (hostsig == _NSIG + EXC_ARITHMETIC) + return GDB_EXC_ARITHMETIC; +#endif +#if defined (EXC_EMULATION) && defined (_NSIG) + if (hostsig == _NSIG + EXC_EMULATION) + return GDB_EXC_EMULATION; +#endif +#if defined (EXC_SOFTWARE) && defined (_NSIG) + if (hostsig == _NSIG + EXC_SOFTWARE) + return GDB_EXC_SOFTWARE; +#endif +#if defined (EXC_BREAKPOINT) && defined (_NSIG) + if (hostsig == _NSIG + EXC_BREAKPOINT) + return GDB_EXC_BREAKPOINT; +#endif + +#if defined (SIGINFO) + if (hostsig == SIGINFO) + return GDB_SIGNAL_INFO; +#endif +#if defined (SIGLIBRT) + if (hostsig == SIGLIBRT) + return GDB_SIGNAL_LIBRT; +#endif + +#if defined (REALTIME_LO) + if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI) + { + /* This block of GDB_SIGNAL_REALTIME value is in order. */ + if (33 <= hostsig && hostsig <= 63) + return (enum gdb_signal) + (hostsig - 33 + (int) GDB_SIGNAL_REALTIME_33); + else if (hostsig == 32) + return GDB_SIGNAL_REALTIME_32; + else if (64 <= hostsig && hostsig <= 127) + return (enum gdb_signal) + (hostsig - 64 + (int) GDB_SIGNAL_REALTIME_64); + else + error (_("GDB bug: target.c (gdb_signal_from_host): " + "unrecognized real-time signal")); + } +#endif + + return GDB_SIGNAL_UNKNOWN; +} + +/* Convert a OURSIG (an enum gdb_signal) to the form used by the + target operating system (refered to as the ``host'') or zero if the + equivalent host signal is not available. Set/clear OURSIG_OK + accordingly. */ + +static int +do_gdb_signal_to_host (enum gdb_signal oursig, + int *oursig_ok) +{ + int retsig; + /* Silence the 'not used' warning, for targets that + do not support signals. */ + (void) retsig; + + /* Signals are ordered ANSI-standard signals first, other signals + second, with signals in each block ordered by their numerical + values on a typical POSIX platform. */ + + *oursig_ok = 1; + switch (oursig) + { + case GDB_SIGNAL_0: + return 0; + + /* SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV and SIGTERM + are ANSI-standard signals and are always available. */ + case GDB_SIGNAL_INT: + return SIGINT; + case GDB_SIGNAL_ILL: + return SIGILL; + case GDB_SIGNAL_ABRT: + return SIGABRT; + case GDB_SIGNAL_FPE: + return SIGFPE; + case GDB_SIGNAL_SEGV: + return SIGSEGV; + case GDB_SIGNAL_TERM: + return SIGTERM; + + /* All other signals need preprocessor conditionals. */ +#if defined (SIGHUP) + case GDB_SIGNAL_HUP: + return SIGHUP; +#endif +#if defined (SIGQUIT) + case GDB_SIGNAL_QUIT: + return SIGQUIT; +#endif +#if defined (SIGTRAP) + case GDB_SIGNAL_TRAP: + return SIGTRAP; +#endif +#if defined (SIGEMT) + case GDB_SIGNAL_EMT: + return SIGEMT; +#endif +#if defined (SIGKILL) + case GDB_SIGNAL_KILL: + return SIGKILL; +#endif +#if defined (SIGBUS) + case GDB_SIGNAL_BUS: + return SIGBUS; +#endif +#if defined (SIGSYS) + case GDB_SIGNAL_SYS: + return SIGSYS; +#endif +#if defined (SIGPIPE) + case GDB_SIGNAL_PIPE: + return SIGPIPE; +#endif +#if defined (SIGALRM) + case GDB_SIGNAL_ALRM: + return SIGALRM; +#endif +#if defined (SIGUSR1) + case GDB_SIGNAL_USR1: + return SIGUSR1; +#endif +#if defined (SIGUSR2) + case GDB_SIGNAL_USR2: + return SIGUSR2; +#endif +#if defined (SIGCHLD) || defined (SIGCLD) + case GDB_SIGNAL_CHLD: +#if defined (SIGCHLD) + return SIGCHLD; +#else + return SIGCLD; +#endif +#endif /* SIGCLD or SIGCHLD */ +#if defined (SIGPWR) + case GDB_SIGNAL_PWR: + return SIGPWR; +#endif +#if defined (SIGWINCH) + case GDB_SIGNAL_WINCH: + return SIGWINCH; +#endif +#if defined (SIGURG) + case GDB_SIGNAL_URG: + return SIGURG; +#endif +#if defined (SIGIO) + case GDB_SIGNAL_IO: + return SIGIO; +#endif +#if defined (SIGPOLL) + case GDB_SIGNAL_POLL: + return SIGPOLL; +#endif +#if defined (SIGSTOP) + case GDB_SIGNAL_STOP: + return SIGSTOP; +#endif +#if defined (SIGTSTP) + case GDB_SIGNAL_TSTP: + return SIGTSTP; +#endif +#if defined (SIGCONT) + case GDB_SIGNAL_CONT: + return SIGCONT; +#endif +#if defined (SIGTTIN) + case GDB_SIGNAL_TTIN: + return SIGTTIN; +#endif +#if defined (SIGTTOU) + case GDB_SIGNAL_TTOU: + return SIGTTOU; +#endif +#if defined (SIGVTALRM) + case GDB_SIGNAL_VTALRM: + return SIGVTALRM; +#endif +#if defined (SIGPROF) + case GDB_SIGNAL_PROF: + return SIGPROF; +#endif +#if defined (SIGXCPU) + case GDB_SIGNAL_XCPU: + return SIGXCPU; +#endif +#if defined (SIGXFSZ) + case GDB_SIGNAL_XFSZ: + return SIGXFSZ; +#endif +#if defined (SIGWIND) + case GDB_SIGNAL_WIND: + return SIGWIND; +#endif +#if defined (SIGPHONE) + case GDB_SIGNAL_PHONE: + return SIGPHONE; +#endif +#if defined (SIGLOST) + case GDB_SIGNAL_LOST: + return SIGLOST; +#endif +#if defined (SIGWAITING) + case GDB_SIGNAL_WAITING: + return SIGWAITING; +#endif +#if defined (SIGCANCEL) + case GDB_SIGNAL_CANCEL: + return SIGCANCEL; +#endif +#if defined (SIGLWP) + case GDB_SIGNAL_LWP: + return SIGLWP; +#endif +#if defined (SIGDANGER) + case GDB_SIGNAL_DANGER: + return SIGDANGER; +#endif +#if defined (SIGGRANT) + case GDB_SIGNAL_GRANT: + return SIGGRANT; +#endif +#if defined (SIGRETRACT) + case GDB_SIGNAL_RETRACT: + return SIGRETRACT; +#endif +#if defined (SIGMSG) + case GDB_SIGNAL_MSG: + return SIGMSG; +#endif +#if defined (SIGSOUND) + case GDB_SIGNAL_SOUND: + return SIGSOUND; +#endif +#if defined (SIGSAK) + case GDB_SIGNAL_SAK: + return SIGSAK; +#endif +#if defined (SIGPRIO) + case GDB_SIGNAL_PRIO: + return SIGPRIO; +#endif + + /* Mach exceptions. Assumes that the values for EXC_ are positive! */ +#if defined (EXC_BAD_ACCESS) && defined (_NSIG) + case GDB_EXC_BAD_ACCESS: + return _NSIG + EXC_BAD_ACCESS; +#endif +#if defined (EXC_BAD_INSTRUCTION) && defined (_NSIG) + case GDB_EXC_BAD_INSTRUCTION: + return _NSIG + EXC_BAD_INSTRUCTION; +#endif +#if defined (EXC_ARITHMETIC) && defined (_NSIG) + case GDB_EXC_ARITHMETIC: + return _NSIG + EXC_ARITHMETIC; +#endif +#if defined (EXC_EMULATION) && defined (_NSIG) + case GDB_EXC_EMULATION: + return _NSIG + EXC_EMULATION; +#endif +#if defined (EXC_SOFTWARE) && defined (_NSIG) + case GDB_EXC_SOFTWARE: + return _NSIG + EXC_SOFTWARE; +#endif +#if defined (EXC_BREAKPOINT) && defined (_NSIG) + case GDB_EXC_BREAKPOINT: + return _NSIG + EXC_BREAKPOINT; +#endif + +#if defined (SIGINFO) + case GDB_SIGNAL_INFO: + return SIGINFO; +#endif +#if defined (SIGLIBRT) + case GDB_SIGNAL_LIBRT: + return SIGLIBRT; +#endif + + default: +#if defined (REALTIME_LO) + retsig = 0; + + if (oursig >= GDB_SIGNAL_REALTIME_33 + && oursig <= GDB_SIGNAL_REALTIME_63) + { + /* This block of signals is continuous, and + GDB_SIGNAL_REALTIME_33 is 33 by definition. */ + retsig = (int) oursig - (int) GDB_SIGNAL_REALTIME_33 + 33; + } + else if (oursig == GDB_SIGNAL_REALTIME_32) + { + /* GDB_SIGNAL_REALTIME_32 isn't contiguous with + GDB_SIGNAL_REALTIME_33. It is 32 by definition. */ + retsig = 32; + } + else if (oursig >= GDB_SIGNAL_REALTIME_64 + && oursig <= GDB_SIGNAL_REALTIME_127) + { + /* This block of signals is continuous, and + GDB_SIGNAL_REALTIME_64 is 64 by definition. */ + retsig = (int) oursig - (int) GDB_SIGNAL_REALTIME_64 + 64; + } + + if (retsig >= REALTIME_LO && retsig < REALTIME_HI) + return retsig; +#endif + + *oursig_ok = 0; + return 0; + } +} + +int +gdb_signal_to_host_p (enum gdb_signal oursig) +{ + int oursig_ok; + do_gdb_signal_to_host (oursig, &oursig_ok); + return oursig_ok; +} + +int +gdb_signal_to_host (enum gdb_signal oursig) +{ + int oursig_ok; + int targ_signo = do_gdb_signal_to_host (oursig, &oursig_ok); + if (!oursig_ok) + { + /* The user might be trying to do "signal SIGSAK" where this system + doesn't have SIGSAK. */ + warning (_("Signal %s does not exist on this system."), + gdb_signal_to_name (oursig)); + return 0; + } + else + return targ_signo; +} diff --git a/gdbsupport/tdesc.c b/gdbsupport/tdesc.c deleted file mode 100644 index aaea8e0..0000000 --- a/gdbsupport/tdesc.c +++ /dev/null @@ -1,401 +0,0 @@ -/* Target description support for GDB. - - Copyright (C) 2018-2020 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 . */ - -#include "common-defs.h" -#include "gdbsupport/tdesc.h" - -tdesc_reg::tdesc_reg (struct tdesc_feature *feature, const std::string &name_, - int regnum, int save_restore_, const char *group_, - int bitsize_, const char *type_) - : name (name_), target_regnum (regnum), - save_restore (save_restore_), - group (group_ != NULL ? group_ : ""), - bitsize (bitsize_), - type (type_ != NULL ? type_ : "") -{ - /* If the register's type is target-defined, look it up now. We may not - have easy access to the containing feature when we want it later. */ - tdesc_type = tdesc_named_type (feature, type.c_str ()); -} - -/* Predefined types. */ -static tdesc_type_builtin tdesc_predefined_types[] = -{ - { "bool", TDESC_TYPE_BOOL }, - { "int8", TDESC_TYPE_INT8 }, - { "int16", TDESC_TYPE_INT16 }, - { "int32", TDESC_TYPE_INT32 }, - { "int64", TDESC_TYPE_INT64 }, - { "int128", TDESC_TYPE_INT128 }, - { "uint8", TDESC_TYPE_UINT8 }, - { "uint16", TDESC_TYPE_UINT16 }, - { "uint32", TDESC_TYPE_UINT32 }, - { "uint64", TDESC_TYPE_UINT64 }, - { "uint128", TDESC_TYPE_UINT128 }, - { "code_ptr", TDESC_TYPE_CODE_PTR }, - { "data_ptr", TDESC_TYPE_DATA_PTR }, - { "ieee_half", TDESC_TYPE_IEEE_HALF }, - { "ieee_single", TDESC_TYPE_IEEE_SINGLE }, - { "ieee_double", TDESC_TYPE_IEEE_DOUBLE }, - { "arm_fpa_ext", TDESC_TYPE_ARM_FPA_EXT }, - { "i387_ext", TDESC_TYPE_I387_EXT } -}; - -void tdesc_feature::accept (tdesc_element_visitor &v) const -{ - v.visit_pre (this); - - for (const tdesc_type_up &type : types) - type->accept (v); - - for (const tdesc_reg_up ® : registers) - reg->accept (v); - - v.visit_post (this); -} - -bool tdesc_feature::operator== (const tdesc_feature &other) const -{ - if (name != other.name) - return false; - - if (registers.size () != other.registers.size ()) - return false; - - for (int ix = 0; ix < registers.size (); ix++) - { - const tdesc_reg_up ®1 = registers[ix]; - const tdesc_reg_up ®2 = other.registers[ix]; - - if (reg1 != reg2 && *reg1 != *reg2) - return false; - } - - if (types.size () != other.types.size ()) - return false; - - for (int ix = 0; ix < types.size (); ix++) - { - const tdesc_type_up &type1 = types[ix]; - const tdesc_type_up &type2 = other.types[ix]; - - if (type1 != type2 && *type1 != *type2) - return false; - } - - return true; -} - -/* Lookup a predefined type. */ - -static struct tdesc_type * -tdesc_predefined_type (enum tdesc_type_kind kind) -{ - for (int ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++) - if (tdesc_predefined_types[ix].kind == kind) - return &tdesc_predefined_types[ix]; - - gdb_assert_not_reached ("bad predefined tdesc type"); -} - -/* See gdbsupport/tdesc.h. */ - -struct tdesc_type * -tdesc_named_type (const struct tdesc_feature *feature, const char *id) -{ - /* First try target-defined types. */ - for (const tdesc_type_up &type : feature->types) - if (type->name == id) - return type.get (); - - /* Next try the predefined types. */ - for (int ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++) - if (tdesc_predefined_types[ix].name == id) - return &tdesc_predefined_types[ix]; - - return NULL; -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_create_reg (struct tdesc_feature *feature, const char *name, - int regnum, int save_restore, const char *group, - int bitsize, const char *type) -{ - tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore, - group, bitsize, type); - - feature->registers.emplace_back (reg); -} - -/* See gdbsupport/tdesc.h. */ - -struct tdesc_type * -tdesc_create_vector (struct tdesc_feature *feature, const char *name, - struct tdesc_type *field_type, int count) -{ - tdesc_type_vector *type = new tdesc_type_vector (name, field_type, count); - feature->types.emplace_back (type); - - return type; -} - -/* See gdbsupport/tdesc.h. */ - -tdesc_type_with_fields * -tdesc_create_struct (struct tdesc_feature *feature, const char *name) -{ - tdesc_type_with_fields *type - = new tdesc_type_with_fields (name, TDESC_TYPE_STRUCT); - feature->types.emplace_back (type); - - return type; -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_set_struct_size (tdesc_type_with_fields *type, int size) -{ - gdb_assert (type->kind == TDESC_TYPE_STRUCT); - gdb_assert (size > 0); - type->size = size; -} - -/* See gdbsupport/tdesc.h. */ - -tdesc_type_with_fields * -tdesc_create_union (struct tdesc_feature *feature, const char *name) -{ - tdesc_type_with_fields *type - = new tdesc_type_with_fields (name, TDESC_TYPE_UNION); - feature->types.emplace_back (type); - - return type; -} - -/* See gdbsupport/tdesc.h. */ - -tdesc_type_with_fields * -tdesc_create_flags (struct tdesc_feature *feature, const char *name, - int size) -{ - gdb_assert (size > 0); - - tdesc_type_with_fields *type - = new tdesc_type_with_fields (name, TDESC_TYPE_FLAGS, size); - feature->types.emplace_back (type); - - return type; -} - -/* See gdbsupport/tdesc.h. */ - -tdesc_type_with_fields * -tdesc_create_enum (struct tdesc_feature *feature, const char *name, - int size) -{ - gdb_assert (size > 0); - - tdesc_type_with_fields *type - = new tdesc_type_with_fields (name, TDESC_TYPE_ENUM, size); - feature->types.emplace_back (type); - - return type; -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_add_field (tdesc_type_with_fields *type, const char *field_name, - struct tdesc_type *field_type) -{ - gdb_assert (type->kind == TDESC_TYPE_UNION - || type->kind == TDESC_TYPE_STRUCT); - - /* Initialize start and end so we know this is not a bit-field - when we print-c-tdesc. */ - type->fields.emplace_back (field_name, field_type, -1, -1); -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_add_typed_bitfield (tdesc_type_with_fields *type, const char *field_name, - int start, int end, struct tdesc_type *field_type) -{ - gdb_assert (type->kind == TDESC_TYPE_STRUCT - || type->kind == TDESC_TYPE_FLAGS); - gdb_assert (start >= 0 && end >= start); - - type->fields.emplace_back (field_name, field_type, start, end); -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_add_bitfield (tdesc_type_with_fields *type, const char *field_name, - int start, int end) -{ - struct tdesc_type *field_type; - - gdb_assert (start >= 0 && end >= start); - - if (type->size > 4) - field_type = tdesc_predefined_type (TDESC_TYPE_UINT64); - else - field_type = tdesc_predefined_type (TDESC_TYPE_UINT32); - - tdesc_add_typed_bitfield (type, field_name, start, end, field_type); -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_add_flag (tdesc_type_with_fields *type, int start, - const char *flag_name) -{ - gdb_assert (type->kind == TDESC_TYPE_FLAGS - || type->kind == TDESC_TYPE_STRUCT); - - type->fields.emplace_back (flag_name, - tdesc_predefined_type (TDESC_TYPE_BOOL), - start, start); -} - -/* See gdbsupport/tdesc.h. */ - -void -tdesc_add_enum_value (tdesc_type_with_fields *type, int value, - const char *name) -{ - gdb_assert (type->kind == TDESC_TYPE_ENUM); - type->fields.emplace_back (name, - tdesc_predefined_type (TDESC_TYPE_INT32), - value, -1); -} - -void print_xml_feature::visit_pre (const tdesc_feature *e) -{ - string_appendf (*m_buffer, "\n", e->name.c_str ()); -} - -void print_xml_feature::visit_post (const tdesc_feature *e) -{ - string_appendf (*m_buffer, "\n"); -} - -void print_xml_feature::visit (const tdesc_type_builtin *t) -{ - error (_("xml output is not supported for type \"%s\"."), t->name.c_str ()); -} - -void print_xml_feature::visit (const tdesc_type_vector *t) -{ - string_appendf (*m_buffer, "\n", - t->name.c_str (), t->element_type->name.c_str (), t->count); -} - -void print_xml_feature::visit (const tdesc_type_with_fields *t) -{ - const static char *types[] = { "struct", "union", "flags", "enum" }; - - gdb_assert (t->kind >= TDESC_TYPE_STRUCT && t->kind <= TDESC_TYPE_ENUM); - - string_appendf (*m_buffer, - "<%s id=\"%s\"", types[t->kind - TDESC_TYPE_STRUCT], - t->name.c_str ()); - - switch (t->kind) - { - case TDESC_TYPE_STRUCT: - case TDESC_TYPE_FLAGS: - if (t->size > 0) - string_appendf (*m_buffer, " size=\"%d\"", t->size); - string_appendf (*m_buffer, ">\n"); - - for (const tdesc_type_field &f : t->fields) - { - string_appendf (*m_buffer, " \n", - f.type->name.c_str ()); - else - string_appendf (*m_buffer, "start=\"%d\" end=\"%d\"/>\n", f.start, - f.end); - } - break; - - case TDESC_TYPE_ENUM: - string_appendf (*m_buffer, ">\n"); - for (const tdesc_type_field &f : t->fields) - string_appendf (*m_buffer, " \n", - f.name.c_str (), f.start); - break; - - case TDESC_TYPE_UNION: - string_appendf (*m_buffer, ">\n"); - for (const tdesc_type_field &f : t->fields) - string_appendf (*m_buffer, " \n", - f.name.c_str (), f.type->name.c_str ()); - break; - - default: - error (_("xml output is not supported for type \"%s\"."), - t->name.c_str ()); - } - - string_appendf (*m_buffer, "\n", types[t->kind - TDESC_TYPE_STRUCT]); -} - -void print_xml_feature::visit (const tdesc_reg *r) -{ - string_appendf (*m_buffer, - "name.c_str (), r->bitsize, r->type.c_str (), - r->target_regnum); - - if (r->group.length () > 0) - string_appendf (*m_buffer, " group=\"%s\"", r->group.c_str ()); - - if (r->save_restore == 0) - string_appendf (*m_buffer, " save-restore=\"no\""); - - string_appendf (*m_buffer, "/>\n"); -} - -void print_xml_feature::visit_pre (const target_desc *e) -{ -#ifndef IN_PROCESS_AGENT - string_appendf (*m_buffer, "\n"); - string_appendf (*m_buffer, "\n"); - string_appendf (*m_buffer, "\n%s\n", - tdesc_architecture_name (e)); - - const char *osabi = tdesc_osabi_name (e); - if (osabi != nullptr) - string_appendf (*m_buffer, "%s", osabi); -#endif -} - -void print_xml_feature::visit_post (const target_desc *e) -{ - string_appendf (*m_buffer, "\n"); -} diff --git a/gdbsupport/tdesc.cc b/gdbsupport/tdesc.cc new file mode 100644 index 0000000..aaea8e0 --- /dev/null +++ b/gdbsupport/tdesc.cc @@ -0,0 +1,401 @@ +/* Target description support for GDB. + + Copyright (C) 2018-2020 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 . */ + +#include "common-defs.h" +#include "gdbsupport/tdesc.h" + +tdesc_reg::tdesc_reg (struct tdesc_feature *feature, const std::string &name_, + int regnum, int save_restore_, const char *group_, + int bitsize_, const char *type_) + : name (name_), target_regnum (regnum), + save_restore (save_restore_), + group (group_ != NULL ? group_ : ""), + bitsize (bitsize_), + type (type_ != NULL ? type_ : "") +{ + /* If the register's type is target-defined, look it up now. We may not + have easy access to the containing feature when we want it later. */ + tdesc_type = tdesc_named_type (feature, type.c_str ()); +} + +/* Predefined types. */ +static tdesc_type_builtin tdesc_predefined_types[] = +{ + { "bool", TDESC_TYPE_BOOL }, + { "int8", TDESC_TYPE_INT8 }, + { "int16", TDESC_TYPE_INT16 }, + { "int32", TDESC_TYPE_INT32 }, + { "int64", TDESC_TYPE_INT64 }, + { "int128", TDESC_TYPE_INT128 }, + { "uint8", TDESC_TYPE_UINT8 }, + { "uint16", TDESC_TYPE_UINT16 }, + { "uint32", TDESC_TYPE_UINT32 }, + { "uint64", TDESC_TYPE_UINT64 }, + { "uint128", TDESC_TYPE_UINT128 }, + { "code_ptr", TDESC_TYPE_CODE_PTR }, + { "data_ptr", TDESC_TYPE_DATA_PTR }, + { "ieee_half", TDESC_TYPE_IEEE_HALF }, + { "ieee_single", TDESC_TYPE_IEEE_SINGLE }, + { "ieee_double", TDESC_TYPE_IEEE_DOUBLE }, + { "arm_fpa_ext", TDESC_TYPE_ARM_FPA_EXT }, + { "i387_ext", TDESC_TYPE_I387_EXT } +}; + +void tdesc_feature::accept (tdesc_element_visitor &v) const +{ + v.visit_pre (this); + + for (const tdesc_type_up &type : types) + type->accept (v); + + for (const tdesc_reg_up ® : registers) + reg->accept (v); + + v.visit_post (this); +} + +bool tdesc_feature::operator== (const tdesc_feature &other) const +{ + if (name != other.name) + return false; + + if (registers.size () != other.registers.size ()) + return false; + + for (int ix = 0; ix < registers.size (); ix++) + { + const tdesc_reg_up ®1 = registers[ix]; + const tdesc_reg_up ®2 = other.registers[ix]; + + if (reg1 != reg2 && *reg1 != *reg2) + return false; + } + + if (types.size () != other.types.size ()) + return false; + + for (int ix = 0; ix < types.size (); ix++) + { + const tdesc_type_up &type1 = types[ix]; + const tdesc_type_up &type2 = other.types[ix]; + + if (type1 != type2 && *type1 != *type2) + return false; + } + + return true; +} + +/* Lookup a predefined type. */ + +static struct tdesc_type * +tdesc_predefined_type (enum tdesc_type_kind kind) +{ + for (int ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++) + if (tdesc_predefined_types[ix].kind == kind) + return &tdesc_predefined_types[ix]; + + gdb_assert_not_reached ("bad predefined tdesc type"); +} + +/* See gdbsupport/tdesc.h. */ + +struct tdesc_type * +tdesc_named_type (const struct tdesc_feature *feature, const char *id) +{ + /* First try target-defined types. */ + for (const tdesc_type_up &type : feature->types) + if (type->name == id) + return type.get (); + + /* Next try the predefined types. */ + for (int ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++) + if (tdesc_predefined_types[ix].name == id) + return &tdesc_predefined_types[ix]; + + return NULL; +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_create_reg (struct tdesc_feature *feature, const char *name, + int regnum, int save_restore, const char *group, + int bitsize, const char *type) +{ + tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore, + group, bitsize, type); + + feature->registers.emplace_back (reg); +} + +/* See gdbsupport/tdesc.h. */ + +struct tdesc_type * +tdesc_create_vector (struct tdesc_feature *feature, const char *name, + struct tdesc_type *field_type, int count) +{ + tdesc_type_vector *type = new tdesc_type_vector (name, field_type, count); + feature->types.emplace_back (type); + + return type; +} + +/* See gdbsupport/tdesc.h. */ + +tdesc_type_with_fields * +tdesc_create_struct (struct tdesc_feature *feature, const char *name) +{ + tdesc_type_with_fields *type + = new tdesc_type_with_fields (name, TDESC_TYPE_STRUCT); + feature->types.emplace_back (type); + + return type; +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_set_struct_size (tdesc_type_with_fields *type, int size) +{ + gdb_assert (type->kind == TDESC_TYPE_STRUCT); + gdb_assert (size > 0); + type->size = size; +} + +/* See gdbsupport/tdesc.h. */ + +tdesc_type_with_fields * +tdesc_create_union (struct tdesc_feature *feature, const char *name) +{ + tdesc_type_with_fields *type + = new tdesc_type_with_fields (name, TDESC_TYPE_UNION); + feature->types.emplace_back (type); + + return type; +} + +/* See gdbsupport/tdesc.h. */ + +tdesc_type_with_fields * +tdesc_create_flags (struct tdesc_feature *feature, const char *name, + int size) +{ + gdb_assert (size > 0); + + tdesc_type_with_fields *type + = new tdesc_type_with_fields (name, TDESC_TYPE_FLAGS, size); + feature->types.emplace_back (type); + + return type; +} + +/* See gdbsupport/tdesc.h. */ + +tdesc_type_with_fields * +tdesc_create_enum (struct tdesc_feature *feature, const char *name, + int size) +{ + gdb_assert (size > 0); + + tdesc_type_with_fields *type + = new tdesc_type_with_fields (name, TDESC_TYPE_ENUM, size); + feature->types.emplace_back (type); + + return type; +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_add_field (tdesc_type_with_fields *type, const char *field_name, + struct tdesc_type *field_type) +{ + gdb_assert (type->kind == TDESC_TYPE_UNION + || type->kind == TDESC_TYPE_STRUCT); + + /* Initialize start and end so we know this is not a bit-field + when we print-c-tdesc. */ + type->fields.emplace_back (field_name, field_type, -1, -1); +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_add_typed_bitfield (tdesc_type_with_fields *type, const char *field_name, + int start, int end, struct tdesc_type *field_type) +{ + gdb_assert (type->kind == TDESC_TYPE_STRUCT + || type->kind == TDESC_TYPE_FLAGS); + gdb_assert (start >= 0 && end >= start); + + type->fields.emplace_back (field_name, field_type, start, end); +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_add_bitfield (tdesc_type_with_fields *type, const char *field_name, + int start, int end) +{ + struct tdesc_type *field_type; + + gdb_assert (start >= 0 && end >= start); + + if (type->size > 4) + field_type = tdesc_predefined_type (TDESC_TYPE_UINT64); + else + field_type = tdesc_predefined_type (TDESC_TYPE_UINT32); + + tdesc_add_typed_bitfield (type, field_name, start, end, field_type); +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_add_flag (tdesc_type_with_fields *type, int start, + const char *flag_name) +{ + gdb_assert (type->kind == TDESC_TYPE_FLAGS + || type->kind == TDESC_TYPE_STRUCT); + + type->fields.emplace_back (flag_name, + tdesc_predefined_type (TDESC_TYPE_BOOL), + start, start); +} + +/* See gdbsupport/tdesc.h. */ + +void +tdesc_add_enum_value (tdesc_type_with_fields *type, int value, + const char *name) +{ + gdb_assert (type->kind == TDESC_TYPE_ENUM); + type->fields.emplace_back (name, + tdesc_predefined_type (TDESC_TYPE_INT32), + value, -1); +} + +void print_xml_feature::visit_pre (const tdesc_feature *e) +{ + string_appendf (*m_buffer, "\n", e->name.c_str ()); +} + +void print_xml_feature::visit_post (const tdesc_feature *e) +{ + string_appendf (*m_buffer, "\n"); +} + +void print_xml_feature::visit (const tdesc_type_builtin *t) +{ + error (_("xml output is not supported for type \"%s\"."), t->name.c_str ()); +} + +void print_xml_feature::visit (const tdesc_type_vector *t) +{ + string_appendf (*m_buffer, "\n", + t->name.c_str (), t->element_type->name.c_str (), t->count); +} + +void print_xml_feature::visit (const tdesc_type_with_fields *t) +{ + const static char *types[] = { "struct", "union", "flags", "enum" }; + + gdb_assert (t->kind >= TDESC_TYPE_STRUCT && t->kind <= TDESC_TYPE_ENUM); + + string_appendf (*m_buffer, + "<%s id=\"%s\"", types[t->kind - TDESC_TYPE_STRUCT], + t->name.c_str ()); + + switch (t->kind) + { + case TDESC_TYPE_STRUCT: + case TDESC_TYPE_FLAGS: + if (t->size > 0) + string_appendf (*m_buffer, " size=\"%d\"", t->size); + string_appendf (*m_buffer, ">\n"); + + for (const tdesc_type_field &f : t->fields) + { + string_appendf (*m_buffer, " \n", + f.type->name.c_str ()); + else + string_appendf (*m_buffer, "start=\"%d\" end=\"%d\"/>\n", f.start, + f.end); + } + break; + + case TDESC_TYPE_ENUM: + string_appendf (*m_buffer, ">\n"); + for (const tdesc_type_field &f : t->fields) + string_appendf (*m_buffer, " \n", + f.name.c_str (), f.start); + break; + + case TDESC_TYPE_UNION: + string_appendf (*m_buffer, ">\n"); + for (const tdesc_type_field &f : t->fields) + string_appendf (*m_buffer, " \n", + f.name.c_str (), f.type->name.c_str ()); + break; + + default: + error (_("xml output is not supported for type \"%s\"."), + t->name.c_str ()); + } + + string_appendf (*m_buffer, "\n", types[t->kind - TDESC_TYPE_STRUCT]); +} + +void print_xml_feature::visit (const tdesc_reg *r) +{ + string_appendf (*m_buffer, + "name.c_str (), r->bitsize, r->type.c_str (), + r->target_regnum); + + if (r->group.length () > 0) + string_appendf (*m_buffer, " group=\"%s\"", r->group.c_str ()); + + if (r->save_restore == 0) + string_appendf (*m_buffer, " save-restore=\"no\""); + + string_appendf (*m_buffer, "/>\n"); +} + +void print_xml_feature::visit_pre (const target_desc *e) +{ +#ifndef IN_PROCESS_AGENT + string_appendf (*m_buffer, "\n"); + string_appendf (*m_buffer, "\n"); + string_appendf (*m_buffer, "\n%s\n", + tdesc_architecture_name (e)); + + const char *osabi = tdesc_osabi_name (e); + if (osabi != nullptr) + string_appendf (*m_buffer, "%s", osabi); +#endif +} + +void print_xml_feature::visit_post (const target_desc *e) +{ + string_appendf (*m_buffer, "\n"); +} diff --git a/gdbsupport/thread-pool.c b/gdbsupport/thread-pool.c deleted file mode 100644 index be9ca22..0000000 --- a/gdbsupport/thread-pool.c +++ /dev/null @@ -1,175 +0,0 @@ -/* Thread pool - - Copyright (C) 2019-2020 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 . */ - -#include "common-defs.h" - -#if CXX_STD_THREAD - -#include "gdbsupport/thread-pool.h" -#include "gdbsupport/alt-stack.h" -#include "gdbsupport/block-signals.h" -#include - -/* On the off chance that we have the pthread library on a Windows - host, but std::thread is not using it, avoid calling - pthread_setname_np on Windows. */ -#ifndef _WIN32 -#ifdef HAVE_PTHREAD_SETNAME_NP -#define USE_PTHREAD_SETNAME_NP -#endif -#endif - -#ifdef USE_PTHREAD_SETNAME_NP - -#include - -/* Handle platform discrepancies in pthread_setname_np: macOS uses a - single-argument form, while Linux uses a two-argument form. NetBSD - takes a printf-style format and an argument. This wrapper handles the - difference. */ - -ATTRIBUTE_UNUSED static void -set_thread_name (int (*set_name) (pthread_t, const char *, void *), - const char *name) -{ - set_name (pthread_self (), "%s", const_cast (name)); -} - -ATTRIBUTE_UNUSED static void -set_thread_name (int (*set_name) (pthread_t, const char *), const char *name) -{ - set_name (pthread_self (), name); -} - -/* The macOS man page says that pthread_setname_np returns "void", but - the headers actually declare it returning "int". */ -ATTRIBUTE_UNUSED static void -set_thread_name (int (*set_name) (const char *), const char *name) -{ - set_name (name); -} - -#endif /* USE_PTHREAD_SETNAME_NP */ - -namespace gdb -{ - -/* The thread pool detach()s its threads, so that the threads will not - prevent the process from exiting. However, it was discovered that - if any detached threads were still waiting on a condition variable, - then the condition variable's destructor would wait for the threads - to exit -- defeating the purpose. - - Allocating the thread pool on the heap and simply "leaking" it - avoids this problem. -*/ -thread_pool *thread_pool::g_thread_pool = new thread_pool (); - -thread_pool::~thread_pool () -{ - /* Because this is a singleton, we don't need to clean up. The - threads are detached so that they won't prevent process exit. - And, cleaning up here would be actively harmful in at least one - case -- see the comment by the definition of g_thread_pool. */ -} - -void -thread_pool::set_thread_count (size_t num_threads) -{ - std::lock_guard guard (m_tasks_mutex); - - /* If the new size is larger, start some new threads. */ - if (m_thread_count < num_threads) - { - /* Ensure that signals used by gdb are blocked in the new - threads. */ - block_signals blocker; - for (size_t i = m_thread_count; i < num_threads; ++i) - { - std::thread thread (&thread_pool::thread_function, this); - thread.detach (); - } - } - /* If the new size is smaller, terminate some existing threads. */ - if (num_threads < m_thread_count) - { - for (size_t i = num_threads; i < m_thread_count; ++i) - m_tasks.emplace (); - m_tasks_cv.notify_all (); - } - - m_thread_count = num_threads; -} - -std::future -thread_pool::post_task (std::function func) -{ - std::packaged_task t (func); - std::future f = t.get_future (); - - if (m_thread_count == 0) - { - /* Just execute it now. */ - t (); - } - else - { - std::lock_guard guard (m_tasks_mutex); - m_tasks.emplace (std::move (t)); - m_tasks_cv.notify_one (); - } - return f; -} - -void -thread_pool::thread_function () -{ -#ifdef USE_PTHREAD_SETNAME_NP - /* This must be done here, because on macOS one can only set the - name of the current thread. */ - set_thread_name (pthread_setname_np, "gdb worker"); -#endif - - /* Ensure that SIGSEGV is delivered to an alternate signal - stack. */ - gdb::alternate_signal_stack signal_stack; - - while (true) - { - optional t; - - { - /* We want to hold the lock while examining the task list, but - not while invoking the task function. */ - std::unique_lock guard (m_tasks_mutex); - while (m_tasks.empty ()) - m_tasks_cv.wait (guard); - t = std::move (m_tasks.front()); - m_tasks.pop (); - } - - if (!t.has_value ()) - break; - (*t) (); - } -} - -} - -#endif /* CXX_STD_THREAD */ diff --git a/gdbsupport/thread-pool.cc b/gdbsupport/thread-pool.cc new file mode 100644 index 0000000..be9ca22 --- /dev/null +++ b/gdbsupport/thread-pool.cc @@ -0,0 +1,175 @@ +/* Thread pool + + Copyright (C) 2019-2020 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 . */ + +#include "common-defs.h" + +#if CXX_STD_THREAD + +#include "gdbsupport/thread-pool.h" +#include "gdbsupport/alt-stack.h" +#include "gdbsupport/block-signals.h" +#include + +/* On the off chance that we have the pthread library on a Windows + host, but std::thread is not using it, avoid calling + pthread_setname_np on Windows. */ +#ifndef _WIN32 +#ifdef HAVE_PTHREAD_SETNAME_NP +#define USE_PTHREAD_SETNAME_NP +#endif +#endif + +#ifdef USE_PTHREAD_SETNAME_NP + +#include + +/* Handle platform discrepancies in pthread_setname_np: macOS uses a + single-argument form, while Linux uses a two-argument form. NetBSD + takes a printf-style format and an argument. This wrapper handles the + difference. */ + +ATTRIBUTE_UNUSED static void +set_thread_name (int (*set_name) (pthread_t, const char *, void *), + const char *name) +{ + set_name (pthread_self (), "%s", const_cast (name)); +} + +ATTRIBUTE_UNUSED static void +set_thread_name (int (*set_name) (pthread_t, const char *), const char *name) +{ + set_name (pthread_self (), name); +} + +/* The macOS man page says that pthread_setname_np returns "void", but + the headers actually declare it returning "int". */ +ATTRIBUTE_UNUSED static void +set_thread_name (int (*set_name) (const char *), const char *name) +{ + set_name (name); +} + +#endif /* USE_PTHREAD_SETNAME_NP */ + +namespace gdb +{ + +/* The thread pool detach()s its threads, so that the threads will not + prevent the process from exiting. However, it was discovered that + if any detached threads were still waiting on a condition variable, + then the condition variable's destructor would wait for the threads + to exit -- defeating the purpose. + + Allocating the thread pool on the heap and simply "leaking" it + avoids this problem. +*/ +thread_pool *thread_pool::g_thread_pool = new thread_pool (); + +thread_pool::~thread_pool () +{ + /* Because this is a singleton, we don't need to clean up. The + threads are detached so that they won't prevent process exit. + And, cleaning up here would be actively harmful in at least one + case -- see the comment by the definition of g_thread_pool. */ +} + +void +thread_pool::set_thread_count (size_t num_threads) +{ + std::lock_guard guard (m_tasks_mutex); + + /* If the new size is larger, start some new threads. */ + if (m_thread_count < num_threads) + { + /* Ensure that signals used by gdb are blocked in the new + threads. */ + block_signals blocker; + for (size_t i = m_thread_count; i < num_threads; ++i) + { + std::thread thread (&thread_pool::thread_function, this); + thread.detach (); + } + } + /* If the new size is smaller, terminate some existing threads. */ + if (num_threads < m_thread_count) + { + for (size_t i = num_threads; i < m_thread_count; ++i) + m_tasks.emplace (); + m_tasks_cv.notify_all (); + } + + m_thread_count = num_threads; +} + +std::future +thread_pool::post_task (std::function func) +{ + std::packaged_task t (func); + std::future f = t.get_future (); + + if (m_thread_count == 0) + { + /* Just execute it now. */ + t (); + } + else + { + std::lock_guard guard (m_tasks_mutex); + m_tasks.emplace (std::move (t)); + m_tasks_cv.notify_one (); + } + return f; +} + +void +thread_pool::thread_function () +{ +#ifdef USE_PTHREAD_SETNAME_NP + /* This must be done here, because on macOS one can only set the + name of the current thread. */ + set_thread_name (pthread_setname_np, "gdb worker"); +#endif + + /* Ensure that SIGSEGV is delivered to an alternate signal + stack. */ + gdb::alternate_signal_stack signal_stack; + + while (true) + { + optional t; + + { + /* We want to hold the lock while examining the task list, but + not while invoking the task function. */ + std::unique_lock guard (m_tasks_mutex); + while (m_tasks.empty ()) + m_tasks_cv.wait (guard); + t = std::move (m_tasks.front()); + m_tasks.pop (); + } + + if (!t.has_value ()) + break; + (*t) (); + } +} + +} + +#endif /* CXX_STD_THREAD */ diff --git a/gdbsupport/xml-utils.c b/gdbsupport/xml-utils.c deleted file mode 100644 index 3c6c11a..0000000 --- a/gdbsupport/xml-utils.c +++ /dev/null @@ -1,63 +0,0 @@ -/* Shared helper routines for manipulating XML. - - Copyright (C) 2006-2020 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 . */ - -#include "common-defs.h" -#include "xml-utils.h" - -/* See xml-utils.h. */ - -std::string -xml_escape_text (const char *text) -{ - std::string result; - - xml_escape_text_append (&result, text); - - return result; -} - -/* See xml-utils.h. */ - -void -xml_escape_text_append (std::string *result, const char *text) -{ - /* Expand the result. */ - for (int i = 0; text[i] != '\0'; i++) - switch (text[i]) - { - case '\'': - *result += "'"; - break; - case '\"': - *result += """; - break; - case '&': - *result += "&"; - break; - case '<': - *result += "<"; - break; - case '>': - *result += ">"; - break; - default: - *result += text[i]; - break; - } -} diff --git a/gdbsupport/xml-utils.cc b/gdbsupport/xml-utils.cc new file mode 100644 index 0000000..3c6c11a --- /dev/null +++ b/gdbsupport/xml-utils.cc @@ -0,0 +1,63 @@ +/* Shared helper routines for manipulating XML. + + Copyright (C) 2006-2020 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 . */ + +#include "common-defs.h" +#include "xml-utils.h" + +/* See xml-utils.h. */ + +std::string +xml_escape_text (const char *text) +{ + std::string result; + + xml_escape_text_append (&result, text); + + return result; +} + +/* See xml-utils.h. */ + +void +xml_escape_text_append (std::string *result, const char *text) +{ + /* Expand the result. */ + for (int i = 0; text[i] != '\0'; i++) + switch (text[i]) + { + case '\'': + *result += "'"; + break; + case '\"': + *result += """; + break; + case '&': + *result += "&"; + break; + case '<': + *result += "<"; + break; + case '>': + *result += ">"; + break; + default: + *result += text[i]; + break; + } +} -- cgit v1.1