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 = [x.replace(" ", "") for x in template_params] 53 54 if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001' or template_params[1] == '-1': 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' or template_params[2] == '-1': 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 return self.__next__() # Python 2.x compatibility 94 95 def __next__(self): 96 97 row = self.currentRow 98 col = self.currentCol 99 if self.rowMajor == 0: 100 if self.currentCol >= self.cols: 101 raise StopIteration 102 103 self.currentRow = self.currentRow + 1 104 if self.currentRow >= self.rows: 105 self.currentRow = 0 106 self.currentCol = self.currentCol + 1 107 else: 108 if self.currentRow >= self.rows: 109 raise StopIteration 110 111 self.currentCol = self.currentCol + 1 112 if self.currentCol >= self.cols: 113 self.currentCol = 0 114 self.currentRow = self.currentRow + 1 115 116 117 item = self.dataPtr.dereference() 118 self.dataPtr = self.dataPtr + 1 119 if (self.cols == 1): #if it's a column vector 120 return ('[%d]' % (row,), item) 121 elif (self.rows == 1): #if it's a row vector 122 return ('[%d]' % (col,), item) 123 return ('[%d,%d]' % (row, col), item) 124 125 def children(self): 126 127 return self._iterator(self.rows, self.cols, self.data, self.rowMajor) 128 129 def to_string(self): 130 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) 131 132class EigenQuaternionPrinter: 133 "Print an Eigen Quaternion" 134 135 def __init__(self, val): 136 "Extract all the necessary information" 137 # The gdb extension does not support value template arguments - need to extract them by hand 138 type = val.type 139 if type.code == gdb.TYPE_CODE_REF: 140 type = type.target() 141 self.type = type.unqualified().strip_typedefs() 142 self.innerType = self.type.template_argument(0) 143 self.val = val 144 145 # Quaternions have a struct as their storage, so we need to walk through this 146 self.data = self.val['m_coeffs']['m_storage']['m_data']['array'] 147 self.data = self.data.cast(self.innerType.pointer()) 148 149 class _iterator: 150 def __init__ (self, dataPtr): 151 self.dataPtr = dataPtr 152 self.currentElement = 0 153 self.elementNames = ['x', 'y', 'z', 'w'] 154 155 def __iter__ (self): 156 return self 157 158 def next(self): 159 return self.__next__() # Python 2.x compatibility 160 161 def __next__(self): 162 element = self.currentElement 163 164 if self.currentElement >= 4: #there are 4 elements in a quanternion 165 raise StopIteration 166 167 self.currentElement = self.currentElement + 1 168 169 item = self.dataPtr.dereference() 170 self.dataPtr = self.dataPtr + 1 171 return ('[%s]' % (self.elementNames[element],), item) 172 173 def children(self): 174 175 return self._iterator(self.data) 176 177 def to_string(self): 178 return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data) 179 180def build_eigen_dictionary (): 181 pretty_printers_dict[re.compile('^Eigen::Quaternion<.*>$')] = lambda val: EigenQuaternionPrinter(val) 182 pretty_printers_dict[re.compile('^Eigen::Matrix<.*>$')] = lambda val: EigenMatrixPrinter("Matrix", val) 183 pretty_printers_dict[re.compile('^Eigen::Array<.*>$')] = lambda val: EigenMatrixPrinter("Array", val) 184 185def register_eigen_printers(obj): 186 "Register eigen pretty-printers with objfile Obj" 187 188 if obj == None: 189 obj = gdb 190 obj.pretty_printers.append(lookup_function) 191 192def lookup_function(val): 193 "Look-up and return a pretty-printer that can print va." 194 195 type = val.type 196 197 if type.code == gdb.TYPE_CODE_REF: 198 type = type.target() 199 200 type = type.unqualified().strip_typedefs() 201 202 typename = type.tag 203 if typename == None: 204 return None 205 206 for function in pretty_printers_dict: 207 if function.search(typename): 208 return pretty_printers_dict[function](val) 209 210 return None 211 212pretty_printers_dict = {} 213 214build_eigen_dictionary () 215