From: Doug Evans Date: Fri, 10 Aug 2012 20:26:00 +0000 (+0000) Subject: Add $_memeq, $_regex, $_streq, $_strlen convenience functions. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a72c32530ec5ee0b1baf366ba99db5f2e83681cb;p=binutils-gdb.git Add $_memeq, $_regex, $_streq, $_strlen convenience functions. * NEWS: Document them. * data-directory/Makefile.in (PYTHON_FILES): Add function/__init__.py, function/strfns.py. * python/py-type.c (typy_array_1): New function. (typy_array): Call it. (typy_vector): New function. (type_object_methods): Add "vector". * python/lib/gdb/function/__init__.py: New file. * python/lib/gdb/function/strfns.py: New file. doc/ * gdb.texinfo (Convenience Funs): New node. (Types In Python): Document Type.vector. testsuite/ * gdb.python/py-strfns.c: New file. * gdb.python/py-strfns.exp: New file. * gdb.python/py-type.exp (test_fields): Add vector tests. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8de8ba73e22..1a31059d108 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2012-08-10 Doug Evans + + Add $_memeq, $_regex, $_streq, $_strlen convenience functions. + * NEWS: Document them. + * data-directory/Makefile.in (PYTHON_FILES): Add function/__init__.py, + function/strfns.py. + * python/py-type.c (typy_array_1): New function. + (typy_array): Call it. + (typy_vector): New function. + (type_object_methods): Add "vector". + * python/lib/gdb/function/__init__.py: New file. + * python/lib/gdb/function/strfns.py: New file. + 2012-08-10 Siddhesh Poyarekar * python/py-type.c (convert_field): Use gdb_py_long_from_longest diff --git a/gdb/NEWS b/gdb/NEWS index d693e64dd8b..942597d7220 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,17 @@ *** Changes since GDB 7.5 +* Python scripting + + ** Vectors can be created with gdb.Type.vector. + +* New Python-based convenience functions: + + ** $_memeq(buf1, buf2, length) + ** $_streq(str1, str2) + ** $_strlen(str) + ** $_regex(str, regex) + * The 'cd' command now defaults to using '~' (the home directory) if not given an argument. diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in index 87c6dd47047..41947c63d29 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in @@ -59,7 +59,9 @@ PYTHON_FILES = \ gdb/command/__init__.py \ gdb/command/pretty_printers.py \ gdb/command/prompt.py \ - gdb/command/explore.py + gdb/command/explore.py \ + gdb/function/__init__.py \ + gdb/function/strfns.py FLAGS_TO_PASS = \ "prefix=$(prefix)" \ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index cfd2bd52426..4318d8416b6 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2012-08-10 Doug Evans + + * gdb.texinfo (Convenience Funs): New node. + (Types In Python): Document Type.vector. + 2012-08-09 Yao Qi * observer.texi: New observer command_param_changed. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a03532ee675..5cc5b48780d 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -7558,6 +7558,7 @@ being passed the type of @var{arg} as the argument. * Pretty Printing:: Python pretty printing * Value History:: Value history * Convenience Vars:: Convenience variables +* Convenience Funs:: Convenience functions * Registers:: Registers * Floating Point Hardware:: Floating point hardware * Vector Unit:: Vector Unit @@ -9311,6 +9312,9 @@ On HP-UX systems, if you refer to a function or variable name that begins with a dollar sign, @value{GDBN} searches for a user or system name first, before it searches for a convenience variable. +@node Convenience Funs +@section Convenience Functions + @cindex convenience functions @value{GDBN} also supplies some @dfn{convenience functions}. These have a syntax similar to convenience variables. A convenience @@ -9318,6 +9322,38 @@ function can be used in an expression just like an ordinary function; however, a convenience function is implemented internally to @value{GDBN}. +These functions require @value{GDBN} to be configured with +@code{Python} support. + +@table @code + +@item $_memeq(@var{buf1}, @var{buf2}, @var{length}) +@findex $_memeq@r{, convenience function} +Returns one if the @var{length} bytes at the addresses given by +@var{buf1} and @var{buf2} are equal. +Otherwise it returns zero. + +@item $_regex(@var{str}, @var{regex}) +@findex $_regex@r{, convenience function} +Returns one if the string @var{str} matches the regular expression +@var{regex}. Otherwise it returns zero. +The syntax of the regular expression is that specified by @code{Python}'s +regular expression support. + +@item $_streq(@var{str1}, @var{str2}) +@findex $_streq@r{, convenience function} +Returns one if the strings @var{str1} and @var{str2} are equal. +Otherwise it returns zero. + +@item $_strlen(@var{str}) +@findex $_strlen@r{, convenience function} +Returns the length of string @var{str}. + +@end table + +@value{GDBN} provides the ability to list and get help on +convenience functions. + @table @code @item help function @kindex help function @@ -23361,6 +23397,19 @@ second argument is the upper bound of the array. An array's length must not be negative, but the bounds can be. @end defun +@defun Type.vector (@var{n1} @r{[}, @var{n2}@r{]}) +Return a new @code{gdb.Type} object which represents a vector of this +type. If one argument is given, it is the inclusive upper bound of +the vector; in this case the lower bound is zero. If two arguments are +given, the first argument is the lower bound of the vector, and the +second argument is the upper bound of the vector. A vector's length +must not be negative, but the bounds can be. + +The difference between an @code{array} and a @code{vector} is that +arrays behave like in C: when used in expressions they decay to a pointer +to the first element whereas vectors are treated as first class values. +@end defun + @defun Type.const () Return a new @code{gdb.Type} object which represents a @code{const}-qualified variant of this type. diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py new file mode 100644 index 00000000000..b669fb669de --- /dev/null +++ b/gdb/python/lib/gdb/function/__init__.py @@ -0,0 +1,14 @@ +# Copyright (C) 2012 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 . diff --git a/gdb/python/lib/gdb/function/strfns.py b/gdb/python/lib/gdb/function/strfns.py new file mode 100644 index 00000000000..baab5bdd465 --- /dev/null +++ b/gdb/python/lib/gdb/function/strfns.py @@ -0,0 +1,108 @@ +# Useful gdb string convenience functions. +# Copyright (C) 2012 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 . + +"""$_memeq, $_strlen, $_streq, $_regex""" + +import gdb +import re + + +class _MemEq(gdb.Function): + """$_memeq - compare bytes of memory + +Usage: + $_memeq(a, b, len) + +Returns: + True if len bytes at a and b compare equally. +""" + def __init__(self): + super(_MemEq, self).__init__("_memeq") + + def invoke(self, a, b, length): + if length < 0: + raise ValueError("length must be non-negative") + if length == 0: + return True + # The argument(s) to vector are [low_bound,]high_bound. + byte_vector = gdb.lookup_type("char").vector(length - 1) + ptr_byte_vector = byte_vector.pointer() + a_ptr = a.reinterpret_cast(ptr_byte_vector) + b_ptr = b.reinterpret_cast(ptr_byte_vector) + return a_ptr.dereference() == b_ptr.dereference() + + +class _StrLen(gdb.Function): + """$_strlen - compute string length + +Usage: + $_strlen(a) + +Returns: + Length of string a, assumed to be a string in the current language. +""" + def __init__(self): + super(_StrLen, self).__init__("_strlen") + + def invoke(self, a): + s = a.string() + return len(s) + + +class _StrEq(gdb.Function): + """$_streq - check string equality + +Usage: + $_streq(a, b) + +Returns: + True if a and b are identical strings in the current language. + +Example (amd64-linux): + catch syscall open + cond $bpnum $_streq((char*) $rdi, "foo") +""" + def __init__(self): + super(_StrEq, self).__init__("_streq") + + def invoke(self, a, b): + return a.string() == b.string() + + +class _RegEx(gdb.Function): + """$_regex - check if a string matches a regular expression + +Usage: + $_regex(string, regex) + +Returns: + True if string str (in the current language) matches the + regular expression regex. +""" + def __init__(self): + super(_RegEx, self).__init__("_regex") + + def invoke(self, string, regex): + s = string.string() + r = re.compile(regex.string()) + return bool(r.match(s)) + + +# GDB will import us automagically via gdb/__init__.py. +_MemEq() +_StrLen() +_StrEq() +_RegEx() diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c index a02402ef02b..b10f9d034d4 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -461,10 +461,10 @@ typy_get_composite (struct type *type) return type; } -/* Return an array type. */ +/* Helper for typy_array and typy_vector. */ static PyObject * -typy_array (PyObject *self, PyObject *args) +typy_array_1 (PyObject *self, PyObject *args, int is_vector) { long n1, n2; PyObject *n2_obj = NULL; @@ -503,12 +503,30 @@ typy_array (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { array = lookup_array_range_type (type, n1, n2); + if (is_vector) + make_vector_type (array); } GDB_PY_HANDLE_EXCEPTION (except); return type_to_type_object (array); } +/* Return an array type. */ + +static PyObject * +typy_array (PyObject *self, PyObject *args) +{ + return typy_array_1 (self, args, 0); +} + +/* Return a vector type. */ + +static PyObject * +typy_vector (PyObject *self, PyObject *args) +{ + return typy_array_1 (self, args, 1); +} + /* Return a Type object which represents a pointer to SELF. */ static PyObject * typy_pointer (PyObject *self, PyObject *args) @@ -1559,6 +1577,14 @@ static PyMethodDef type_object_methods[] = Return a type which represents an array of objects of this type.\n\ The bounds of the array are [LOW_BOUND, HIGH_BOUND] inclusive.\n\ If LOW_BOUND is omitted, a value of zero is used." }, + { "vector", typy_vector, METH_VARARGS, + "vector ([LOW_BOUND,] HIGH_BOUND) -> Type\n\ +Return a type which represents a vector of objects of this type.\n\ +The bounds of the array are [LOW_BOUND, HIGH_BOUND] inclusive.\n\ +If LOW_BOUND is omitted, a value of zero is used.\n\ +Vectors differ from arrays in that if the current language has C-style\n\ +arrays, vectors don't decay to a pointer to the first element.\n\ +They are first class values." }, { "__contains__", typy_has_key, METH_VARARGS, "T.__contains__(k) -> True if T has a field named k, else False" }, { "const", typy_const, METH_NOARGS, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 3113c6a6ca3..27fe40ce369 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-08-10 Doug Evans + + * gdb.python/py-strfns.c: New file. + * gdb.python/py-strfns.exp: New file. + * gdb.python/py-type.exp (test_fields): Add vector tests. + 2012-08-10 Mike Frysinger PR cli/10436: diff --git a/gdb/testsuite/gdb.python/py-strfns.c b/gdb/testsuite/gdb.python/py-strfns.c new file mode 100644 index 00000000000..db38bd9ed86 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-strfns.c @@ -0,0 +1,50 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 . */ + +const char str1[] = "Hello."; +const char str2[] = "Hello."; +const char str3[] = "Goodbye."; + +const char buf1[] = { 0, 1, 2, 3 }; +const char buf2[] = { 0, 1, 2, 3 }; +const char buf3[] = { 0, 1, 2, 4 }; + +static void +func (const char *arg) +{ + return; /* Break func here. */ +} + +static void +bfunc (const char *arg) +{ + return; /* Break bfunc here. */ +} + +int +main () +{ + func (str1); + func (str2); + func (str3); + + bfunc (buf1); + bfunc (buf2); + bfunc (buf3); + + return 0; +} diff --git a/gdb/testsuite/gdb.python/py-strfns.exp b/gdb/testsuite/gdb.python/py-strfns.exp new file mode 100644 index 00000000000..88d6cdf8134 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-strfns.exp @@ -0,0 +1,103 @@ +# Copyright (C) 2012 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 . + +# This file is part of the GDB testsuite. It tests the convenience +# functions in strfns.py. + +load_lib gdb-python.exp + +standard_testfile + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { + return -1 +} + +if ![runto_main] { + return 0 +} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +proc test_all_strfns { } { + gdb_test "p \$_streq (str1, str2)" " = 1" + gdb_test "p \$_streq (str1, str3)" " = 0" + + gdb_test "p \$_strlen (str1)" " = 6" + gdb_test "p \$_strlen (buf1)" " = 0" + + gdb_test "p \$_memeq (buf1, buf2, 4)" " = 1" + gdb_test "p \$_memeq (buf1, buf3, 4)" " = 0" + + gdb_test {p $_regex (str1, "Hello")} " = 1" + gdb_test {p $_regex (str1, "Help")} " = 0" + gdb_test {p $_regex (str1, "^Hello")} " = 1" + gdb_test {p $_regex (str1, "^Hello.$")} " = 1" +} + +test_all_strfns + +# Verify use in a conditional breakpoint. + +gdb_breakpoint [gdb_get_line_number "Break func here."] +gdb_test_no_output "condition \$bpnum \$_streq (arg, \"Goodbye.\")" +gdb_continue_to_breakpoint "Break func here." +gdb_test "p arg" "= $hex \"Goodbye.\"" + +gdb_breakpoint [gdb_get_line_number "Break bfunc here."] +gdb_test_no_output "condition \$bpnum \$_memeq (arg, buf3, 4)" +gdb_continue_to_breakpoint "Break bfunc here." +gdb_test "p /d {char\[4\]} arg" "= \\{0, 1, 2, 4\\}" + +# Verify use on a core file. + +proc test_strfns_core_file { } { + global objdir subdir gdb_prompt testfile + + set filename "${objdir}/${subdir}/py-strfns.core" + set escapedfilename [string_to_regexp $filename] + + gdb_test_multiple "gcore $filename" \ + "save a corefile" \ + { + -re "Saved corefile ${escapedfilename}\[\r\n\]+$gdb_prompt $" { + pass "save a corefile" + } + -re "Can't create a corefile\[\r\n\]+$gdb_prompt $" { + unsupported "save a corefile" + # No use proceeding from here. + return + } + } + + clean_restart $testfile + + gdb_test_multiple "core $filename" \ + "re-load generated corefile" \ + { + -re "Core was generated by .*$gdb_prompt $" { + pass "re-load generated corefile" + } + -re ".*$gdb_prompt $" { + fail "re-load generated corefile" + # No use proceeding from here. + return + } + } + + test_all_strfns +} + +test_strfns_core_file diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp index 98a055e06eb..b997c51d65e 100644 --- a/gdb/testsuite/gdb.python/py-type.exp +++ b/gdb/testsuite/gdb.python/py-type.exp @@ -114,12 +114,27 @@ proc test_fields {lang} { gdb_test "python print len(fields)" "1" "Check the number of fields" gdb_test "python print fields\[0\].type" "" "Check array field type" + # Test gdb.Type.array. gdb_test "python print ar\[0\].cast(ar\[0\].type.array(1))" \ ".1, 2." "cast to array with one argument" gdb_test "python print ar\[0\].cast(ar\[0\].type.array(0, 1))" \ ".1, 2." "cast to array with two arguments" gdb_test "python print ar\[0\].type == ar\[0\].type" "True" + + # Test gdb.Type.vector. + # Note: vectors cast differently than arrays. Here ar[0] is replicated + # for the size of the vector. + gdb_py_test_silent_cmd \ + "python vec1 = ar\[0\].cast(ar\[0\].type.vector(1))" "set vec1" 1 + gdb_test "python print vec1" ".1, 1." "cast to vector with one argument" + gdb_py_test_silent_cmd \ + "python vec2 = ar\[0\].cast(ar\[0\].type.vector(0, 1))" "set vec2" 1 + gdb_test "python print vec2" ".1, 1." "cast to vector with two arguments" + gdb_test "python print vec1 == vec2" "True" + gdb_py_test_silent_cmd \ + "python vec3 = ar\[1\].cast(ar\[1\].type.vector(1))" "set vec3" 1 + gdb_test "python print vec1 == vec3" "False" } proc test_enums {} {