From 8904abb5a053fa40ef8b4d28e077283823b1932e Mon Sep 17 00:00:00 2001
From: pompolic <pompolic@special-circumstanc.es>
Date: Fri, 25 Jun 2021 23:38:35 +0200
Subject: [PATCH] Add HParserEnv base class for specific parser envs to inherit
 from

Also some boilerplate for GUI
---
 gdb-port/gui.py                             | 10 +++
 gdb-port/parser-type-instrumentation-gdb.py | 69 ++++++++++++++++++---
 2 files changed, 69 insertions(+), 10 deletions(-)

diff --git a/gdb-port/gui.py b/gdb-port/gui.py
index 32a6ea8..34089ef 100644
--- a/gdb-port/gui.py
+++ b/gdb-port/gui.py
@@ -1,6 +1,8 @@
 from tkinter import *
 from tkinter import ttk
 
+# TODO: investigate if tkinter installs a SIGCHLD handler, which can break GDB
+
 class PresentationLayer():
 	def __init__(self, parser):
 		self.top_parser = parser
@@ -11,6 +13,8 @@ class PresentationLayer():
 		self.top_parser_address = None
 		self.input_chunk = None
 
+		self.parser_env = None
+
 	def set_top_parser(self,parser):
 		self.top_parser = parser
 		self.top_parser_name.set(self.top_parser.name)
@@ -19,6 +23,9 @@ class PresentationLayer():
 	def set_input_chunk(self, input_chunk):
 		self.input_chunk.set(input_chunk)
 
+	def set_parser_env(self, parser_env):
+		self.parser_env.set(parser_env)
+
 	# let's avoid polluting the global namespace
 	def init_gui(self):
 		self.root = Tk()
@@ -38,6 +45,8 @@ class PresentationLayer():
 		#self.set_top_parser(top_level_parse.peek_parser())
 		#self.set_input_chunk(top_level_parse.get_input_chunk())
 
+		self.parser_env = StringVar()
+
 		#"Current parser" widgets
 		ttk.Label(self.frame, text="Current parser").grid(column=1, row=1)
 		ttk.Label(self.frame, textvariable=self.top_parser_name).grid(column=1, row=2)
@@ -50,6 +59,7 @@ class PresentationLayer():
 		# ParserHierarchy widget (sequence members, parsers this one contains, etc)
 		# Showing parser decisions is probably possible by capturing the return value of h_do_parse
 		ttk.Label(self.frame, text="Parser hierarchy").grid(column=2, row=3)
+		#ttk.Label(self.frame, textvariable=self.parser_env).grid(column=2, row=4)
 		ttk.Label(self.frame, text="[Placeholder, Placeholder, Placeholder]").grid(column=2, row=4)
 
 		ttk.Button(self.frame, text="Step", command=step).grid(column=1, row=4)
diff --git a/gdb-port/parser-type-instrumentation-gdb.py b/gdb-port/parser-type-instrumentation-gdb.py
index faf5bec..039b921 100644
--- a/gdb-port/parser-type-instrumentation-gdb.py
+++ b/gdb-port/parser-type-instrumentation-gdb.py
@@ -3,26 +3,73 @@
 # TopLevelParse should be amenable to adding parsers to the dict through here
 
 parser_name_defaults = {
-	'sequence_vt': '(Unnamed sequence)',
-	'ignore_vt': '(Unnamed ignore)',
 	'action_vt': '(Unnamed action)',
-	'and_vt': '(Unnamed and)'
-	#...
+	'and_vt': '(Unnamed and)',
+	'attr_bool_vt': '(Unnamed attr_bool)',
+	'bind_vt': '(Unnamed bind)',
+	'bits_vt': '(Unnamed bits)',
+	'butnot_vt': '(Unnamed butnot)',
+	'ch_vt': '(Unnamed ch)',
+	'charset_vt': '(Unnamed charset)',
+	'choice_vt': '(Unnamed choice)',
+	'difference_vt': '(Unnamed difference)',
+	'end_vt': '(Unnamed end)',
+	'endianness_vt': '(Unnamed endianness)',
+	'ignore_vt': '(Unnamed ignore)',
+	'ignoreseq_vt': '(Unnamed ignoreseq)',
+	'indirect_vt': '(Unnamed indirect)',
+	'int_range_vt': '(Unnamed int_range)',
+	'length_value_vt': '(Unnamed length_value)',
+	'many_vt': '(Unnamed many)',
+	'not_vt': '(Unnamed not)',
+	'nothing_vt': '(Unnamed nothing)',
+	'optional_vt': '(Unnamed optional)',
+	'permutation_vt': '(Unnamed permutation)',
+	'seek_vt': '(Unnamed seek)',
+	'skip_vt': '(Unnamed skip)',
+	'tell_vt': '(Unnamed tell)',
+	'sequence_vt': '(Unnamed sequence)',
+	'token_vt': '(Unnamed token)',
+	'unimplemented_vt': '(Unnamed unimplemented)',
+	'get_vt': '(Unnamed get)',
+	'put_vt': '(Unnamed put)',
+	'whitespace_vt': '(Unnamed whitespace)',
+	'xor_vt': '(Unnamed xor)'
 }
 
+class VTTypes:
+	def __init__(self):
+		self.vt_symbols = {int(gdb.lookup_symbol(key)[0].value().address) : gdb.lookup_symbol(key)[0] for key in parser_name_defaults.keys()}
+
+	# vt_p == vt_symbols[int(parser_vtable_p)].value().address
+	# name = parser_name_defaults[vt_types.lookup_by_address(parser_vtable_p)].name
+	# address is expected to be pointer to a parser that can be converted to int()
+	# e.g. parser.address of a Parser object, integer
+	def lookup_by_address(self, address):
+		try:
+			return self.vt_symbols[int(address)]
+		except KeyError:
+			return None
+
+vt_types = VTTypes()
+
 class HParserEnv:
 	def __init__(self, parser, top_level_parse):
 		print("HParserEnv constructed") # DEBUG
 
+	# parser is expected to be a Parser object
 	def name_from_vtable(self, parser):
 		parser_addr = parser.address
 		# TODO: do this without passing a string to gdb.parse_and_eval()
 		# perhaps using gdb.Value would be the best
-		vtable = gdb.parse_and_eval("((HParser*) " + parser_addr + ")->env->vtable")
+		vtable_p = gdb.parse_and_eval("((HParser*) " + str(parser_addr) + ")->vtable")
 		try:
-			name = parser_name_defaults[vtable.name()]
+			name = parser_name_defaults[vt_types.lookup_by_address(vtable_p).name]
+		# if lookup_by_address() returns None
+		except AttributeError:
+			name = "(Unknown parser type (vtable symbol not found in lookup)"
 		except KeyError:
-			name = "(Unknown parser type)"
+			name = "(Unknown parser type (vtable exists but has no default name associated)"
 
 		return name
 
@@ -31,8 +78,9 @@ class HParserEnv:
 # parser_array = [top_level_parse.add_or_get_parser(gdb.parse_and_eval("((HSequence*) parser->env)->p_array[" + str(index) +"]")) for index in range(0, num_parsers)]
 # compare pointers for equality
 
-class SequenceEnv:
+class SequenceEnv(HParserEnv):
 	def __init__(self, parser, top_level_parse):
+		super().__init__(parser, top_level_parse)
 		self.parser = parser
 		self.member_parsers = []
 
@@ -48,10 +96,11 @@ class SequenceEnv:
 		for index in range(0, num_parsers):
 			parser_p = gdb.parse_and_eval("((HSequence*) parser->env)->p_array[" + str(index) + "]")
 			parser_obj = top_level_parse.add_or_get_parser(parser_p)
-			#parser_obj.name_parser( self.name_from_vtable(parser_obj) )
+			parser_obj.name_parser( self.name_from_vtable(parser_obj) )
 			self.member_parsers.append(parser_obj)
 
-		# TODO
+	def __str__(self):
+		return str([str(parser) for parser in self.member_parsers])
 
 
 class IgnoreEnv:
-- 
GitLab