nakst / gf

A GDB frontend for Linux.
MIT License
1.82k stars 61 forks source link

How can I write a hook to display variable number of items in the watch window? #50

Closed typon closed 2 years ago

typon commented 3 years ago

I am trying to write a display hook in python for a dynamic array container (for example std::vector).

The way I understand the hook function is that it is called twice: once to fetch the list of names of the fields, and another time to fetch their respective values.

I would like to display each item in my dynamic array as a separate element in this list of fields. I can't figure out how to change the gf code such that by the time it calls the hook with field = None, I already know the number of elements in my array.

Any help would be greatly appreciated.

nakst commented 3 years ago

This is currently not possible to do; the watch window API needs to be expanded first. Do you have any suggestions on what it should look like?

typon commented 3 years ago

It took me a while to wrap my head around what the current API is attempting to do...my suggestion would be to make it a lot more explicit.

What about something like this:

from typing import Callable
from abc import ABC, abstractmethod

class WatchHook(ABC):
    @abstractmethod
    def get_short_name(self, expression_value: gdb.Value):
        raise NotImplementedError("must override!")

    @abstractmethod
    def get_row_names(self, expression_value: gdb.Value):
        raise NotImplementedError("must override!")

    @abstractmethod
    def get_row_values(self, expression_value: gdb.Value):
        raise NotImplementedError("must override!")

# Sample array hook
class ArrayHook(WatchHook):
    def get_short_name(self, array_value: gdb.Value):
        # TODO: Extract size of array here
        return f"Array of {array_size} items"

    def get_row_names(self, array_value: gdb.Value):
        """
        This method is called `get_row_names` and not `get_field_names` because
        the user can use these for any purpose, for example indices of an array
        """
        # TODO: Extract size of array here
        self.array_size = array_size
        return [str(index) for index in range(0, array_size)]

    def get_row_values(self, value_stringify_callback: Callable, array_value: gdb.Value):
        result = []
        for index in range(self.array_size):
            value: gdb.Value = array_value[index]
            # This callback will recursively call other registered hooks or the default hook
            # to get the string to be displayed
            # In the case where array items are structs or other nested objects,
            # the callback will insert the short_name here and mark this row as expandable
            value_str: str = value_stringify_callback(value)
            result.append(value_str)
        return result

I don't understand the rest of the gf code enough to actually implement this myself, unfortunately :( I am willing to help though.

nakst commented 3 years ago

I've added this in 982176e and documented it in c3aa0fb. However I have not had a chance to test it much yet, so I'll keep this issue open for now in case there are bugs.