diff options
Diffstat (limited to 'gdb/python')
-rw-r--r-- | gdb/python/lib/gdb/dap/breakpoint.py | 13 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/events.py | 4 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/next.py | 12 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/server.py | 27 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/startup.py | 10 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/varref.py | 10 | ||||
-rw-r--r-- | gdb/python/lib/gdb/printing.py | 19 | ||||
-rw-r--r-- | gdb/python/py-block.c | 3 | ||||
-rw-r--r-- | gdb/python/py-disasm.c | 85 | ||||
-rw-r--r-- | gdb/python/py-event-types.def | 2 | ||||
-rw-r--r-- | gdb/python/py-finishbreakpoint.c | 6 | ||||
-rw-r--r-- | gdb/python/py-framefilter.c | 2 | ||||
-rw-r--r-- | gdb/python/py-infevents.c | 2 | ||||
-rw-r--r-- | gdb/python/py-infthread.c | 33 | ||||
-rw-r--r-- | gdb/python/py-mi.c | 6 | ||||
-rw-r--r-- | gdb/python/py-micmd.c | 4 | ||||
-rw-r--r-- | gdb/python/py-objfile.c | 12 | ||||
-rw-r--r-- | gdb/python/py-record.c | 3 | ||||
-rw-r--r-- | gdb/python/py-symbol.c | 44 | ||||
-rw-r--r-- | gdb/python/py-type.c | 15 | ||||
-rw-r--r-- | gdb/python/py-unwind.c | 2 | ||||
-rw-r--r-- | gdb/python/py-value.c | 82 | ||||
-rw-r--r-- | gdb/python/python-internal.h | 7 | ||||
-rw-r--r-- | gdb/python/python.c | 32 |
24 files changed, 259 insertions, 176 deletions
diff --git a/gdb/python/lib/gdb/dap/breakpoint.py b/gdb/python/lib/gdb/dap/breakpoint.py index 4d4ca18..3162911 100644 --- a/gdb/python/lib/gdb/dap/breakpoint.py +++ b/gdb/python/lib/gdb/dap/breakpoint.py @@ -373,10 +373,12 @@ def set_insn_breakpoints( @in_gdb_thread def _catch_exception(filterId, **args): if filterId in ("assert", "exception", "throw", "rethrow", "catch"): - cmd = "-catch-" + filterId + cmd = ["-catch-" + filterId] else: raise DAPException("Invalid exception filterID: " + str(filterId)) - result = exec_mi_and_log(cmd) + if "exception" in args and args["exception"] is not None: + cmd += ["-e", args["exception"]] + result = exec_mi_and_log(*cmd) # While the Ada catchpoints emit a "bkptno" field here, the C++ # ones do not. So, instead we look at the "number" field. num = result["bkpt"]["number"] @@ -404,6 +406,13 @@ def _rewrite_exception_breakpoint( # Note that exception breakpoints do not support a hit count. **args, ): + if filterId == "exception": + # Treat Ada exceptions specially -- in particular the + # condition is just an exception name, not an expression. + return { + "filterId": filterId, + "exception": condition, + } return { "filterId": filterId, "condition": condition, diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py index e8f2655..778acc5 100644 --- a/gdb/python/lib/gdb/dap/events.py +++ b/gdb/python/lib/gdb/dap/events.py @@ -161,7 +161,7 @@ _expected_pause = False @in_gdb_thread -def exec_and_expect_stop(cmd, expected_pause=False, propagate_exception=False): +def exec_and_expect_stop(cmd, expected_pause=False): """A wrapper for exec_and_log that sets the continue-suppression flag. When EXPECTED_PAUSE is True, a stop that looks like a pause (e.g., @@ -174,7 +174,7 @@ def exec_and_expect_stop(cmd, expected_pause=False, propagate_exception=False): # continuing. _suppress_cont = not expected_pause # FIXME if the call fails should we clear _suppress_cont? - exec_and_log(cmd, propagate_exception) + exec_and_log(cmd) # Map from gdb stop reasons to DAP stop reasons. Some of these can't diff --git a/gdb/python/lib/gdb/dap/next.py b/gdb/python/lib/gdb/dap/next.py index 898fff1..993e9d2 100644 --- a/gdb/python/lib/gdb/dap/next.py +++ b/gdb/python/lib/gdb/dap/next.py @@ -17,7 +17,7 @@ import gdb from .events import exec_and_expect_stop from .server import capability, request -from .startup import in_gdb_thread +from .startup import DAPException, exec_and_log, in_gdb_thread from .state import set_thread @@ -36,11 +36,9 @@ def _handle_thread_step(thread_id, single_thread, select=False): result = False arg = "off" try: - # This can fail, depending on the target, so catch the error - # and report to our caller. We can't use exec_and_log because - # that does not propagate exceptions. - gdb.execute("set scheduler-locking " + arg, from_tty=True, to_string=True) - except gdb.error: + # This can fail, depending on the target, so catch any error. + exec_and_log("set scheduler-locking " + arg) + except DAPException: result = False # Other DAP code may select a frame, and the "finish" command uses # the selected frame. @@ -76,7 +74,7 @@ def step_in( @request("stepOut") def step_out(*, threadId: int, singleThread: bool = False, **args): _handle_thread_step(threadId, singleThread, True) - exec_and_expect_stop("finish &", propagate_exception=True) + exec_and_expect_stop("finish &") @request("continue") diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index 7dab582..98a8084 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -398,7 +398,7 @@ class Server: # responses are flushed to the client before exiting. self._write_queue.put(None) json_writer.join() - send_gdb("quit") + send_gdb(lambda: exec_and_log("quit")) @in_dap_thread def set_defer_events(self): @@ -614,7 +614,7 @@ def terminate(**args): @capability("supportTerminateDebuggee") def disconnect(*, terminateDebuggee: bool = False, **args): if terminateDebuggee: - send_gdb_with_response("kill") + send_gdb_with_response(lambda: exec_and_log("kill")) _server.shutdown() @@ -633,18 +633,6 @@ def cancel(**args): return None -class Invoker(object): - """A simple class that can invoke a gdb command.""" - - def __init__(self, cmd): - self._cmd = cmd - - # This is invoked in the gdb thread to run the command. - @in_gdb_thread - def __call__(self): - exec_and_log(self._cmd) - - class Cancellable(object): def __init__(self, fn, result_q=None): @@ -677,25 +665,16 @@ class Cancellable(object): def send_gdb(cmd): """Send CMD to the gdb thread. - CMD can be either a function or a string. - If it is a string, it is passed to gdb.execute.""" - if isinstance(cmd, str): - cmd = Invoker(cmd) - + CMD is a function.""" # Post the event and don't wait for the result. gdb.post_event(Cancellable(cmd)) def send_gdb_with_response(fn): """Send FN to the gdb thread and return its result. - If FN is a string, it is passed to gdb.execute and None is - returned as the result. If FN throws an exception, this function will throw the same exception in the calling thread. """ - if isinstance(fn, str): - fn = Invoker(fn) - # Post the event and wait for the result in result_q. result_q = DAPQueue() gdb.post_event(Cancellable(fn, result_q)) diff --git a/gdb/python/lib/gdb/dap/startup.py b/gdb/python/lib/gdb/dap/startup.py index ab3e8fd..0c95ada 100644 --- a/gdb/python/lib/gdb/dap/startup.py +++ b/gdb/python/lib/gdb/dap/startup.py @@ -204,7 +204,7 @@ def log_stack(level=LogLevel.DEFAULT): @in_gdb_thread -def exec_and_log(cmd, propagate_exception=False): +def exec_and_log(cmd): """Execute the gdb command CMD. If logging is enabled, log the command and its output.""" log("+++ " + cmd) @@ -213,10 +213,10 @@ def exec_and_log(cmd, propagate_exception=False): if output != "": log(">>> " + output) except gdb.error as e: - if propagate_exception: - raise DAPException(str(e)) from e - else: - log_stack() + # Don't normally want to see this, as it interferes with the + # test suite. + log_stack(LogLevel.FULL) + raise DAPException(str(e)) from e @in_gdb_thread diff --git a/gdb/python/lib/gdb/dap/varref.py b/gdb/python/lib/gdb/dap/varref.py index 8a13c51..d18197b 100644 --- a/gdb/python/lib/gdb/dap/varref.py +++ b/gdb/python/lib/gdb/dap/varref.py @@ -146,6 +146,10 @@ class BaseReference(ABC): if self._children is None: self._children = [None] * self.child_count() for idx in range(start, start + count): + if idx >= len(self._children): + raise DAPException( + f"requested child {idx} outside range of variable {self._ref}" + ) if self._children[idx] is None: (name, value) = self.fetch_one_child(idx) name = self._compute_name(name) @@ -242,7 +246,11 @@ class VariableReference(BaseReference): # changed DAP to allow memory references for any of the # variable response requests, and to lift the restriction # to pointer-to-function from Variable. - if self._value.type.strip_typedefs().code == gdb.TYPE_CODE_PTR: + if ( + self._value.type.strip_typedefs().code == gdb.TYPE_CODE_PTR + and not self._value.is_optimized_out + and not self._value.is_unavailable + ): result["memoryReference"] = hex(int(self._value)) if client_bool_capability("supportsVariableType"): result["type"] = str(self._value.type) diff --git a/gdb/python/lib/gdb/printing.py b/gdb/python/lib/gdb/printing.py index cba27d2..f1ac19d 100644 --- a/gdb/python/lib/gdb/printing.py +++ b/gdb/python/lib/gdb/printing.py @@ -415,10 +415,21 @@ def make_visualizer(value): result = NoOpArrayPrinter(ty, value) elif ty.code in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION): result = NoOpStructPrinter(ty, value) - elif ty.code in ( - gdb.TYPE_CODE_PTR, - gdb.TYPE_CODE_REF, - gdb.TYPE_CODE_RVALUE_REF, + elif ( + ty.code + in ( + gdb.TYPE_CODE_PTR, + gdb.TYPE_CODE_REF, + gdb.TYPE_CODE_RVALUE_REF, + ) + # Avoid "void *" here because those pointers can't be + # dereferenced without a cast. + and ty.target().code != gdb.TYPE_CODE_VOID + # An optimized-out or unavailable pointer should just be + # treated as a scalar, since there's no way to dereference + # it. + and not value.is_optimized_out + and not value.is_unavailable ): result = NoOpPointerReferencePrinter(value) else: diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c index fa7dd19..66ccad7 100644 --- a/gdb/python/py-block.c +++ b/gdb/python/py-block.c @@ -356,6 +356,9 @@ block_to_block_object (const struct block *block, struct objfile *objfile) } result = PyObject_New (block_object, &block_object_type); + if (result == nullptr) + return nullptr; + result->block = block; result->objfile = objfile; diff --git a/gdb/python/py-disasm.c b/gdb/python/py-disasm.c index 17064dc..47ae99c 100644 --- a/gdb/python/py-disasm.c +++ b/gdb/python/py-disasm.c @@ -254,15 +254,15 @@ disasm_info_object_is_valid (disasm_info_object *obj) /* Fill in OBJ with all the other arguments. */ static void -disasm_info_fill (disasm_info_object *obj, struct gdbarch *gdbarch, +disasm_info_fill (disasm_info_object &obj, struct gdbarch *gdbarch, program_space *progspace, bfd_vma address, disassemble_info *di, disasm_info_object *next) { - obj->gdbarch = gdbarch; - obj->program_space = progspace; - obj->address = address; - obj->gdb_info = di; - obj->next = next; + obj.gdbarch = gdbarch; + obj.program_space = progspace; + obj.address = address; + obj.gdb_info = di; + obj.next = next; } /* Implement DisassembleInfo.__init__. Takes a single argument that must @@ -281,7 +281,7 @@ disasm_info_init (PyObject *self, PyObject *args, PyObject *kwargs) disasm_info_object *other = (disasm_info_object *) info_obj; disasm_info_object *info = (disasm_info_object *) self; - disasm_info_fill (info, other->gdbarch, other->program_space, + disasm_info_fill (*info, other->gdbarch, other->program_space, other->address, other->gdb_info, other->next); other->next = info; @@ -1156,19 +1156,18 @@ gdbpy_disassembler::gdbpy_disassembler (disasm_info_object *obj) happens when gdbpy_print_insn returns. This class is responsible for marking the DisassembleInfo as invalid in its destructor. */ -struct scoped_disasm_info_object +struct scoped_invalidate_disasm_info { - /* Constructor. */ - scoped_disasm_info_object (struct gdbarch *gdbarch, CORE_ADDR memaddr, - disassemble_info *info) - : m_disasm_info (allocate_disasm_info_object ()) + /* Constructor. Just cache DISASM_INFO for use in the destructor. */ + scoped_invalidate_disasm_info + (gdbpy_ref<disasm_info_object> disasm_info) + : m_disasm_info (std::move (disasm_info)) { - disasm_info_fill (m_disasm_info.get (), gdbarch, current_program_space, - memaddr, info, nullptr); + /* Nothing. */ } /* Upon destruction mark m_disasm_info as invalid. */ - ~scoped_disasm_info_object () + ~scoped_invalidate_disasm_info () { /* Invalidate the original DisassembleInfo object as well as any copies that the user might have made. */ @@ -1178,30 +1177,15 @@ struct scoped_disasm_info_object obj->gdb_info = nullptr; } - /* Return a pointer to the underlying disasm_info_object instance. */ - disasm_info_object * - get () const - { - return m_disasm_info.get (); - } - private: - /* Wrapper around the call to PyObject_New, this wrapper function can be - called from the constructor initialization list, while PyObject_New, a - macro, can't. */ - static disasm_info_object * - allocate_disasm_info_object () - { - return (disasm_info_object *) PyObject_New (disasm_info_object, - &disasm_info_object_type); - } - /* A reference to a gdb.disassembler.DisassembleInfo object. When this - containing instance goes out of scope this reference is released, - however, the user might be holding other references to the - DisassembleInfo object in Python code, so the underlying object might - not be deleted. */ + object goes out of scope this reference is released, however, the user + might be holding other references to the DisassembleInfo (either + directly, or via copies of this object), in which case the underlying + object will not be deleted. The destructor of this class ensures + that this DisassembleInfo object, and any copies, are all marked + invalid. */ gdbpy_ref<disasm_info_object> m_disasm_info; }; @@ -1242,17 +1226,30 @@ gdbpy_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr, return {}; } - /* Create the new DisassembleInfo object we will pass into Python. This - object will be marked as invalid when we leave this scope. */ - scoped_disasm_info_object scoped_disasm_info (gdbarch, memaddr, info); - disasm_info_object *disasm_info = scoped_disasm_info.get (); + /* Create the new DisassembleInfo object we will pass into Python. */ + gdbpy_ref<disasm_info_object> disasm_info + ((disasm_info_object *) PyObject_New (disasm_info_object, + &disasm_info_object_type)); + if (disasm_info == nullptr) + { + gdbpy_print_stack (); + return {}; + } + + /* Initialise the DisassembleInfo object. */ + disasm_info_fill (*disasm_info.get (), gdbarch, current_program_space, + memaddr, info, nullptr); + + /* Ensure the DisassembleInfo, along with any copies the user makes, are + marked as invalid when we leave this scope. */ + scoped_invalidate_disasm_info invalidate_disasm (disasm_info); /* Call into the registered disassembler to (possibly) perform the disassembly. */ - PyObject *insn_disas_obj = (PyObject *) disasm_info; - gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (), - insn_disas_obj, - nullptr)); + gdbpy_ref<> result + (PyObject_CallFunctionObjArgs (hook.get (), + (PyObject *) disasm_info.get (), + nullptr)); if (result == nullptr) { diff --git a/gdb/python/py-event-types.def b/gdb/python/py-event-types.def index 15cd9fa..83167f3 100644 --- a/gdb/python/py-event-types.def +++ b/gdb/python/py-event-types.def @@ -54,7 +54,7 @@ GDB_PY_DEFINE_EVENT_TYPE (new_thread, GDB_PY_DEFINE_EVENT_TYPE (thread_exited, "ThreadExitedEvent", "GDB thread exited event object", - event_object_type); + thread_event_object_type); GDB_PY_DEFINE_EVENT_TYPE (new_inferior, "NewInferiorEvent", diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c index 0ea629f..70e1684 100644 --- a/gdb/python/py-finishbreakpoint.c +++ b/gdb/python/py-finishbreakpoint.c @@ -175,7 +175,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) struct frame_id frame_id; PyObject *internal = NULL; int internal_bp = 0; - CORE_ADDR pc; + std::optional<CORE_ADDR> pc; if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords, &frame_obj, &internal)) @@ -249,9 +249,9 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) try { - if (get_frame_pc_if_available (frame, &pc)) + if ((pc = get_frame_pc_if_available (frame))) { - struct symbol *function = find_pc_function (pc); + struct symbol *function = find_pc_function (*pc); if (function != nullptr) { struct type *ret_type = diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c index adf4233..db8c274 100644 --- a/gdb/python/py-framefilter.c +++ b/gdb/python/py-framefilter.c @@ -168,7 +168,7 @@ mi_should_print (struct symbol *sym, enum mi_print_types type) { int print_me = 0; - switch (sym->aclass ()) + switch (sym->loc_class ()) { default: case LOC_UNDEF: /* catches errors */ diff --git a/gdb/python/py-infevents.c b/gdb/python/py-infevents.c index e63ba52..f74fb01 100644 --- a/gdb/python/py-infevents.c +++ b/gdb/python/py-infevents.c @@ -40,7 +40,7 @@ create_inferior_call_event_object (inferior_call_kind flag, ptid_t ptid, gdb_assert_not_reached ("invalid inferior_call_kind"); } - gdbpy_ref<> ptid_obj (gdbpy_create_ptid_object (ptid)); + gdbpy_ref<> ptid_obj = gdbpy_create_ptid_object (ptid); if (ptid_obj == NULL) return NULL; diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c index 4f1f8d4..08533fe 100644 --- a/gdb/python/py-infthread.c +++ b/gdb/python/py-infthread.c @@ -190,7 +190,7 @@ thpy_get_ptid (PyObject *self, void *closure) THPY_REQUIRE_VALID (thread_obj); - return gdbpy_create_ptid_object (thread_obj->thread->ptid); + return gdbpy_create_ptid_object (thread_obj->thread->ptid).release (); } /* Implement gdb.InferiorThread.ptid_string attribute. */ @@ -361,23 +361,14 @@ thpy_repr (PyObject *self) target_pid_to_str (thr->ptid).c_str ()); } -/* Return a reference to a new Python object representing a ptid_t. - The object is a tuple containing (pid, lwp, tid). */ -PyObject * +/* See python-internal.h. */ + +gdbpy_ref<> gdbpy_create_ptid_object (ptid_t ptid) { - int pid; - long lwp; - ULONGEST tid; - PyObject *ret; - - ret = PyTuple_New (3); - if (!ret) - return NULL; - - pid = ptid.pid (); - lwp = ptid.lwp (); - tid = ptid.tid (); + int pid = ptid.pid (); + long lwp = ptid.lwp (); + ULONGEST tid = ptid.tid (); gdbpy_ref<> pid_obj = gdb_py_object_from_longest (pid); if (pid_obj == nullptr) @@ -389,10 +380,14 @@ gdbpy_create_ptid_object (ptid_t ptid) if (tid_obj == nullptr) return nullptr; + gdbpy_ref<> ret (PyTuple_New (3)); + if (ret == nullptr) + return nullptr; + /* Note that these steal references, hence the use of 'release'. */ - PyTuple_SET_ITEM (ret, 0, pid_obj.release ()); - PyTuple_SET_ITEM (ret, 1, lwp_obj.release ()); - PyTuple_SET_ITEM (ret, 2, tid_obj.release ()); + PyTuple_SET_ITEM (ret.get (), 0, pid_obj.release ()); + PyTuple_SET_ITEM (ret.get (), 1, lwp_obj.release ()); + PyTuple_SET_ITEM (ret.get (), 2, tid_obj.release ()); return ret; } diff --git a/gdb/python/py-mi.c b/gdb/python/py-mi.c index 9b871d4..b2ab4e2 100644 --- a/gdb/python/py-mi.c +++ b/gdb/python/py-mi.c @@ -218,11 +218,11 @@ py_object_to_mi_key (PyObject *key_obj) { gdb_assert (name != nullptr); - if (*name == '\0' || !isalpha (*name)) + if (*name == '\0' || !c_isalpha (*name)) return false; for (; *name != '\0'; ++name) - if (!isalnum (*name) && *name != '_' && *name != '-') + if (!c_isalnum (*name) && *name != '_' && *name != '-') return false; return true; @@ -363,7 +363,7 @@ gdbpy_notify_mi (PyObject *self, PyObject *args, PyObject *kwargs) } for (int i = 0; i < name_len; i++) { - if (!isalnum (name[i]) && name[i] != '-') + if (!c_isalnum (name[i]) && name[i] != '-') { PyErr_Format (PyExc_ValueError, diff --git a/gdb/python/py-micmd.c b/gdb/python/py-micmd.c index 72f427f..07db0cc 100644 --- a/gdb/python/py-micmd.c +++ b/gdb/python/py-micmd.c @@ -350,7 +350,7 @@ micmdpy_init (PyObject *self, PyObject *args, PyObject *kwargs) PyErr_SetString (PyExc_ValueError, _("MI command name is empty.")); return -1; } - else if ((name_len < 2) || (name[0] != '-') || !isalnum (name[1])) + else if ((name_len < 2) || (name[0] != '-') || !c_isalnum (name[1])) { PyErr_SetString (PyExc_ValueError, _("MI command name does not start with '-'" @@ -361,7 +361,7 @@ micmdpy_init (PyObject *self, PyObject *args, PyObject *kwargs) { for (int i = 2; i < name_len; i++) { - if (!isalnum (name[i]) && name[i] != '-') + if (!c_isalnum (name[i]) && name[i] != '-') { PyErr_Format (PyExc_ValueError, diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c index 1c6f569..a9f5754 100644 --- a/gdb/python/py-objfile.c +++ b/gdb/python/py-objfile.c @@ -556,7 +556,7 @@ objfpy_build_id_ok (const char *string) return 0; for (i = 0; i < n; ++i) { - if (!isxdigit (string[i])) + if (!c_isxdigit (string[i])) return 0; } return 1; @@ -619,9 +619,8 @@ gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw) struct objfile *objfile = nullptr; if (by_build_id) - gdbarch_iterate_over_objfiles_in_search_order - (current_inferior ()->arch (), - [&objfile, name] (struct objfile *obj) + current_program_space->iterate_over_objfiles_in_search_order + ([&objfile, name] (struct objfile *obj) { /* Don't return separate debug files. */ if (obj->separate_debug_objfile_backlink != nullptr) @@ -642,9 +641,8 @@ gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw) return 1; }, gdbpy_current_objfile); else - gdbarch_iterate_over_objfiles_in_search_order - (current_inferior ()->arch (), - [&objfile, name] (struct objfile *obj) + current_program_space->iterate_over_objfiles_in_search_order + ([&objfile, name] (struct objfile *obj) { /* Don't return separate debug files. */ if (obj->separate_debug_objfile_backlink != nullptr) diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c index 7e7904b..89c2e77 100644 --- a/gdb/python/py-record.c +++ b/gdb/python/py-record.c @@ -696,6 +696,9 @@ gdbpy_current_recording (PyObject *self, PyObject *args) Py_RETURN_NONE; ret = PyObject_New (recpy_record_object, &recpy_record_type); + if (ret == nullptr) + return nullptr; + ret->thread = inferior_thread (); ret->method = target_record_method (ret->thread->ptid); diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c index 3028a30..284e385 100644 --- a/gdb/python/py-symbol.c +++ b/gdb/python/py-symbol.c @@ -126,7 +126,7 @@ sympy_get_addr_class (PyObject *self, void *closure) SYMPY_REQUIRE_VALID (self, symbol); - return gdb_py_object_from_longest (symbol->aclass ()).release (); + return gdb_py_object_from_longest (symbol->loc_class ()).release (); } /* Implement gdb.Symbol.domain attribute. Return the domain as an @@ -156,42 +156,39 @@ static PyObject * sympy_is_constant (PyObject *self, void *closure) { struct symbol *symbol = NULL; - enum address_class theclass; SYMPY_REQUIRE_VALID (self, symbol); - theclass = symbol->aclass (); + location_class loc_class = symbol->loc_class (); - return PyBool_FromLong (theclass == LOC_CONST || theclass == LOC_CONST_BYTES); + return PyBool_FromLong (loc_class == LOC_CONST || loc_class == LOC_CONST_BYTES); } static PyObject * sympy_is_function (PyObject *self, void *closure) { struct symbol *symbol = NULL; - enum address_class theclass; SYMPY_REQUIRE_VALID (self, symbol); - theclass = symbol->aclass (); + location_class loc_class = symbol->loc_class (); - return PyBool_FromLong (theclass == LOC_BLOCK); + return PyBool_FromLong (loc_class == LOC_BLOCK); } static PyObject * sympy_is_variable (PyObject *self, void *closure) { struct symbol *symbol = NULL; - enum address_class theclass; SYMPY_REQUIRE_VALID (self, symbol); - theclass = symbol->aclass (); + location_class loc_class = symbol->loc_class (); return PyBool_FromLong (!symbol->is_argument () - && (theclass == LOC_LOCAL || theclass == LOC_REGISTER - || theclass == LOC_STATIC || theclass == LOC_COMPUTED - || theclass == LOC_OPTIMIZED_OUT)); + && (loc_class == LOC_LOCAL || loc_class == LOC_REGISTER + || loc_class == LOC_STATIC || loc_class == LOC_COMPUTED + || loc_class == LOC_OPTIMIZED_OUT)); } /* Implementation of Symbol.is_artificial. */ @@ -279,7 +276,7 @@ sympy_value (PyObject *self, PyObject *args) } SYMPY_REQUIRE_VALID (self, symbol); - if (symbol->aclass () == LOC_TYPEDEF) + if (symbol->loc_class () == LOC_TYPEDEF) { PyErr_SetString (PyExc_TypeError, "cannot get the value of a typedef"); return NULL; @@ -605,17 +602,15 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw) /* Expand any symtabs that contain potentially matching symbols. */ lookup_name_info lookup_name (name, symbol_name_match_type::FULL); - expand_symtabs_matching (NULL, lookup_name, NULL, NULL, - SEARCH_STATIC_BLOCK, flags); for (objfile *objfile : current_program_space->objfiles ()) { - for (compunit_symtab *cust : objfile->compunits ()) + auto callback = [&] (compunit_symtab *cust) { /* Skip included compunits to prevent including compunits from being searched twice. */ if (cust->user != nullptr) - continue; + return true; const struct blockvector *bv = cust->blockvector (); const struct block *block = bv->static_block (); @@ -628,13 +623,18 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw) if (symbol != nullptr) { PyObject *sym_obj = symbol_to_symbol_object (symbol); - if (sym_obj == nullptr) - return nullptr; - if (PyList_Append (return_list.get (), sym_obj) == -1) - return nullptr; + if (sym_obj == nullptr + || PyList_Append (return_list.get (), sym_obj) == -1) + return false; } } - } + + return true; + }; + + if (!objfile->search (nullptr, &lookup_name, nullptr, callback, + SEARCH_STATIC_BLOCK, flags)) + return nullptr; } } catch (const gdb_exception &except) diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c index c546aa7..a2c5939 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -1045,9 +1045,9 @@ typy_template_argument (PyObject *self, PyObject *args) } sym = TYPE_TEMPLATE_ARGUMENT (type, argno); - if (sym->aclass () == LOC_TYPEDEF) + if (sym->loc_class () == LOC_TYPEDEF) return type_to_type_object (sym->type ()); - else if (sym->aclass () == LOC_OPTIMIZED_OUT) + else if (sym->loc_class () == LOC_OPTIMIZED_OUT) { PyErr_Format (PyExc_RuntimeError, _("Template argument is optimized out")); @@ -1312,10 +1312,9 @@ static PyObject * typy_has_key (PyObject *self, PyObject *args) { struct type *type = ((type_object *) self)->type; - const char *field; - int i; + const char *field_name; - if (!PyArg_ParseTuple (args, "s", &field)) + if (!PyArg_ParseTuple (args, "s", &field_name)) return NULL; /* We want just fields of this type, not of base types, so instead of @@ -1326,11 +1325,11 @@ typy_has_key (PyObject *self, PyObject *args) if (type == NULL) return NULL; - for (i = 0; i < type->num_fields (); i++) + for (const auto &field : type->fields ()) { - const char *t_field_name = type->field (i).name (); + const char *t_field_name = field.name (); - if (t_field_name && (strcmp_iw (t_field_name, field) == 0)) + if (t_field_name && (strcmp_iw (t_field_name, field_name) == 0)) Py_RETURN_TRUE; } Py_RETURN_FALSE; diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c index dc078ec..43125bb 100644 --- a/gdb/python/py-unwind.c +++ b/gdb/python/py-unwind.c @@ -287,6 +287,8 @@ pyuw_create_unwind_info (PyObject *pyo_pending_frame, unwind_info_object *unwind_info = PyObject_New (unwind_info_object, &unwind_info_object_type); + if (unwind_info == nullptr) + return nullptr; unwind_info->frame_id = frame_id; Py_INCREF (pyo_pending_frame); diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 8a2e263..5d8fab9 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -478,6 +478,9 @@ valpy_get_dynamic_type (PyObject *self, void *closure) type = value_rtti_type (val, NULL, NULL, NULL); else type = val->type (); + + if (type == nullptr) + type = val->type (); } catch (const gdb_exception &except) { @@ -1288,6 +1291,30 @@ valpy_get_is_optimized_out (PyObject *self, void *closure) Py_RETURN_FALSE; } +/* Implements gdb.Value.is_unavailable. Return true if any part of the + value is unavailable. */ + +static PyObject * +valpy_get_is_unavailable (PyObject *self, void *closure) +{ + struct value *value = ((value_object *) self)->value; + bool entirely_available = false; + + try + { + entirely_available = value->entirely_available (); + } + catch (const gdb_exception &except) + { + return gdbpy_handle_gdb_exception (nullptr, except); + } + + if (!entirely_available) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + /* Implements gdb.Value.is_lazy. */ static PyObject * valpy_get_is_lazy (PyObject *self, void *closure) @@ -1842,7 +1869,7 @@ valpy_long (PyObject *self) { struct value *value = ((value_object *) self)->value; struct type *type = value->type (); - LONGEST l = 0; + PyObject *result; try { @@ -1858,17 +1885,57 @@ valpy_long (PyObject *self) && type->code () != TYPE_CODE_PTR) error (_("Cannot convert value to long.")); - l = value_as_long (value); + gdb::array_view<const gdb_byte> contents = value->contents (); +#if PY_VERSION_HEX >= 0x030d0000 + int flags = (type_byte_order (type) == BFD_ENDIAN_BIG + ? Py_ASNATIVEBYTES_BIG_ENDIAN + : Py_ASNATIVEBYTES_LITTLE_ENDIAN); + if (type->is_unsigned ()) + flags |= Py_ASNATIVEBYTES_UNSIGNED_BUFFER; + result = PyLong_FromNativeBytes (contents.data (), contents.size (), + flags); +#else + /* Here we construct a call to "int.from_bytes", passing in the + appropriate arguments. We need a somewhat roundabout + approach because int.from_bytes requires "signed" to be a + keyword arg. */ + + /* PyObject_Call requires a tuple argument. */ + gdbpy_ref<> empty_tuple (PyTuple_New (0)); + if (empty_tuple == nullptr) + return nullptr; + + /* Since we need a dictionary anyway, we pass all arguments as + keywords, building the dictionary here. */ + gdbpy_ref<> args + (Py_BuildValue ("{sy#sssO}", + "bytes", contents.data (), + (Py_ssize_t) contents.size (), + "byteorder", + (type_byte_order (type) == BFD_ENDIAN_BIG + ? "big" : "little"), + "signed", + type->is_unsigned () + ? Py_False : Py_True)); + if (args == nullptr) + return nullptr; + + /* Find the "int.from_bytes" callable. */ + gdbpy_ref<> callable (PyObject_GetAttrString ((PyObject *) &PyLong_Type, + "from_bytes")); + if (callable == nullptr) + return nullptr; + + result = PyObject_Call (callable.get (), empty_tuple.get (), + args.get ()); +#endif } catch (const gdb_exception &except) { return gdbpy_handle_gdb_exception (nullptr, except); } - if (type->is_unsigned ()) - return gdb_py_object_from_ulongest (l).release (); - else - return gdb_py_object_from_longest (l).release (); + return result; } /* Implements conversion to float. */ @@ -2194,6 +2261,9 @@ static gdb_PyGetSetDef value_object_getset[] = { "Boolean telling whether the value is optimized " "out (i.e., not available).", NULL }, + { "is_unavailable", valpy_get_is_unavailable, nullptr, + "Boolean telling whether the value is unavailable.", + nullptr }, { "type", valpy_get_type, NULL, "Type of the value.", NULL }, { "dynamic_type", valpy_get_dynamic_type, NULL, "Dynamic type of the value.", NULL }, diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 7f4237e..f61a175 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -503,7 +503,12 @@ PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length, const char *encoding, struct type *type); PyObject *gdbpy_inferiors (PyObject *unused, PyObject *unused2); -PyObject *gdbpy_create_ptid_object (ptid_t ptid); + +/* Return a reference to a new Python Tuple object representing a ptid_t. + The object is a tuple containing (pid, lwp, tid). */ + +extern gdbpy_ref<> gdbpy_create_ptid_object (ptid_t ptid); + PyObject *gdbpy_selected_thread (PyObject *self, PyObject *args); PyObject *gdbpy_selected_inferior (PyObject *self, PyObject *args); PyObject *gdbpy_string_to_argv (PyObject *self, PyObject *args); diff --git a/gdb/python/python.c b/gdb/python/python.c index cb0d642..740b196 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -31,7 +31,6 @@ #include "python.h" #include "extension-priv.h" #include "cli/cli-utils.h" -#include <ctype.h> #include "location.h" #include "run-on-main-thread.h" #include "observable.h" @@ -1202,15 +1201,22 @@ gdbpy_post_event (PyObject *self, PyObject *args) static PyObject * gdbpy_interrupt (PyObject *self, PyObject *args) { +#ifdef __MINGW32__ { - /* Make sure the interrupt isn't delivered immediately somehow. - This probably is not truly needed, but at the same time it - seems more clear to be explicit about the intent. */ gdbpy_allow_threads temporarily_exit_python; scoped_disable_cooperative_sigint_handling no_python_sigint; set_quit_flag (); } +#else + { + /* For targets with support kill() just send SIGINT. This will be + handled as if the user hit Ctrl+C. This isn't exactly the same as + the above, which directly sets the quit flag. Consider, for + example, every place that install_sigint_handler is called. */ + kill (getpid (), SIGINT); + } +#endif Py_RETURN_NONE; } @@ -1570,21 +1576,21 @@ gdbpy_write (PyObject *self, PyObject *args, PyObject *kw) try { + ui_file *stream; switch (stream_type) { case 1: - { - gdb_printf (gdb_stderr, "%s", arg); - break; - } + stream = gdb_stderr; + break; case 2: - { - gdb_printf (gdb_stdlog, "%s", arg); - break; - } + stream = gdb_stdlog; + break; default: - gdb_printf (gdb_stdout, "%s", arg); + stream = gdb_stdout; + break; } + + gdb_puts (arg, stream); } catch (const gdb_exception &except) { |