From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id iT6/GuFChmpFXTEAWB0awg (envelope-from ) for ; Wed, 19 Aug 2026 19:57:21 -0400 Authentication-Results: simark.ca; dkim=fail reason="signature verification failed" (768-bit key; unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=pSNtGuVs; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 66FAD1E0A3; Wed, 19 Aug 2026 19:57:21 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.1 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 9A9AA1E09B for ; Wed, 19 Aug 2026 19:57:19 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9A6934B99F7C for ; Wed, 19 Aug 2026 23:57:18 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9A6934B99F7C Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (768-bit key, unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=pSNtGuVs Received: from omta040.useast.a.cloudfilter.net (omta040.useast.a.cloudfilter.net [44.202.169.39]) by sourceware.org (Postfix) with ESMTPS id 7ECF84BA9037 for ; Wed, 19 Aug 2026 23:54:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7ECF84BA9037 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tromey.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tromey.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 7ECF84BA9037 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=44.202.169.39 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787183683; cv=none; b=CdsMpK0J32RStfI/Pvfx2V61Queh+pykLOuuu1ee1fmuHXFy0HoWlb5529LGm4GiCc4z60b+8Nh81xKRkdnwstHqdYPH3+wk991xfiYwHRp0B0SOXDoq7C8xoLSwvCdtZ0PHYZlEvqsLNpIjikbaAkbB1vZMUk2+TQ6I7nY9570= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787183683; c=relaxed/simple; bh=VuN5I/asr2c4YKCvO2V0gPeLOEPHgwNBVMnceBuOuMo=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=LXqooHt1amviOWMCx6PPoVpQknJOrXIXxiykIgLhHyuKvj1Pfr5qCmslqmrupCyJT5Zllv14ExkSP1QgwgT1b/RN+daMhcehbzd3L0TXFPVu52wuuizH8bGaGIoa5/Hf2VGT/lLB500NzNe1CGCF0HIpLYjxll/ESajgU5PjnT8= ARC-Authentication-Results: i=1; sourceware.org; dkim=policy (768-bit key, unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=pSNtGuVs reason="signing key too small" DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7ECF84BA9037 Received: from eig-obgw-6005b.ext.cloudfilter.net ([10.0.30.162]) by cmsmtp with ESMTPS id wgYxwQWMVuFzgwq7GwHmkU; Wed, 19 Aug 2026 23:54:43 +0000 Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with ESMTPS id wq7GwJoQ4OYlBwq7GwYxEd; Wed, 19 Aug 2026 23:54:42 +0000 X-Authority-Analysis: v=2.4 cv=FLYbx/os c=1 sm=1 tr=0 ts=6a864242 a=ApxJNpeYhEAb1aAlGBBbmA==:117 a=ApxJNpeYhEAb1aAlGBBbmA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=ItBw4LHWJt0A:10 a=p7_mzhCJ6SsjLMJcPA0A:9 a=QMvGyNdsn17uVFDd:21 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=O8hF6Hzn-FEA:10 a=DCx65vhANUyCzuf5D8fC:22 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Cc:To:In-Reply-To:References:Message-Id: Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date:From:Sender: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=ExT1odnLt9IWE7R1eMAx1zny6Tla/nDNqvlvn88zxLE=; b=pSNtGuVs7dHJdnpg/T+Zswt+jX S6GpCkVJm9yjIzLDXQ+SSLKqgSUpMmclAKQ7k1v4bFRr/uJuLhs9vzNsfDXGdSiv211qFA6cKWzNs wOrnjsm8y28qS+LkTsr2dbW0G; Received: from 75-166-225-82.hlrn.qwest.net ([75.166.225.82]:36824 helo=[192.168.122.1]) by box5379.bluehost.com with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.99.5) (envelope-from ) id 1wwq7F-000000020o1-2qfm; Wed, 19 Aug 2026 17:54:41 -0600 From: Tom Tromey Date: Wed, 19 Aug 2026 17:54:39 -0600 Subject: [PATCH 1/4] Basic safety conversion of py-frame.c MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260819-python-safety-frame-v1-1-563cb6b9e7a6@tromey.com> References: <20260819-python-safety-frame-v1-0-563cb6b9e7a6@tromey.com> In-Reply-To: <20260819-python-safety-frame-v1-0-563cb6b9e7a6@tromey.com> To: gdb-patches@sourceware.org Cc: Tom Tromey X-Mailer: b4 0.14.3 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box5379.bluehost.com X-AntiAbuse: Original Domain - sourceware.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 75.166.225.82 X-Source-L: No X-Exim-ID: 1wwq7F-000000020o1-2qfm X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 75-166-225-82.hlrn.qwest.net ([192.168.122.1]) [75.166.225.82]:36824 X-Source-Auth: tom+tromey.com X-Email-Count: 2 X-Org: HG=bhshared;ORG=bluehost; X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes X-CMAE-Envelope: MS4xfE6OmNnSkGN1HNjeGfom079syfpPQnjdmwyKp68xTmgRSIykzq1z1V+wma8WYsRe6KACZeKzjjuWdAoF8FQXGliV1xaDnIamsPl55S3v21nqk7pT/r32 Iq0arbtKB5cRCKKToCGo17bqTcAR+pvaZgFKWr3NGGTJsAyG/UYITOyw/cyTskiX2rD/RQP4Fw4YSriJ0eide3IkjvF3q/V2Ax8= X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org This converts the bulk of py-frame.c to the new Python safety API. --- gdb/python/py-frame.c | 764 +++++++++++++++++++------------------------------- 1 file changed, 289 insertions(+), 475 deletions(-) diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index afa89f0d112..5c5ff8cf0de 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -32,22 +32,125 @@ struct frame_object : public PyObject { struct frame_id frame_id; struct gdbarch *gdbarch; + + /* Marks that the FRAME_ID member actually holds the ID of the frame next + to this, and not this frames' ID itself. This is a hack to permit Python + frame objects which represent invalid frames (i.e., the last frame_info + in a corrupt stack). The problem arises from the fact that this code + relies on FRAME_ID to uniquely identify a frame, which is not always true + for the last "frame" in a corrupt stack (it can have a null ID, or the same + ID as the previous frame). Whenever get_prev_frame returns NULL, we + record the frame_id of the next frame and set FRAME_ID_IS_NEXT to 1. */ + int frame_id_is_next; + + /* Return the associated frame. Throws an exception on error. */ + frame_info_ptr require_frame () + { + frame_info_ptr frame = frame_object_to_frame_info (this); + /* FIXME: Python safety. frame_object_to_frame_info should be + converted, but the callers aren't ready yet. */ + if (frame == nullptr) + gdbpy_err_format (PyExc_RuntimeError, _("Frame is invalid.")); + return frame; + } + + /* Called by the Python interpreter to obtain string representation + of the object. */ + gdbpy_ref<> str () + { + return gdbpy_unicode_from_string (frame_id.to_string ()); + } + + /* Implement repr() for gdb.Frame. */ + gdbpy_ref<> repr (); + + /* Implementation of gdb.Frame.is_valid (self) -> Boolean. Returns + True if the frame corresponding to the frame_id of this object + still exists in the inferior. */ + bool is_valid () + { + return frame_object_to_frame_info (this) != nullptr; + } + + /* Implementation of gdb.Frame.name (self) -> String. + Returns the name of the function corresponding to this frame. */ + gdb::unique_xmalloc_ptr name (); + + /* Implementation of gdb.Frame.type (self) -> Integer. + Returns the frame type, namely one of the gdb.*_FRAME constants. */ + ULONGEST type (); + + /* Implementation of gdb.Frame.architecture (self) -> gdb.Architecture. + Returns the frame's architecture as a gdb.Architecture object. */ + gdbpy_ref<> arch (); + + /* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. + Returns one of the gdb.FRAME_UNWIND_* constants. */ + int unwind_stop_reason (); + + /* Implementation of gdb.Frame.pc (self) -> Long. + Returns the frame's resume address. */ + ULONGEST pc (); + + /* Implementation of gdb.Frame.read_register (self, register) -> gdb.Value. + Returns the value of a register in this frame. */ + gdbpy_ref<> read_register (gdbpy_borrowed_ref<> args, + gdbpy_opt_borrowed_ref<> kw); + + /* Implementation of gdb.Frame.block (self) -> gdb.Block. + Returns the frame's code block. */ + gdbpy_ref<> block (); + + /* Implementation of gdb.Frame.function (self) -> gdb.Symbol. + Returns the symbol for the function corresponding to this frame. */ + gdbpy_ref<> function (); + + /* Implementation of gdb.Frame.older (self) -> gdb.Frame. + Returns the frame immediately older (outer) to this frame, or None if + there isn't one. */ + gdbpy_ref<> older (); + + /* Implementation of gdb.Frame.newer (self) -> gdb.Frame. + Returns the frame immediately newer (inner) to this frame, or None if + there isn't one. */ + gdbpy_ref<> newer (); + + /* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line. + Returns the frame's symtab and line. */ + gdbpy_ref<> find_sal (); + + /* Implementation of gdb.Frame.read_var_value (self, variable, + [block]) -> gdb.Value. If the optional block argument is provided + start the search from that block, otherwise search from the frame's + current block (determined by examining the resume address of the + frame). The variable argument must be a string or an instance of a + gdb.Symbol. The block argument must be an instance of gdb.Block. Returns + NULL on error, with a python exception set. */ + gdbpy_ref<> read_var (gdbpy_borrowed_ref<> args, + gdbpy_opt_borrowed_ref<> kw); + + /* Select this frame. */ + void select (); + + /* The stack frame level for this frame. */ + int level (); + + /* The language for this frame. */ + const char *language (); + + /* The static link for this frame. */ + gdbpy_ref<> static_link (); + + static PyTypeObject *corresponding_object_type; }; static_assert (gdb::is_python_allocatable_v); -/* Require a valid frame. This must be called inside a TRY_CATCH, or - another context in which a gdb exception is allowed. */ -#define FRAPY_REQUIRE_VALID(frame_obj, frame) \ - do { \ - frame = frame_object_to_frame_info (frame_obj); \ - if (frame == NULL) \ - error (_("Frame is invalid.")); \ - } while (0) - /* Returns the frame_info object corresponding to the given Python Frame object. If the frame doesn't exist anymore (the frame id doesn't correspond to any frame in the inferior), returns NULL. */ +/* FIXME: Python safety. This function should be converted, but the + callers aren't ready yet. */ frame_info_ptr frame_object_to_frame_info (PyObject *obj) @@ -62,291 +165,127 @@ frame_object_to_frame_info (PyObject *obj) return frame; } -/* Called by the Python interpreter to obtain string representation - of the object. */ - -static PyObject * -frapy_str (PyObject *self) -{ - const frame_id &fid = ((frame_object *) self)->frame_id; - return PyUnicode_FromString (fid.to_string ().c_str ()); -} - -/* Implement repr() for gdb.Frame. */ - -static PyObject * -frapy_repr (PyObject *self) +gdbpy_ref<> +frame_object::repr () { - frame_object *frame_obj = (frame_object *) self; - frame_info_ptr f_info = frame_find_by_id (frame_obj->frame_id); + frame_info_ptr f_info = frame_find_by_id (frame_id); if (f_info == nullptr) - return gdb_py_invalid_object_repr (self); - - const frame_id &fid = frame_obj->frame_id; - return PyUnicode_FromFormat ("<%s level=%d frame-id=%s>", - gdbpy_py_obj_tp_name (self).c_str (), - frame_relative_level (f_info), - fid.to_string ().c_str ()); + /* FIXME: Python safety. gdb_py_invalid_object_repr should + throw on error. */ + return gdbpy_ref<> (gdb_py_invalid_object_repr (this)); + + return gdbpy_unicode_from_format ("<%s level=%d frame-id=%s>", + gdbpy_py_obj_tp_name (this).c_str (), + frame_relative_level (f_info), + frame_id.to_string ().c_str ()); } -/* Implementation of gdb.Frame.is_valid (self) -> Boolean. - Returns True if the frame corresponding to the frame_id of this - object still exists in the inferior. */ - -static PyObject * -frapy_is_valid (PyObject *self, PyObject *args) +gdb::unique_xmalloc_ptr +frame_object::name () { - frame_info_ptr frame = NULL; - - try - { - frame = frame_object_to_frame_info (self); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - if (frame == NULL) - return py_false ().release (); - - return py_true ().release (); -} - -/* Implementation of gdb.Frame.name (self) -> String. - Returns the name of the function corresponding to this frame. */ - -static PyObject * -frapy_name (PyObject *self, PyObject *args) -{ - frame_info_ptr frame; - gdb::unique_xmalloc_ptr name; + frame_info_ptr frame = require_frame (); enum language lang; - PyObject *result; - - try - { - FRAPY_REQUIRE_VALID (self, frame); - - name = find_frame_funname (frame, &lang, NULL); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - if (name) - { - result = PyUnicode_Decode (name.get (), strlen (name.get ()), - host_charset (), NULL); - } - else - { - result = py_none ().release (); - } - - return result; + return find_frame_funname (frame, &lang, nullptr); } -/* Implementation of gdb.Frame.type (self) -> Integer. - Returns the frame type, namely one of the gdb.*_FRAME constants. */ - -static PyObject * -frapy_type (PyObject *self, PyObject *args) +ULONGEST +frame_object::type () { - frame_info_ptr frame; - enum frame_type type = NORMAL_FRAME;/* Initialize to appease gcc warning. */ - - try - { - FRAPY_REQUIRE_VALID (self, frame); - - type = get_frame_type (frame); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - return gdb_py_object_from_longest (type).release (); + frame_info_ptr frame = require_frame (); + return get_frame_type (frame); } -/* Implementation of gdb.Frame.architecture (self) -> gdb.Architecture. - Returns the frame's architecture as a gdb.Architecture object. */ - -static PyObject * -frapy_arch (PyObject *self, PyObject *args) +gdbpy_ref<> +frame_object::arch () { - frame_info_ptr frame = NULL; /* Initialize to appease gcc warning. */ - frame_object *obj = (frame_object *) self; - - try - { - FRAPY_REQUIRE_VALID (self, frame); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - return gdbarch_to_arch_object (obj->gdbarch).release (); + require_frame (); + return gdbarch_to_arch_object (gdbarch); } -/* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. - Returns one of the gdb.FRAME_UNWIND_* constants. */ - -static PyObject * -frapy_unwind_stop_reason (PyObject *self, PyObject *args) +int +frame_object::unwind_stop_reason () { - frame_info_ptr frame = NULL; /* Initialize to appease gcc warning. */ - enum unwind_stop_reason stop_reason; - - try - { - FRAPY_REQUIRE_VALID (self, frame); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - stop_reason = get_frame_unwind_stop_reason (frame); - - return gdb_py_object_from_longest (stop_reason).release (); + frame_info_ptr frame = require_frame (); + return get_frame_unwind_stop_reason (frame); } -/* Implementation of gdb.Frame.pc (self) -> Long. - Returns the frame's resume address. */ - -static PyObject * -frapy_pc (PyObject *self, PyObject *args) +ULONGEST +frame_object::pc () { - CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ - frame_info_ptr frame; - - try - { - FRAPY_REQUIRE_VALID (self, frame); - - pc = get_frame_pc (frame); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - return gdb_py_object_from_ulongest (pc).release (); + frame_info_ptr frame = require_frame (); + return get_frame_pc (frame); } -/* Implementation of gdb.Frame.read_register (self, register) -> gdb.Value. - Returns the value of a register in this frame. */ - -static PyObject * -frapy_read_register (PyObject *self, PyObject *args, PyObject *kw) +gdbpy_ref<> +frame_object::read_register (gdbpy_borrowed_ref<> args, + gdbpy_opt_borrowed_ref<> kw) { PyObject *pyo_reg_id; - gdbpy_ref<> result; static const char *keywords[] = { "register", nullptr }; - if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O", keywords, &pyo_reg_id)) - return nullptr; - - try - { - scoped_value_mark free_values; - frame_info_ptr frame; - int regnum; - - FRAPY_REQUIRE_VALID (self, frame); - - if (!gdbpy_parse_register_id (get_frame_arch (frame), pyo_reg_id, - ®num)) - return nullptr; + gdbpy_arg_parse_tuple_and_keywords (args, kw, "O", keywords, &pyo_reg_id); - gdb_assert (regnum >= 0); - value *val - = value_of_register (regnum, get_next_frame_sentinel_okay (frame)); + scoped_value_mark free_values; + frame_info_ptr frame = require_frame (); - if (val == NULL) - PyErr_SetString (PyExc_ValueError, _("Can't read register.")); - else - result = value_to_value_object (val); - } - catch (const gdb_exception &except) + int regnum; + if (!gdbpy_parse_register_id (get_frame_arch (frame), pyo_reg_id, ®num)) { - return gdbpy_handle_gdb_exception (nullptr, except); + /* FIXME: Python safety. gdbpy_parse_register_id should throw + on error. */ + throw gdb_python_exception (); } - return result.release (); -} + gdb_assert (regnum >= 0); + value *val + = value_of_register (regnum, get_next_frame_sentinel_okay (frame)); -/* Implementation of gdb.Frame.block (self) -> gdb.Block. - Returns the frame's code block. */ + if (val == nullptr) + gdbpy_err_set_string (PyExc_ValueError, _("Can't read register.")); -static PyObject * -frapy_block (PyObject *self, PyObject *args) -{ - frame_info_ptr frame; - const struct block *block = NULL, *fn_block; + return value_to_value_object (val); +} - try - { - FRAPY_REQUIRE_VALID (self, frame); - block = get_frame_block (frame, NULL); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } +gdbpy_ref<> +frame_object::block () +{ + frame_info_ptr frame = require_frame (); + const struct block *block = get_frame_block (frame, nullptr); + const struct block *fn_block; for (fn_block = block; fn_block != NULL && fn_block->function () == NULL; fn_block = fn_block->superblock ()) ; if (block == NULL || fn_block == NULL || fn_block->function () == NULL) - { - PyErr_SetString (PyExc_RuntimeError, - _("Cannot locate block for frame.")); - return NULL; - } + gdbpy_err_set_string (PyExc_RuntimeError, + _("Cannot locate block for frame.")); - return block_to_block_object (block, - fn_block->function ()->objfile ()).release (); + return block_to_block_object (block, fn_block->function ()->objfile ()); } -/* Implementation of gdb.Frame.function (self) -> gdb.Symbol. - Returns the symbol for the function corresponding to this frame. */ - -static PyObject * -frapy_function (PyObject *self, PyObject *args) +gdbpy_ref<> +frame_object::function () { - struct symbol *sym = NULL; - frame_info_ptr frame; - - try - { - enum language funlang; + frame_info_ptr frame = require_frame (); - FRAPY_REQUIRE_VALID (self, frame); + struct symbol *sym = nullptr; + enum language funlang; + gdb::unique_xmalloc_ptr funname + = find_frame_funname (frame, &funlang, &sym); - gdb::unique_xmalloc_ptr funname - = find_frame_funname (frame, &funlang, &sym); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - if (sym) - return symbol_to_symbol_object (sym).release (); + if (sym != nullptr) + return symbol_to_symbol_object (sym); - return py_none ().release (); + return py_none (); } /* Convert a frame_info struct to a Python Frame object. Sets a Python exception and returns NULL on error. */ +/* FIXME: Python safety. This function should be converted, but the + callers aren't ready yet. */ gdbpy_ref<> frame_info_to_frame_object (const frame_info_ptr &frame) @@ -369,106 +308,51 @@ frame_info_to_frame_object (const frame_info_ptr &frame) return frame_obj; } -/* Implementation of gdb.Frame.older (self) -> gdb.Frame. - Returns the frame immediately older (outer) to this frame, or None if - there isn't one. */ - -static PyObject * -frapy_older (PyObject *self, PyObject *args) +gdbpy_ref<> +frame_object::older () { - frame_info_ptr frame, prev = NULL; - - try - { - FRAPY_REQUIRE_VALID (self, frame); + frame_info_ptr frame = require_frame (); + frame_info_ptr prev = get_prev_frame (frame); - prev = get_prev_frame (frame); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - gdbpy_ref<> prev_obj; if (prev) - prev_obj = frame_info_to_frame_object (prev); - else - prev_obj = py_none (); + return frame_info_to_frame_object (prev); - return prev_obj.release (); + return py_none (); } -/* Implementation of gdb.Frame.newer (self) -> gdb.Frame. - Returns the frame immediately newer (inner) to this frame, or None if - there isn't one. */ - -static PyObject * -frapy_newer (PyObject *self, PyObject *args) +gdbpy_ref<> +frame_object::newer () { - frame_info_ptr frame, next = NULL; - - try - { - FRAPY_REQUIRE_VALID (self, frame); - - next = get_next_frame (frame); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } + frame_info_ptr frame = require_frame (); + frame_info_ptr next = get_next_frame (frame); - gdbpy_ref<> next_obj; if (next) - next_obj = frame_info_to_frame_object (next); - else - next_obj = py_none (); + return frame_info_to_frame_object (next); - return next_obj.release (); + return py_none (); } -/* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line. - Returns the frame's symtab and line. */ - -static PyObject * -frapy_find_sal (PyObject *self, PyObject *args) +gdbpy_ref<> +frame_object::find_sal () { - frame_info_ptr frame; - - try - { - FRAPY_REQUIRE_VALID (self, frame); - - symtab_and_line sal = find_frame_sal (frame); - return symtab_and_line_to_sal_object (sal).release (); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } + frame_info_ptr frame = require_frame (); + symtab_and_line sal = find_frame_sal (frame); + return symtab_and_line_to_sal_object (sal); } -/* Implementation of gdb.Frame.read_var_value (self, variable, - [block]) -> gdb.Value. If the optional block argument is provided - start the search from that block, otherwise search from the frame's - current block (determined by examining the resume address of the - frame). The variable argument must be a string or an instance of a - gdb.Symbol. The block argument must be an instance of gdb.Block. Returns - NULL on error, with a python exception set. */ -static PyObject * -frapy_read_var (PyObject *self, PyObject *args, PyObject *kw) +gdbpy_ref<> +frame_object::read_var (gdbpy_borrowed_ref<> args, + gdbpy_opt_borrowed_ref<> kw) { - frame_info_ptr frame; PyObject *sym_obj, *block_obj = NULL; - struct symbol *var = NULL; /* gcc-4.3.2 false warning. */ - const struct block *block = NULL; static const char *keywords[] = { "variable", "block", nullptr }; - if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|O!", keywords, - &sym_obj, &block_object_type, - &block_obj)) - return nullptr; + gdbpy_arg_parse_tuple_and_keywords (args, kw, "O|O!", keywords, + &sym_obj, &block_object_type, + &block_obj); + const struct block *block = NULL; + struct symbol *var = NULL; /* gcc-4.3.2 false warning. */ if (PyObject_TypeCheck (sym_obj, &symbol_object_type)) var = symbol_object_to_symbol (sym_obj); else if (gdbpy_is_string (sym_obj)) @@ -476,8 +360,10 @@ frapy_read_var (PyObject *self, PyObject *args, PyObject *kw) gdb::unique_xmalloc_ptr var_name (python_string_to_target_string (sym_obj)); - if (!var_name) - return NULL; + /* FIXME: Python safety. python_string_to_target_string should + throw on error. */ + if (var_name == nullptr) + throw gdb_python_exception (); if (block_obj != nullptr) { @@ -488,139 +374,65 @@ frapy_read_var (PyObject *self, PyObject *args, PyObject *kw) gdb_assert (block != nullptr); } - try - { - struct block_symbol lookup_sym; - FRAPY_REQUIRE_VALID (self, frame); - - if (!block) - block = get_frame_block (frame, NULL); - lookup_sym = lookup_symbol (var_name.get (), block, - SEARCH_VFT, nullptr); - var = lookup_sym.symbol; - block = lookup_sym.block; - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } + frame_info_ptr frame = require_frame (); - if (!var) - { - PyErr_Format (PyExc_ValueError, - _("Variable '%s' not found."), var_name.get ()); + if (!block) + block = get_frame_block (frame, NULL); + block_symbol lookup_sym = lookup_symbol (var_name.get (), block, + SEARCH_VFT, nullptr); + var = lookup_sym.symbol; + block = lookup_sym.block; - return NULL; - } + if (var == nullptr) + gdbpy_err_format (PyExc_ValueError, + _("Variable '%s' not found."), var_name.get ()); } else - { - PyErr_Format (PyExc_TypeError, - _("argument 1 must be gdb.Symbol or str, not %s"), - gdbpy_py_obj_tp_name (sym_obj).c_str ()); - return NULL; - } - - gdbpy_ref<> result; - try - { - FRAPY_REQUIRE_VALID (self, frame); - - scoped_value_mark free_values; - struct value *val = read_var_value (var, block, frame); - result = value_to_value_object (val); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - return result.release (); + gdbpy_err_format (PyExc_TypeError, + _("argument 1 must be gdb.Symbol or str, not %s"), + gdbpy_py_obj_tp_name (sym_obj).c_str ()); + + frame_info_ptr frame = require_frame (); + scoped_value_mark free_values; + struct value *val = read_var_value (var, block, frame); + return value_to_value_object (val); } -/* Select this frame. */ - -static PyObject * -frapy_select (PyObject *self, PyObject *args) +void +frame_object::select () { - frame_info_ptr fi; - - try - { - FRAPY_REQUIRE_VALID (self, fi); - - select_frame (fi); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } - - return py_none ().release (); + frame_info_ptr fi = require_frame (); + select_frame (fi); } -/* The stack frame level for this frame. */ - -static PyObject * -frapy_level (PyObject *self, PyObject *args) +int +frame_object::level () { - frame_info_ptr fi; - - try - { - FRAPY_REQUIRE_VALID (self, fi); - - return gdb_py_object_from_longest (frame_relative_level (fi)).release (); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } + frame_info_ptr fi = require_frame (); + return frame_relative_level (fi); } -/* The language for this frame. */ - -static PyObject * -frapy_language (PyObject *self, PyObject *args) +const char * +frame_object::language () { - try - { - frame_info_ptr fi; - FRAPY_REQUIRE_VALID (self, fi); + frame_info_ptr fi = require_frame (); - enum language lang = get_frame_language (fi); - const language_defn *lang_def = language_def (lang); + enum language lang = get_frame_language (fi); + const language_defn *lang_def = language_def (lang); - return host_string_to_python_string (lang_def->name ()).release (); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } + return lang_def->name (); } -/* The static link for this frame. */ - -static PyObject * -frapy_static_link (PyObject *self, PyObject *args) +gdbpy_ref<> +frame_object::static_link () { - frame_info_ptr link; - - try - { - FRAPY_REQUIRE_VALID (self, link); - - link = frame_follow_static_link (link); - } - catch (const gdb_exception &except) - { - return gdbpy_handle_gdb_exception (nullptr, except); - } + frame_info_ptr link = require_frame (); + link = frame_follow_static_link (link); if (link == nullptr) - return py_none ().release (); + return py_none (); - return frame_info_to_frame_object (link).release (); + return frame_info_to_frame_object (link); } /* Implementation of gdb.newest_frame () -> gdb.Frame. @@ -712,6 +524,8 @@ frapy_richcompare (PyObject *self, PyObject *other, int op) return py_false ().release (); } +PyTypeObject *frame_object::corresponding_object_type = &frame_object_type; + /* Sets up the Frame API in the gdb module. */ static int @@ -750,54 +564,54 @@ GDBPY_INITIALIZE_FILE (gdbpy_initialize_frames); static PyMethodDef frame_object_methods[] = { - { "is_valid", frapy_is_valid, METH_NOARGS, + noargs_method ("is_valid", "is_valid () -> Boolean.\n\ -Return true if this frame is valid, false if not." }, - { "name", frapy_name, METH_NOARGS, +Return true if this frame is valid, false if not."), + noargs_method ("name", "name () -> String.\n\ -Return the function name of the frame, or None if it can't be determined." }, - { "type", frapy_type, METH_NOARGS, +Return the function name of the frame, or None if it can't be determined."), + noargs_method ("type", "type () -> Integer.\n\ -Return the type of the frame." }, - { "architecture", frapy_arch, METH_NOARGS, +Return the type of the frame."), + noargs_method ("architecture", "architecture () -> gdb.Architecture.\n\ -Return the architecture of the frame." }, - { "unwind_stop_reason", frapy_unwind_stop_reason, METH_NOARGS, - "unwind_stop_reason () -> Integer.\n\ -Return the reason why it's not possible to find frames older than this." }, - { "pc", frapy_pc, METH_NOARGS, +Return the architecture of the frame."), + noargs_method + ("unwind_stop_reason", + "unwind_stop_reason () -> Integer.\n\ +Return the reason why it's not possible to find frames older than this."), + noargs_method ("pc", "pc () -> Long.\n\ -Return the frame's resume address." }, - { "read_register", (PyCFunction) frapy_read_register, - METH_VARARGS | METH_KEYWORDS, +Return the frame's resume address."), + varargs_method ("read_register", "read_register (register_name) -> gdb.Value\n\ -Return the value of the register in the frame." }, - { "block", frapy_block, METH_NOARGS, +Return the value of the register in the frame."), + noargs_method ("block", "block () -> gdb.Block.\n\ -Return the frame's code block." }, - { "function", frapy_function, METH_NOARGS, +Return the frame's code block."), + noargs_method ("function", "function () -> gdb.Symbol.\n\ -Returns the symbol for the function corresponding to this frame." }, - { "older", frapy_older, METH_NOARGS, +Returns the symbol for the function corresponding to this frame."), + noargs_method ("older", "older () -> gdb.Frame.\n\ -Return the frame that called this frame." }, - { "newer", frapy_newer, METH_NOARGS, +Return the frame that called this frame."), + noargs_method ("newer", "newer () -> gdb.Frame.\n\ -Return the frame called by this frame." }, - { "find_sal", frapy_find_sal, METH_NOARGS, +Return the frame called by this frame."), + noargs_method ("find_sal", "find_sal () -> gdb.Symtab_and_line.\n\ -Return the frame's symtab and line." }, - { "read_var", (PyCFunction) frapy_read_var, METH_VARARGS | METH_KEYWORDS, +Return the frame's symtab and line."), + varargs_method ("read_var", "read_var (variable) -> gdb.Value.\n\ -Return the value of the variable in this frame." }, - { "select", frapy_select, METH_NOARGS, - "Select this frame as the user's current frame." }, - { "level", frapy_level, METH_NOARGS, - "The stack level of this frame." }, - { "language", frapy_language, METH_NOARGS, - "The language of this frame." }, - { "static_link", frapy_static_link, METH_NOARGS, - "The static link of this frame, or None." }, +Return the value of the variable in this frame."), + noargs_method ("select", + "Select this frame as the user's current frame."), + noargs_method ("level", + "The stack level of this frame."), + noargs_method ("language", + "The language of this frame."), + noargs_method ("static_link", + "The static link of this frame, or None."), {NULL} /* Sentinel */ }; @@ -811,13 +625,13 @@ PyTypeObject frame_object_type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - frapy_repr, /* tp_repr */ + wrap_tp_callback, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ - frapy_str, /* tp_str */ + wrap_tp_callback, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ -- 2.49.0