From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1726) id 2A9403858D38; Sun, 2 Oct 2022 16:28:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2A9403858D38 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1664728081; bh=zZ3VtLmP3JKuZQFeH9GxcoBEkLM7+9SHj9mkqj2NYj0=; h=From:To:Subject:Date:From; b=g7d7lOB1MQMdkLB66pjhiffSD/UkIQRtmgpjn60cwldnGRN6Ftb6zDUEXWOFEoiv1 lkH/iI+tP7CR+bBluCiMkZeSE4Ouf+5Zht6hpGw2rMEXsMZB+yekcwhnDeZ4ERgoSN 6S3BFYvJ0U/aNTeklIhaDJ8JN7bLEro9NtbbiL04= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Andrew Burgess To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdb: add asserts to gdbarch_register_name X-Act-Checkin: binutils-gdb X-Git-Author: Andrew Burgess X-Git-Refname: refs/heads/master X-Git-Oldrev: 9a103324fee16bf4d0bc4fa7b19f5d937d47b881 X-Git-Newrev: 7df4240040277fb752fd010f5a947cf2d32bc3a5 Message-Id: <20221002162801.2A9403858D38@sourceware.org> Date: Sun, 2 Oct 2022 16:28:01 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D7df424004027= 7fb752fd010f5a947cf2d32bc3a5 commit 7df4240040277fb752fd010f5a947cf2d32bc3a5 Author: Andrew Burgess Date: Thu Sep 1 14:01:11 2022 +0100 gdb: add asserts to gdbarch_register_name =20 This commit adds asserts to gdbarch_register_name that validate the parameters, and the return value. =20 The interesting thing here is that gdbarch_register_name is generated by gdbarch.py, and so, to add these asserts, I need to update the generation script. =20 I've added two new arguments for Functions and Methods (as declared in gdbarch-components.py), these arguments are 'param_checks' and 'result_checks'. Each of these new arguments can be used to list some expressions that are then used within gdb_assert calls in the generated code. =20 The asserts that validate the API as described in the comment I added to gdbarch_register_name a few commits back; the register number passed in needs to be a valid cooked register number, and the result being returned should not be nullptr. Diff: --- gdb/gdbarch-components.py | 16 ++++++++++++++++ gdb/gdbarch.c | 6 +++++- gdb/gdbarch.py | 21 ++++++++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py index 9e0a3e99417..b8d7648d5ec 100644 --- a/gdb/gdbarch-components.py +++ b/gdb/gdbarch-components.py @@ -99,6 +99,20 @@ # argument, and NAME is the name. Note that while the names could be # auto-generated, this approach lets the "comment" field refer to # arguments in a nicer way. It is also just nicer for users. +# +# * "param_checks" - optional, a list of strings. Each string is an +# expression that is placed within a gdb_assert before the call is +# made to the Function/Method implementation. Each expression is +# something that should be true, and it is expected that the +# expression will make use of the parameters named in 'params' (though +# this is not required). +# +# * "result_checks" - optional, a list of strings. Each string is an +# expression that is placed within a gdb_assert after the call to the +# Function/Method implementation. Within each expression the variable +# 'result' can be used to reference the result of the function/method +# implementation. The 'result_checks' can only be used if the 'type' +# of this Function/Method is not 'void'. =20 Info( type=3D"const struct bfd_arch_info *", @@ -568,6 +582,8 @@ should never return nullptr. type=3D"const char *", name=3D"register_name", params=3D[("int", "regnr")], + param_checks=3D["regnr >=3D 0", "regnr < gdbarch_num_cooked_regs (gdba= rch)"], + result_checks=3D["result !=3D nullptr"], predefault=3D"0", invalid=3DTrue, ) diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index be73d399069..4b0c10be402 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -2235,9 +2235,13 @@ gdbarch_register_name (struct gdbarch *gdbarch, int = regnr) { gdb_assert (gdbarch !=3D NULL); gdb_assert (gdbarch->register_name !=3D NULL); + gdb_assert (regnr >=3D 0); + gdb_assert (regnr < gdbarch_num_cooked_regs (gdbarch)); if (gdbarch_debug >=3D 2) gdb_printf (gdb_stdlog, "gdbarch_register_name called\n"); - return gdbarch->register_name (gdbarch, regnr); + auto result =3D gdbarch->register_name (gdbarch, regnr); + gdb_assert (result !=3D nullptr); + return result; } =20 void diff --git a/gdb/gdbarch.py b/gdb/gdbarch.py index 696b3028e6f..da848feae84 100755 --- a/gdb/gdbarch.py +++ b/gdb/gdbarch.py @@ -49,6 +49,11 @@ class _Component: setattr(self, key, kwargs[key]) components.append(self) =20 + # It doesn't make sense to have a check of the result value + # for a function or method with void return type. + if self.type =3D=3D "void" and self.result_checks: + raise Exception("can't have result checks with a void return t= ype") + def get_predicate(self): "Return the expression used for validity checking." assert self.predicate and not isinstance(self.invalid, str) @@ -112,6 +117,8 @@ class Function(_Component): postdefault=3DNone, invalid=3DNone, printer=3DNone, + param_checks=3DNone, + result_checks=3DNone, ): super().__init__( comment=3Dcomment, @@ -123,6 +130,8 @@ class Function(_Component): invalid=3Dinvalid, printer=3Dprinter, params=3Dparams, + param_checks=3Dparam_checks, + result_checks=3Dresult_checks, ) =20 def ftype(self): @@ -444,6 +453,9 @@ with open("gdbarch.c", "w") as f: f" /* Do not check predicate: {c.get_predicate()}, al= low call. */", file=3Df, ) + if c.param_checks: + for rule in c.param_checks: + print(f" gdb_assert ({rule});", file=3Df) print(" if (gdbarch_debug >=3D 2)", file=3Df) print( f""" gdb_printf (gdb_stdlog, "gdbarch_{c.name} called\\= n");""", @@ -451,8 +463,15 @@ with open("gdbarch.c", "w") as f: ) print(" ", file=3Df, end=3D"") if c.type !=3D "void": - print("return ", file=3Df, end=3D"") + if c.result_checks: + print("auto result =3D ", file=3Df, end=3D"") + else: + print("return ", file=3Df, end=3D"") print(f"gdbarch->{c.name} ({c.actuals()});", file=3Df) + if c.type !=3D "void" and c.result_checks: + for rule in c.result_checks: + print(f" gdb_assert ({rule});", file=3Df) + print(" return result;", file=3Df) print("}", file=3Df) print(file=3Df) print("void", file=3Df)