1# -*- coding: utf-8 -*- 2# This file is part of Eigen, a lightweight C++ template library 3# for linear algebra. 4# 5# Copyright (C) 2009 Benjamin Schindler <bschindler@inf.ethz.ch> 6# 7# This Source Code Form is subject to the terms of the Mozilla Public 8# License, v. 2.0. If a copy of the MPL was not distributed with this 9# file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 11# Pretty printers for Eigen::Matrix 12# This is still pretty basic as the python extension to gdb is still pretty basic. 13# It cannot handle complex eigen types and it doesn't support any of the other eigen types 14# Such as quaternion or some other type. 15# This code supports fixed size as well as dynamic size matrices 16 17# To use it: 18# 19# * Create a directory and put the file as well as an empty __init__.py in 20# that directory. 21# * Create a ~/.gdbinit file, that contains the following: 22# python 23# import sys 24# sys.path.insert(0, '/path/to/eigen/printer/directory') 25# from printers import register_eigen_printers 26# register_eigen_printers (None) 27# end 28 29import gdb 30import re 31import itertools 32 33 34class EigenMatrixPrinter: 35 "Print Eigen Matrix or Array of some kind" 36 37 def __init__(self, variety, val): 38 "Extract all the necessary information" 39 40 # Save the variety (presumably "Matrix" or "Array") for later usage 41 self.variety = variety 42 43 # The gdb extension does not support value template arguments - need to extract them by hand 44 type = val.type 45 if type.code == gdb.TYPE_CODE_REF: 46 type = type.target() 47 self.type = type.unqualified().strip_typedefs() 48 tag = self.type.tag 49 regex = re.compile('\<.*\>') 50 m = regex.findall(tag)[0][1:-1] 51 template_params = m.split(',') 52 template_params = map(lambda x:x.replace(" ", ""), template_params) 53 54 if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001': 55 self.rows = val['m_storage']['m_rows'] 56 else: 57 self.rows = int(template_params[1]) 58 59 if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001': 60 self.cols = val['m_storage']['m_cols'] 61 else: 62 self.cols = int(template_params[2]) 63 64 self.options = 0 # default value 65 if len(template_params) > 3: 66 self.options = template_params[3]; 67 68 self.rowMajor = (int(self.options) & 0x1) 69 70 self.innerType = self.type.template_argument(0) 71 72 self.val = val 73 74 # Fixed size matrices have a struct as their storage, so we need to walk through this 75 self.data = self.val['m_storage']['m_data'] 76 if self.data.type.code == gdb.TYPE_CODE_STRUCT: 77 self.data = self.data['array'] 78 self.data = self.data.cast(self.innerType.pointer()) 79 80 class _iterator: 81 def __init__ (self, rows, cols, dataPtr, rowMajor): 82 self.rows = rows 83 self.cols = cols 84 self.dataPtr = dataPtr 85 self.currentRow = 0 86 self.currentCol = 0 87 self.rowMajor = rowMajor 88 89 def __iter__ (self): 90 return self 91 92 def next(self): 93 94 row = self.currentRow 95 col = self.currentCol 96 if self.rowMajor == 0: 97 if self.currentCol >= self.cols: 98 raise StopIteration 99 100 self.currentRow = self.currentRow + 1 101 if self.currentRow >= self.rows: 102 self.currentRow = 0 103 self.currentCol = self.currentCol + 1 104 else: 105 if self.currentRow >= self.rows: 106 raise StopIteration 107 108 self.currentCol = self.currentCol + 1 109 if self.currentCol >= self.cols: 110 self.currentCol = 0 111 self.currentRow = self.currentRow + 1 112 113 114 item = self.dataPtr.dereference() 115 self.dataPtr = self.dataPtr + 1 116 if (self.cols == 1): #if it's a column vector 117 return ('[%d]' % (row,), item) 118 elif (self.rows == 1): #if it's a row vector 119 return ('[%d]' % (col,), item) 120 return ('[%d,%d]' % (row, col), item) 121 122 def children(self): 123 124 return self._iterator(self.rows, self.cols, self.data, self.rowMajor) 125 126 def to_string(self): 127 return "Eigen::%s<%s,%d,%d,%s> (data ptr: %s)" % (self.variety, self.innerType, self.rows, self.cols, "RowMajor" if self.rowMajor else "ColMajor", self.data) 128 129class EigenQuaternionPrinter: 130 "Print an Eigen Quaternion" 131 132 def __init__(self, val): 133 "Extract all the necessary information" 134 # The gdb extension does not support value template arguments - need to extract them by hand 135 type = val.type 136 if type.code == gdb.TYPE_CODE_REF: 137 type = type.target() 138 self.type = type.unqualified().strip_typedefs() 139 self.innerType = self.type.template_argument(0) 140 self.val = val 141 142 # Quaternions have a struct as their storage, so we need to walk through this 143 self.data = self.val['m_coeffs']['m_storage']['m_data']['array'] 144 self.data = self.data.cast(self.innerType.pointer()) 145 146 class _iterator: 147 def __init__ (self, dataPtr): 148 self.dataPtr = dataPtr 149 self.currentElement = 0 150 self.elementNames = ['x', 'y', 'z', 'w'] 151 152 def __iter__ (self): 153 return self 154 155 def next(self): 156 element = self.currentElement 157 158 if self.currentElement >= 4: #there are 4 elements in a quanternion 159 raise StopIteration 160 161 self.currentElement = self.currentElement + 1 162 163 item = self.dataPtr.dereference() 164 self.dataPtr = self.dataPtr + 1 165 return ('[%s]' % (self.elementNames[element],), item) 166 167 def children(self): 168 169 return self._iterator(self.data) 170 171 def to_string(self): 172 return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data) 173 174def build_eigen_dictionary (): 175 pretty_printers_dict[re.compile('^Eigen::Quaternion<.*>$')] = lambda val: EigenQuaternionPrinter(val) 176 pretty_printers_dict[re.compile('^Eigen::Matrix<.*>$')] = lambda val: EigenMatrixPrinter("Matrix", val) 177 pretty_printers_dict[re.compile('^Eigen::Array<.*>$')] = lambda val: EigenMatrixPrinter("Array", val) 178 179def register_eigen_printers(obj): 180 "Register eigen pretty-printers with objfile Obj" 181 182 if obj == None: 183 obj = gdb 184 obj.pretty_printers.append(lookup_function) 185 186def lookup_function(val): 187 "Look-up and return a pretty-printer that can print va." 188 189 type = val.type 190 191 if type.code == gdb.TYPE_CODE_REF: 192 type = type.target() 193 194 type = type.unqualified().strip_typedefs() 195 196 typename = type.tag 197 if typename == None: 198 return None 199 200 for function in pretty_printers_dict: 201 if function.search(typename): 202 return pretty_printers_dict[function](val) 203 204 return None 205 206pretty_printers_dict = {} 207 208build_eigen_dictionary () 209