如何为std::vector数据编写LLDB合成提供者以实现形状视图
我正在尝试为我项目中的类创建 LLDB 可视化工具,但 LLDB 的文档实在是太少了。我有一个数组类,它使用 std::vector 来存储底层数据,并且有一个扩展数组来描述形状。这个数组还可以在之后进行重塑。
默认情况下,std::vector 中的 "data_" 总是以线性向量的方式显示。我希望我的提供者能够创建一个视图层次结构。在这个例子中,第一层将是子行,每一行展开后会显示一列的值。就像查看一个静态的二维数组(比如 double[3][2])。你可以想象把这个扩展到 N 维。
我似乎无法弄清楚如何使用 lldb 的 Python 对象模型来在 std::vector 的线性缓冲区上强加层次结构。文档中没有相关信息,我已经在黑暗中摸索了大约一周。这里有一个我想为其创建可视化工具的简化数组类的例子。
任何帮助都非常感谢!
#include <vector>
#include <cassert>
template <typename T>
class myarray {
int extent_[2];
std::vector<T> data_;
public:
myarray(int r, int c, const T* data) {
extent_[0] = r;
extent_[1] = c;
data_.resize(r * c);
for(size_t i = 0; i < data_.size(); ++i) data_[i] = data[i];
}
void reshape(int r, int c) {
assert(r * c == data_.size());
extent_[0] = r;
extent_[1] = c;
}
};
int main(int argc, const char * argv[])
{
double initdata[6] = { 0, 1, 2, 3, 4, 5 };
myarray<double> mydata(3, 2, initdata);
mydata.reshape(1, 6);
return 0;
}
根据要求:我希望看到的第一个 [3][2] 例子的输出可能看起来像这样。第一层有 3 个子项,代表 "行",每一行都有一个关于行中首个元素的摘要字符串。这个想法是获取矩阵数据的二维视图。当一行被展开时,它将被视为一组列值的数组。
LLDB 可能的合成输出:
mydata
[0]
[0] = 0 <-- expanded contents
[1] = 1
[1] = {2, 3} <-- summary string of row contents. First N elements, then ...
[2] = {4, 5}
对于一个简单向量的合成提供者示例,get_child_at_index 的实现大致如下,我在 update() 方法中确定了计数、值大小和值类型:
def get_child_at_index(self,index):
logger = lldb.formatters.Logger.Logger()
logger >> "get_child_at_index: " + str(index)
if index < 0: return None;
if index >= self.count: return None;
try:
offset = index * self.value_size
return self.data.CreateChildAtOffset('['+str(index)+']',offset,self.value_type)
except:
return None
我觉得如果能弄清楚如何创建一个 SBType 来替代调用 CreateChildAtOffset 时的 value_type,我就能很容易地解决这个问题。这样我就可以构建任何我想要的结构。然而,经过多次尝试,我还是没能成功创建一个 SBType 对象。
有没有什么想法?有没有人知道如何从我构造的字符串中创建一个 SBType?
2 个回答
不确定这是否有用,但你可以找到已有的类型。
target = lldb.debugger.GetSelectedTarget()
type_list = target.FindTypes('base::Value')
如果你想用一个已有的类型来创建你的子类,这可能会对你有帮助。
我假设你已经看过这个链接:http://lldb.llvm.org/varformats.html
如果我理解得没错,你想要以更层次化的格式显示向量中的元素。
这个任务挺有意思的,不过你可能需要自己定义一些数据类型。目前在我们的公共API中,对这方面的支持似乎不多。作为一种变通办法,你当然可以运行一个表达式来生成你关心的结构体并保存它,但这样会比较慢。
在你的例子中,你具体想要得到什么样的视图呢?这种通过示例提供的信息实际上能帮助我们更好地理解细节。
补充说明:目前LLDB不允许你通过公共API创建新类型。你可以使用表达式解析器来获取你自己创建的SBType,像这个例子:
x = lldb.frame.EvaluateExpression("struct foo { int x; }; foo myfoo = {12}; myfoo")
data = lldb.SBData.CreateDataFromSInt32Array(lldb.eByteOrderLittle,8,[24])
x_type = x.GetType()
myOtherFoo = x.CreateValueFromData("myOtherFoo",data,x_type)
print myOtherFoo
OUTPUT: (foo) myOtherFoo = (x = 24)
这样做会比较慢,尤其是如果你不缓存你需要的foo类型(从你的例子来看,似乎是你模板参数T的T[2])的话。不过在LLDB有SB API可以通过clang创建类型之前(就像我们内部做的那样),这就是你唯一的办法。