From b800b0622b80f7e60e6bb8cae747468ecd986ec0 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 25 Nov 2021 22:12:48 +0800 Subject: [PATCH 01/19] Add PLUGIN_FINISH_PARSE_FUNCTION support This is one great callbacks provided by GCC. Signed-off-by: Yihao Wu --- gcc-python-callbacks.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gcc-python-callbacks.c b/gcc-python-callbacks.c index e8a42aa8..0d83d28d 100644 --- a/gcc-python-callbacks.c +++ b/gcc-python-callbacks.c @@ -375,7 +375,12 @@ PyGcc_RegisterCallback(PyObject *self, PyObject *args, PyObject *kwargs) PyGcc_CallbackFor_GGC_END, closure); break; - + case PLUGIN_FINISH_PARSE_FUNCTION: + register_callback("python", // FIXME + (enum plugin_event)event, + PyGcc_CallbackFor_tree, + closure); + break; /* PLUGIN_FINISH_DECL was added in gcc 4.7 onwards: */ #ifdef GCC_PYTHON_PLUGIN_CONFIG_has_PLUGIN_FINISH_DECL case PLUGIN_FINISH_DECL: From a8373e291991ef9f0acabf5cd426f1e780853fde Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 25 Nov 2021 22:13:45 +0800 Subject: [PATCH 02/19] Add get_location We have set_location. Why not get_location? This tells us much information on variable and function and more locations. Signed-off-by: Yihao Wu --- gcc-python.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gcc-python.c b/gcc-python.c index 104d412a..3287d069 100644 --- a/gcc-python.c +++ b/gcc-python.c @@ -133,6 +133,12 @@ PyGcc_define_macro(PyObject *self, Py_RETURN_NONE; } +static PyObject * +PyGcc_get_location(PyObject *self, PyObject *args) +{ + return PyGccLocation_New(gcc_private_make_location(input_location)); +} + static PyObject * PyGcc_set_location(PyObject *self, PyObject *args) { @@ -438,6 +444,10 @@ static PyMethodDef GccMethods[] = { (METH_VARARGS | METH_KEYWORDS), ("Report an information message\n" "FIXME\n")}, + {"get_location", + (PyCFunction)PyGcc_get_location, + METH_VARARGS, + ("Get the default location for error reports\n")}, {"set_location", (PyCFunction)PyGcc_set_location, METH_VARARGS, From e9b93844bfecbc1cc60582e31f0bd6321f0b27f1 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 25 Nov 2021 22:17:49 +0800 Subject: [PATCH 03/19] Add main_input_filename We definitely want to know the filename we are compiling. Signed-off-by: Yihao Wu --- gcc-python.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gcc-python.c b/gcc-python.c index 3287d069..c18d3a3a 100644 --- a/gcc-python.c +++ b/gcc-python.c @@ -371,6 +371,12 @@ PyGcc_dump(PyObject *self, PyObject *arg) Py_RETURN_NONE; } +static PyObject * +PyGcc_get_main_input_filename(PyObject *self, PyObject *args) +{ + return PyGccStringOrNone(main_input_filename); +} + static PyObject * PyGcc_get_dump_file_name(PyObject *self, PyObject *noargs) { @@ -494,6 +500,9 @@ static PyMethodDef GccMethods[] = { {"get_callgraph_nodes", PyGcc_get_callgraph_nodes, METH_VARARGS, "Get a list of all gcc.CallgraphNode instances"}, + {"get_main_input_filename", PyGcc_get_main_input_filename, METH_NOARGS, + "Get main_input_filename"}, + /* Dump files */ {"dump", PyGcc_dump, METH_O, "Dump str() of the argument to the current dump file (or silently discard it when no dump file is open)"}, From 5caf3852e16e362001c20c0085e8e28f5c53e826 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 29 Oct 2020 17:18:14 +0800 Subject: [PATCH 04/19] Add stub for types There are times we want to know where the structure is defined or sth. Signed-off-by: Yihao Wu --- gcc-python-tree.c | 5 +++++ gcc-python-wrappers.h | 3 +++ generate-tree-c.py | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/gcc-python-tree.c b/gcc-python-tree.c index e5f81012..fa160d3f 100644 --- a/gcc-python-tree.c +++ b/gcc-python-tree.c @@ -1103,6 +1103,11 @@ PyGcc_GetMethods(struct PyGccTree *self) #endif } +PyObject * PyGcc_GetStubDecl(struct PyGccTree *self) +{ + return PyGccTree_New(gcc_private_make_tree(TYPE_STUB_DECL(self->t.inner))); +} + /* GCC's debug_tree is implemented in: gcc/print-tree.c diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h index 1816b193..4a17e664 100644 --- a/gcc-python-wrappers.h +++ b/gcc-python-wrappers.h @@ -355,6 +355,9 @@ PyGcc_GetFields(struct PyGccTree *self); PyObject * PyGcc_GetMethods(struct PyGccTree *self); +PyObject * +PyGcc_GetStubDecl(struct PyGccTree *self); + /* gcc-python-gimple.c: */ extern gcc_gimple_asm PyGccGimple_as_gcc_gimple_asm(struct PyGccGimple *self); diff --git a/generate-tree-c.py b/generate-tree-c.py index faf3faf1..6eb3382a 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -484,11 +484,17 @@ def add_complex_getter(name, doc): add_simple_getter('methods', 'PyGcc_GetMethods(self)', "The methods of this type") + add_simple_getter('stub', + 'PyGcc_GetStubDecl(self)', + "The stub decl of this type") if tree_type.SYM == 'ENUMERAL_TYPE': add_simple_getter('values', 'PyGcc_TreeMakeListOfPairsFromTreeListChain(TYPE_VALUES(self->t.inner))', "The values of this type") + add_simple_getter('stub', + 'PyGcc_GetStubDecl(self)', + "The stub decl of this type") if tree_type.SYM == 'IDENTIFIER_NODE': add_simple_getter('name', From 8da8d81b0bd73d557eec834d5c9df9d186b7b6d8 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Fri, 6 Nov 2020 21:10:08 +0800 Subject: [PATCH 05/19] Add current_function_decl This is very frequently used when working in all different callbacks. Signed-off-by: Yihao Wu --- gcc-python.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gcc-python.c b/gcc-python.c index c18d3a3a..591142de 100644 --- a/gcc-python.c +++ b/gcc-python.c @@ -28,6 +28,7 @@ #include "gcc-c-api/gcc-declaration.h" #include "gcc-c-api/gcc-diagnostics.h" #include "gcc-c-api/gcc-option.h" +#include "gcc-c-api/gcc-function.h" int plugin_is_GPL_compatible; @@ -154,6 +155,12 @@ PyGcc_set_location(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +PyGcc_get_current_function(PyObject *self, PyObject *args) +{ + return PyGccFunction_New(gcc_get_current_function()); +} + static bool add_option_to_list(gcc_option opt, void *user_data) { PyObject *result = (PyObject*)user_data; @@ -458,6 +465,10 @@ static PyMethodDef GccMethods[] = { (PyCFunction)PyGcc_set_location, METH_VARARGS, ("Temporarily set the default location for error reports\n")}, + {"get_current_function", + (PyCFunction)PyGcc_get_current_function, + METH_VARARGS, + ("Get the current function declaration\n")}, /* Options: */ {"get_option_list", From 6f92456ef9c81713f4013a8ec3c3ad88d650098b Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 25 Nov 2021 22:18:41 +0800 Subject: [PATCH 06/19] Add context We want to know for example, is this variable defined in a translation unit or in a function scope, or which struct contains this field. Signed-off-by: Yihao Wu --- generate-tree-c.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/generate-tree-c.py b/generate-tree-c.py index 6eb3382a..f3a66a22 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -199,12 +199,18 @@ def add_simple_getter(name, c_expression, doc): add_simple_getter('is_artificial', 'PyBool_FromLong(gcc_decl_is_artificial(PyGccTree_as_gcc_decl(self)))', "Is this a compiler-generated entity?") + add_simple_getter('context', + 'PyGccTree_New(gcc_function_decl_as_gcc_tree(gcc_private_make_function_decl(DECL_CONTEXT (PyGccTree_as_gcc_decl(self).inner))))', + "context") add_simple_getter('is_builtin', 'PyBool_FromLong(gcc_decl_is_builtin(PyGccTree_as_gcc_decl(self)))', "Is this declaration built in by the compiler?") pytype.tp_repr = '(reprfunc)PyGccDeclaration_repr' if localname == 'Type': + add_simple_getter('context', + 'PyGccTree_New(gcc_function_decl_as_gcc_tree(gcc_private_make_function_decl(DECL_CONTEXT (PyGccTree_as_gcc_decl(self).inner))))', + "context") add_simple_getter('name', 'PyGccTree_New(gcc_type_get_name(PyGccTree_as_gcc_type(self)))', "The name of the type as a gcc.Tree, or None") From 16579baf96d7c8d56379793bb884cacc5b27764f Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Mon, 2 Nov 2020 17:53:08 +0800 Subject: [PATCH 07/19] Add main_variant for types This is useful when, for example we want to know what data structure has a function accessed, without caring qualifiers. Signed-off-by: Yihao Wu --- gcc-python-tree.c | 4 ++++ gcc-python-wrappers.h | 3 +++ generate-tree-c.py | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/gcc-python-tree.c b/gcc-python-tree.c index fa160d3f..ecfdf999 100644 --- a/gcc-python-tree.c +++ b/gcc-python-tree.c @@ -1108,6 +1108,10 @@ PyObject * PyGcc_GetStubDecl(struct PyGccTree *self) return PyGccTree_New(gcc_private_make_tree(TYPE_STUB_DECL(self->t.inner))); } +PyObject * PyGcc_MainVariant(struct PyGccTree *self) +{ + return PyGccTree_New(gcc_private_make_tree(TYPE_MAIN_VARIANT(self->t.inner))); +} /* GCC's debug_tree is implemented in: gcc/print-tree.c diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h index 4a17e664..4c16ed05 100644 --- a/gcc-python-wrappers.h +++ b/gcc-python-wrappers.h @@ -358,6 +358,9 @@ PyGcc_GetMethods(struct PyGccTree *self); PyObject * PyGcc_GetStubDecl(struct PyGccTree *self); +PyObject * +PyGcc_MainVariant(struct PyGccTree *self); + /* gcc-python-gimple.c: */ extern gcc_gimple_asm PyGccGimple_as_gcc_gimple_asm(struct PyGccGimple *self); diff --git a/generate-tree-c.py b/generate-tree-c.py index f3a66a22..9623c085 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -404,6 +404,9 @@ def add_complex_getter(name, doc): add_simple_getter('%s_equivalent' % qual, 'PyGccTree_New(gcc_private_make_tree(build_qualified_type(self->t.inner, TYPE_QUALS(self->t.inner) | TYPE_QUAL_%s)))' % qual.upper(), 'The gcc.Type for the %s version of this type' % qual) + add_simple_getter('main_variant', + 'PyGcc_MainVariant(self)', + "The main vairant of this type") add_simple_getter('unqualified_equivalent', 'PyGccTree_New(gcc_private_make_tree(build_qualified_type(self->t.inner, 0)))', 'The gcc.Type for the unqualified version of this type') @@ -493,6 +496,9 @@ def add_complex_getter(name, doc): add_simple_getter('stub', 'PyGcc_GetStubDecl(self)', "The stub decl of this type") + add_simple_getter('main_variant', + 'PyGcc_MainVariant(self)', + "The main vairant of this type") if tree_type.SYM == 'ENUMERAL_TYPE': add_simple_getter('values', From b149a22ff5e1e300a7d88186c306fe8048f25800 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Mon, 2 Nov 2020 17:53:27 +0800 Subject: [PATCH 08/19] Add print_declaration support besides dump_generic_node print_declaration gives much more graceful results than dump_generic_node when the node is decl. On the other hand, dump_generic_node always gives very ugly ones. Signed-off-by: Yihao Wu --- gcc-python-tree.c | 30 ++++++++++++++++++++++++++++++ gcc-python-wrappers.h | 3 +++ generate-tree-c.py | 2 ++ 3 files changed, 35 insertions(+) diff --git a/gcc-python-tree.c b/gcc-python-tree.c index ecfdf999..1fa76bf0 100644 --- a/gcc-python-tree.c +++ b/gcc-python-tree.c @@ -121,6 +121,30 @@ do_pretty_print(struct PyGccTree * self, int spc, dump_flags_t flags) if (!result) { goto error; } + + Py_XDECREF(ppobj); + return result; + + error: + Py_XDECREF(ppobj); + return NULL; +} + +static PyObject * +do_decl_print(struct PyGccTree * self, int spc, dump_flags_t flags) +{ + PyObject *ppobj = PyGccPrettyPrinter_New(); + PyObject *result = NULL; + if (!ppobj) { + return NULL; + } + + print_declaration (PyGccPrettyPrinter_as_pp(ppobj), + self->t.inner, spc, flags); + result = PyGccPrettyPrinter_as_string(ppobj); + if (!result) { + goto error; + } Py_XDECREF(ppobj); return result; @@ -284,6 +308,12 @@ PyGccTree_get_str_no_uid(struct PyGccTree *self, void *closure) return do_pretty_print(self, 0, TDF_NOUID); } +PyObject * +PyGccTree_get_str_decl(struct PyGccTree *self, void *closure) +{ + return do_decl_print(self, 0, TDF_NOUID); +} + PyObject * PyGccTree_get_symbol(PyObject *cls, PyObject *args) { diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h index 4c16ed05..63cb12fa 100644 --- a/gcc-python-wrappers.h +++ b/gcc-python-wrappers.h @@ -244,6 +244,9 @@ PyGccTree_richcompare(PyObject *o1, PyObject *o2, int op); PyObject * PyGccTree_get_str_no_uid(struct PyGccTree *self, void *closure); +PyObject * +PyGccTree_get_str_decl(struct PyGccTree *self, void *closure); + PyObject * PyGccTree_get_symbol(PyObject *cls, PyObject *args); diff --git a/generate-tree-c.py b/generate-tree-c.py index 9623c085..b408b3d0 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -76,6 +76,8 @@ def generate_tree(): 'Instance of gcc.Tree giving the type of the node'), PyGetSetDef('addr', 'PyGccTree_get_addr', None, 'The address of the underlying GCC object in memory'), + PyGetSetDef('str_decl', 'PyGccTree_get_str_decl', None, + 'A string representation of this declaration of the object.'), PyGetSetDef('str_no_uid', 'PyGccTree_get_str_no_uid', None, 'A string representation of this object, like str(), but without including any internal UID')], identifier_prefix='PyGccTree', From 3cc359ae7da22d5889f6c3c36f0c8e52b04ef9b1 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Sat, 7 Nov 2020 18:08:50 +0800 Subject: [PATCH 09/19] Make static attribute writtable This is needed when we want to use GCC's pretty print to do some code generation work. Signed-off-by: Yihao Wu --- generate-tree-c.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/generate-tree-c.py b/generate-tree-c.py index b408b3d0..f17b8c14 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -173,6 +173,17 @@ def add_simple_getter(name, c_expression, doc): doc) if localname == 'Declaration': + getter = cu.add_simple_getter('PyGccTree_get_static', + 'PyGccTree', + 'PyBool_FromLong(TREE_STATIC(self->t.inner))') + setter = cu.add_simple_int_setter('PyGccTree_set_static', + 'PyGccTree', + 'static', + 'TREE_STATIC(self->t.inner) = PyGccInt_AsLong(value)') + getsettable.add_gsdef('static', + getter, setter, + "(bool/bool)") + cu.add_defn(""" PyObject * PyGccDeclaration_get_name(struct PyGccTree *self, void *closure) @@ -520,9 +531,6 @@ def add_complex_getter(name, doc): add_simple_getter('initial', 'PyGccTree_New(gcc_constructor_as_gcc_tree(gcc_var_decl_get_initial(PyGccTree_as_gcc_var_decl(self))))', "The initial value for this variable as a gcc.Constructor, or None") - add_simple_getter('static', - 'PyBool_FromLong(gcc_var_decl_is_static(PyGccTree_as_gcc_var_decl(self)))', - "Boolean: is this variable to be allocated with static storage") if tree_type.SYM == 'CONSTRUCTOR': add_complex_getter('elements', From 1b57fccfa9c08379e18645180342564d96356f5f Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Sat, 7 Nov 2020 20:59:09 +0800 Subject: [PATCH 10/19] Make initial attribute writeable This is needed when we want to use GCC's pretty print to do some code generation work. For example, assigning NULL to initial, makes it have no initial value any more. Signed-off-by: Yihao Wu --- generate-tree-c.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/generate-tree-c.py b/generate-tree-c.py index f17b8c14..9a3235a6 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -184,6 +184,17 @@ def add_simple_getter(name, c_expression, doc): getter, setter, "(bool/bool)") + getter = cu.add_simple_getter('PyGccTree_get_initial', + 'PyGccTree', + 'PyGccTree_New(gcc_constructor_as_gcc_tree(gcc_var_decl_get_initial(PyGccTree_as_gcc_var_decl(self))))') + setter = cu.add_simple_int_setter('PyGccTree_set_initial', + 'PyGccTree', + 'initial', + 'DECL_INITIAL(self->t.inner) = NULL;') + getsettable.add_gsdef('initial', + getter, setter, + "(ptr/None)") + cu.add_defn(""" PyObject * PyGccDeclaration_get_name(struct PyGccTree *self, void *closure) @@ -528,9 +539,7 @@ def add_complex_getter(name, doc): tp_repr = '(reprfunc)PyGccIdentifierNode_repr' if tree_type.SYM == 'VAR_DECL': - add_simple_getter('initial', - 'PyGccTree_New(gcc_constructor_as_gcc_tree(gcc_var_decl_get_initial(PyGccTree_as_gcc_var_decl(self))))', - "The initial value for this variable as a gcc.Constructor, or None") + pass if tree_type.SYM == 'CONSTRUCTOR': add_complex_getter('elements', From 2a8a4731f4f44fa64a20e63152a294dec11f72f4 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Mon, 11 Jan 2021 21:41:24 +0800 Subject: [PATCH 11/19] Make public attribute writable This is needed when we want to use GCC's pretty print to do some code generation work. Signed-off-by: Yihao Wu --- generate-tree-c.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/generate-tree-c.py b/generate-tree-c.py index 9a3235a6..bce582d3 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -194,6 +194,17 @@ def add_simple_getter(name, c_expression, doc): getsettable.add_gsdef('initial', getter, setter, "(ptr/None)") + getter = cu.add_simple_getter('PyGccTree_get_public', + 'PyGccTree', + 'PyBool_FromLong(TREE_PUBLIC(self->t.inner))') + setter = cu.add_simple_int_setter('PyGccTree_set_public', + 'PyGccTree', + 'public', + 'TREE_PUBLIC(self->t.inner) = PyGccInt_AsLong(value)') + getsettable.add_gsdef('public', + getter, setter, + "(bool/bool)") + cu.add_defn(""" PyObject * From 324a3375d2bee33bbddc1707408ce179e1c88837 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Sat, 7 Nov 2020 21:01:19 +0800 Subject: [PATCH 12/19] Add external attribute This is provided by GCC, better have it. Signed-off-by: Yihao Wu --- generate-tree-c.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/generate-tree-c.py b/generate-tree-c.py index bce582d3..48dd1a33 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -222,6 +222,16 @@ def add_simple_getter(name, c_expression, doc): return PyGccLocation_New(gcc_decl_get_location(PyGccTree_as_gcc_decl(self))); } """) + getter = cu.add_simple_getter('PyGccTree_get_external', + 'PyGccTree', + 'PyBool_FromLong(DECL_EXTERNAL(self->t.inner))') + setter = cu.add_simple_int_setter('PyGccTree_set_', + 'PyGccTree', + 'external', + 'DECL_EXTERNAL(self->t.inner) = PyGccInt_AsLong(value)') + getsettable.add_gsdef('external', + getter, setter, + "(bool/bool)") getsettable.add_gsdef('name', 'PyGccDeclaration_get_name', From d6168389b77581807bf19f2ea5350dd2b475357a Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Sat, 7 Nov 2020 22:36:10 +0800 Subject: [PATCH 13/19] Make location hasher robust I've encountered strange bugs caused by this location hasher. So better not rely on pointer address, but the real content. As an example, the find-global-state test case was wrong because of this wrong hasher. Notice these two snippets: 1) int test2(int p) { static int q = 0; q += p; return p * q; } 2) int test2(int p) { static int q = 0; q = q + p; return p * q; } These two are not identical in compilers eyes. With "q += p", q is only acccessed once, the intermediate value q+p is nothing but a temporary value asserted by the compiler, eg. "q.2". While with "q = q + p", q is accessed twice, because q at both lhs and rhs are the original q, not temp variable. Signed-off-by: Yihao Wu --- gcc-python-location.c | 2 +- tests/examples/find-global-state/stderr.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/gcc-python-location.c b/gcc-python-location.c index 0857694f..696d3704 100644 --- a/gcc-python-location.c +++ b/gcc-python-location.c @@ -190,7 +190,7 @@ PyGccLocation_richcompare(PyObject *o1, PyObject *o2, int op) long PyGccLocation_hash(struct PyGccLocation * self) { - return self->loc.inner; + return (unsigned long)(LOCATION_FILE(self->loc.inner)) ^ LOCATION_LINE(self->loc.inner); } #if (GCC_VERSION >= 5000) diff --git a/tests/examples/find-global-state/stderr.txt b/tests/examples/find-global-state/stderr.txt index 1385ef1e..8a24a156 100644 --- a/tests/examples/find-global-state/stderr.txt +++ b/tests/examples/find-global-state/stderr.txt @@ -1,5 +1,4 @@ tests/examples/find-global-state/input.c:41:nn: note: use of global state "int q" here -tests/examples/find-global-state/input.c:41:nn: note: use of global state "int q" here tests/examples/find-global-state/input.c:42:nn: note: use of global state "int q" here tests/examples/find-global-state/input.c:53:nn: note: use of global state "int foo" here tests/examples/find-global-state/input.c:58:nn: note: use of global state "struct From 08b6ae47fbf25ba6eb49576bdc19960b69807ddb Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Sun, 8 Nov 2020 01:44:45 +0800 Subject: [PATCH 14/19] Add PLUGIN_INCLUDE_FILE callback Better support all callbacks which GCC supports. Signed-off-by: Yihao Wu --- gcc-python-callbacks.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gcc-python-callbacks.c b/gcc-python-callbacks.c index 0d83d28d..1aeb8655 100644 --- a/gcc-python-callbacks.c +++ b/gcc-python-callbacks.c @@ -197,6 +197,18 @@ PyGcc_CallbackFor_tree(void *gcc_data, void *user_data) user_data); } +static void +PyGcc_CallbackFor_string(void *gcc_data, void *user_data) +{ + PyGILState_STATE gstate; + const char *str = (const char *)gcc_data; + + gstate = PyGILState_Ensure(); + + PyGcc_FinishInvokingCallback(gstate, + 1, PyGccString_FromString(str), + user_data); +} static void PyGcc_CallbackFor_PLUGIN_ATTRIBUTES(void *gcc_data, void *user_data) @@ -381,6 +393,12 @@ PyGcc_RegisterCallback(PyObject *self, PyObject *args, PyObject *kwargs) PyGcc_CallbackFor_tree, closure); break; + case PLUGIN_INCLUDE_FILE: + register_callback("python", // FIXME + (enum plugin_event)event, + PyGcc_CallbackFor_string, + closure); + break; /* PLUGIN_FINISH_DECL was added in gcc 4.7 onwards: */ #ifdef GCC_PYTHON_PLUGIN_CONFIG_has_PLUGIN_FINISH_DECL case PLUGIN_FINISH_DECL: From fdcd69cdf88d7b05cc604ebf7a39362e2b4413c7 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Mon, 16 Nov 2020 00:08:45 +0800 Subject: [PATCH 15/19] Add decl.attributes Of course we want this not only for types but declaraions too. People give various attributes to functions and variables. Signed-off-by: Yihao Wu --- gcc-python-tree.c | 50 +++++++++++++++++++++++++++++++++++++++++++ gcc-python-wrappers.h | 3 +++ generate-tree-c.py | 4 ++++ 3 files changed, 57 insertions(+) diff --git a/gcc-python-tree.c b/gcc-python-tree.c index 1fa76bf0..47d5a039 100644 --- a/gcc-python-tree.c +++ b/gcc-python-tree.c @@ -456,6 +456,56 @@ PyGccIdentifierNode_repr(struct PyGccTree * self) } } +PyObject * +PyGccDeclaration_get_attributes(struct PyGccTree *self, void *closure) +{ + /* gcc/tree.h defines TYPE_ATTRIBUTES(NODE) as: + "A TREE_LIST of IDENTIFIER nodes of the attributes that apply + to this type" + + Looking at: + typedef int (example3)(const char *, const char *, const char *) + __attribute__((nonnull(1))) + __attribute__((nonnull(3))); + (which is erroneous), we get this for TYPE_ATTRIBUTES: + gcc.TreeList(purpose=gcc.IdentifierNode(name='nonnull'), + value=gcc.TreeList(purpose=None, + value=gcc.IntegerCst(3), + chain=None), + chain=gcc.TreeList(purpose=gcc.IdentifierNode(name='nonnull'), + value=gcc.TreeList(purpose=None, + value=gcc.IntegerCst(1), + chain=None), + chain=None) + ) + */ + tree attr; + PyObject *result = PyDict_New(); + if (!result) { + return NULL; + } + for (attr = DECL_ATTRIBUTES(self->t.inner); attr; attr = TREE_CHAIN(attr)) { + const char *attrname = IDENTIFIER_POINTER(TREE_PURPOSE(attr)); + PyObject *values; + values = PyGcc_TreeMakeListFromTreeList(TREE_VALUE(attr)); + if (!values) { + goto error; + } + + if (-1 == PyDict_SetItemString(result, attrname, values)) { + Py_DECREF(values); + goto error; + } + Py_DECREF(values); + } + + return result; + + error: + Py_DECREF(result); + return NULL; +} + PyObject * PyGccType_get_attributes(struct PyGccTree *self, void *closure) { diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h index 63cb12fa..7181535b 100644 --- a/gcc-python-wrappers.h +++ b/gcc-python-wrappers.h @@ -271,6 +271,9 @@ PyGccDeclaration_get_name(struct PyGccTree *self, void *closure); PyObject * PyGccDeclaration_repr(struct PyGccTree * self); +PyObject * +PyGccDeclaration_get_attributes(struct PyGccTree *self, void *closure); + PyObject * PyGccFunctionDecl_get_fullname(struct PyGccTree *self, void *closure); diff --git a/generate-tree-c.py b/generate-tree-c.py index 48dd1a33..a1bb9323 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -241,6 +241,10 @@ def add_simple_getter(name, c_expression, doc): 'PyGccDeclaration_get_location', None, 'The gcc.Location for this declaration') + getsettable.add_gsdef('attributes', + 'PyGccDeclaration_get_attributes', + None, + 'The user-defined attributes on this decl') add_simple_getter('is_artificial', 'PyBool_FromLong(gcc_decl_is_artificial(PyGccTree_as_gcc_decl(self)))', "Is this a compiler-generated entity?") From 3d2e5d3f84147fe969810ab8fe600b187eb651dd Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Mon, 16 Nov 2020 00:09:25 +0800 Subject: [PATCH 16/19] Add referring and referer to variables Cgraph gives us callers and callees, and Varpool gives us referring and referred. It's good to have themtoo. Signed-off-by: Yihao Wu --- gcc-python-variable.c | 50 ++++++++++++++++++++++++++++++++++++++++++ generate-variable-c.py | 13 +++++++++++ 2 files changed, 63 insertions(+) diff --git a/gcc-python-variable.c b/gcc-python-variable.c index bab1ec2f..198b2687 100644 --- a/gcc-python-variable.c +++ b/gcc-python-variable.c @@ -51,6 +51,56 @@ PyGcc_WrtpMarkForPyGccVariable(PyGccVariable *wrapper) gcc_variable_mark_in_use(wrapper->var); } +IMPL_APPENDER(add_var_to_list, + gcc_variable, + PyGccVariable_New) + + +GCC_IMPLEMENT_PUBLIC_API (bool) gcc_variable_get_referring (gcc_variable var, + bool (*cb) (gcc_variable var, void *user_data), + void *user_data) +{ + ipa_ref *ref = NULL; + int i; + for (i = 0; var.inner->iterate_referring(i, ref); i++) { + if (cb(gcc_private_make_variable((varpool_node*)ref->referring), user_data)) + return true; + } + + return false; +} + +GCC_IMPLEMENT_PUBLIC_API (PyObject *) +PyGccVariable_get_referring(struct PyGccVariable * self) +{ + IMPL_LIST_MAKER(gcc_variable_get_referring, + self->var, + add_var_to_list) +} + + +GCC_IMPLEMENT_PUBLIC_API (bool) gcc_variable_get_reference (gcc_variable var, + bool (*cb) (gcc_variable var, void *user_data), + void *user_data) +{ + ipa_ref *ref = NULL; + int i; + for (i = 0; var.inner->iterate_reference(i, ref); i++) { + if (cb(gcc_private_make_variable((varpool_node*)ref->referred), user_data)) + return true; + } + + return false; +} + +GCC_IMPLEMENT_PUBLIC_API (PyObject *) +PyGccVariable_get_reference(struct PyGccVariable * self) +{ + IMPL_LIST_MAKER(gcc_variable_get_reference, + self->var, + add_var_to_list) +} + /* PEP-7 Local variables: diff --git a/generate-variable-c.py b/generate-variable-c.py index aed8955b..498b2cb7 100644 --- a/generate-variable-c.py +++ b/generate-variable-c.py @@ -44,6 +44,19 @@ def add_simple_getter(name, c_expression, doc): 'PyGccTree_New(gcc_variable_get_decl(self->var))', 'The declaration of this variable, as a gcc.Tree') + cu.add_decl('GCC_IMPLEMENT_PUBLIC_API (PyObject *) PyGccVariable_get_referring(struct PyGccVariable * self);') + cu.add_decl('GCC_IMPLEMENT_PUBLIC_API (PyObject *) PyGccVariable_get_reference(struct PyGccVariable * self);') + + getsettable.add_gsdef('referring', + 'PyGccVariable_get_referring', + None, + 'Referencing this var') + + getsettable.add_gsdef('reference', + 'PyGccVariable_get_reference', + None, + 'Referenced by this var') + cu.add_defn(getsettable.c_defn()) pytype = PyGccWrapperTypeObject(identifier = 'PyGccVariable_TypeObj', From afb65cbb6580c0a65a293dae2e3af6892f351a39 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 25 Nov 2021 21:09:42 +0800 Subject: [PATCH 17/19] Add VarDecl.node points to varpool nodes Just like FunctionDecl.node points to function nodes, they are similar. Signed-off-by: Yihao Wu --- generate-tree-c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/generate-tree-c.py b/generate-tree-c.py index a1bb9323..6c8c031a 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -564,7 +564,9 @@ def add_complex_getter(name, doc): tp_repr = '(reprfunc)PyGccIdentifierNode_repr' if tree_type.SYM == 'VAR_DECL': - pass + add_simple_getter('node', + 'PyGccVariable_New(gcc_private_make_variable(varpool_node::get (self->t.inner)))', + 'Node which contains this var decl') if tree_type.SYM == 'CONSTRUCTOR': add_complex_getter('elements', From 99ab6a0d7facda19d96ad53fd80bb14fbf499379 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Sat, 2 Jan 2021 13:10:10 +0800 Subject: [PATCH 18/19] Add general purpose walk_tree GCC supports not only walking of gimple, but general purpose decl. It's good to have them. For example we want to walk down the of initializing tree a global data structure variable. Signed-off-by: Yihao Wu --- gcc-python-tree.c | 79 +++++++++++++++++++++++++++++++++++++++++++ gcc-python-wrappers.h | 3 ++ generate-tree-c.py | 4 +++ 3 files changed, 86 insertions(+) diff --git a/gcc-python-tree.c b/gcc-python-tree.c index 47d5a039..c36d569b 100644 --- a/gcc-python-tree.c +++ b/gcc-python-tree.c @@ -21,6 +21,7 @@ #include "gcc-python.h" #include "gcc-python-wrappers.h" #include "gcc-python-compat.h" +#include "gcc-python-closure.h" #include "cp/cp-tree.h" #include "gimple.h" @@ -328,6 +329,84 @@ PyGccTree_get_symbol(PyObject *cls, PyObject *args) return PyGccString_FromString(op_symbol_code(code)); } +static tree +tree_walk_callback(tree *tree_ptr, int *walk_subtree, void *data) +{ + struct callback_closure *closure = (struct callback_closure*)data; + PyObject *tree_obj = NULL; + PyObject *args = NULL; + PyObject *result = NULL; + + assert(closure); + assert(*tree_ptr); + tree_obj = PyGccTree_New(gcc_private_make_tree(*tree_ptr)); + if (!tree_obj) { + goto error; + } + + args = PyGcc_Closure_MakeArgs(closure, 0, tree_obj); + if (!args) { + goto error; + } + + /* Invoke the python callback: */ + result = PyObject_Call(closure->callback, args, closure->kwargs); + if (!result) { + goto error; + } + + Py_DECREF(tree_obj); + Py_DECREF(args); + + if (PyObject_IsTrue(result)) { + Py_DECREF(result); + return *tree_ptr; + } else { + Py_DECREF(result); + return NULL; + } + +error: + /* On and exception, terminate the traversal: */ + *walk_subtree = 0; + Py_XDECREF(tree_obj); + Py_XDECREF(args); + Py_XDECREF(result); + return NULL; +} + +PyObject * +PyGccTree_walk_tree(struct PyGccTree * self, PyObject *args, PyObject *kwargs) +{ + PyObject *callback; + PyObject *extraargs = NULL; + struct callback_closure *closure; + tree result; + + callback = PyTuple_GetItem(args, 0); + extraargs = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); + + closure = PyGcc_closure_new_generic(callback, extraargs, kwargs); + + if (!closure) { + Py_DECREF(callback); + Py_DECREF(extraargs); + return NULL; + } + + result = walk_tree (&self->t.inner, + tree_walk_callback, + closure, NULL); + + PyGcc_closure_free(closure); + + if (PyErr_Occurred()) { + return NULL; + } + + return PyGccTree_New(gcc_private_make_tree(result)); +} + PyObject * PyGccDeclaration_repr(struct PyGccTree * self) { diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h index 7181535b..8bc2e22f 100644 --- a/gcc-python-wrappers.h +++ b/gcc-python-wrappers.h @@ -268,6 +268,9 @@ PyGccComponentRef_repr(PyObject *self); PyObject * PyGccDeclaration_get_name(struct PyGccTree *self, void *closure); +PyObject * +PyGccTree_walk_tree(struct PyGccTree * self, PyObject *args, PyObject *kwargs); + PyObject * PyGccDeclaration_repr(struct PyGccTree * self); diff --git a/generate-tree-c.py b/generate-tree-c.py index 6c8c031a..37607d2b 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -96,6 +96,10 @@ def generate_tree(): tp_str = '(reprfunc)PyGccTree_str', tp_richcompare = 'PyGccTree_richcompare') methods = PyMethodTable('PyGccTree_methods', []) + methods.add_method('walk_tree', + '(PyCFunction)PyGccTree_walk_tree', + 'METH_VARARGS | METH_KEYWORDS', + 'Walk the tree of the declaration') methods.add_method('debug', 'PyGccTree_debug', 'METH_VARARGS', From 33c3873d17032e21b726ed2395463e133e2d2956 Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Wed, 7 Apr 2021 02:09:10 +0800 Subject: [PATCH 19/19] Add inline attr to function decl To tell a function is inline or not. Note that this only indicates if the functions is attributed with "inline", it can't tell whether gcc really decides to inline it. Signed-off-by: Yihao Wu --- generate-tree-c.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/generate-tree-c.py b/generate-tree-c.py index 37607d2b..2f87c30c 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -652,6 +652,9 @@ def add_complex_getter(name, doc): add_simple_getter('result', 'PyGccTree_New(gcc_private_make_tree(DECL_RESULT_FLD(self->t.inner)))', 'The gcc.ResultDecl for the return value') + add_simple_getter('inline', + 'PyBool_FromLong(DECL_DECLARED_INLINE_P(self->t.inner))', + 'If function is declared as inline') getsettable.add_gsdef('callgraph_node', 'PyGccFunctionDecl_get_callgraph_node', None,