Общие помощники Python для gdb для перемещения по контейнеру C++ STL и вызова обратного вызова для элементовPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Общие помощники Python для gdb для перемещения по контейнеру C++ STL и вызова обратного вызова для элементов

Сообщение Anonymous »

Я хочу отладить ядро ​​приложения C++ и файлы gcore.

Это включает в себя создание отчетов для соответствующих данных в репозиториях двоичных данных.

Эти репозитории основаны на STL контейнеры (std::map, std::set, std::vector, ...)

Для этого я использую свои собственные «универсальные» помощники Python для автоматического перемещения по STL контейнеры, вызывать функцию обратного вызова для обработки данных и создавать отчеты о данных.

Вот пример:

Тестовая программа на C++:

Код: Выделить всё

#include 
#include 
#include 

struct DemoStruct
{
DemoStruct(int arg1, double arg2, std::string arg3, std::string arg4, char arg5, double arg6)
: wantSeeThis_1(arg1),
wantIgnoreThis_1(arg2),
wantSeeThis_2(arg3),
wantIgnoreThis_2(arg4),
wantIgnoreThis_3(arg5),
wantSeeThis_3(arg6)
{ };

~DemoStruct() = default;

int             wantSeeThis_1;
double          wantIgnoreThis_1;
std::string     wantSeeThis_2;
std::string     wantIgnoreThis_2;
char            wantIgnoreThis_3;
double          wantSeeThis_3;
};

std::map staticData = {
{       1, {1, 2.0, "hello", "world", 'a', 3.0 } },
{       2, {10, 3.2, "hi", "world", 'b', 0.3 } },
{       3, {50, 4.7, "salute", "world", 'c', 11.5 } },
};

int main(int, char**)
{
// set breakpoint here and inspect data
return 0;
}
скомпилируйте его с помощью:

Код: Выделить всё

> g++ -std=c++11 -o main -g3 -O0 main.cpp
используйте скрипты Python №2 для отладки:
Файл №1:

Код: Выделить всё

> cat stlhelper.py
# -*- coding: utf-8 -*-

import gdb
import sys
import re
import itertools
import six

#
# base class for PrintGenricXY
#
class PrintGenericCommon (gdb.Function):
"""print generic common"""

def __init__ (self):
super (PrintGenericCommon, self).__init__ ("PrintGenericList")

#
# data is hosted by the subject and we don't know their representation
# subject.ElemItemString() is responsible to format properly (might be complex data)
#
def PrintResult(self, subject):
# calculate the max sizes per element of all lines for alignment
sizes = subject.sizesDef
for x in subject.result:
for key, value in six.iteritems(sizes):
valStr = subject.ElemItemString(x[key])
if len(valStr) > value:
sizes[key] = len(valStr)

totalSize = 0
for key, value in six.iteritems(sizes):
sizes[key] += 2
totalSize += sizes[key]

print("-" * totalSize)
for i in range(len(subject.result)):
myStr = ''
for j in range(len(subject.elements)):
setSize=sizes[subject.elements[j]]
if (j == len(subject.elements) - 1):
setSize=0 # don't auto-align the last element, which often can have some large elements in the list
myStr  += "%-*s" % (setSize, subject.ElemItemString(subject.result[i][subject.elements[j]]))
print (myStr)
# print optional __VERBOSE data in a next line
if '__VERBOSE' in subject.result[i]:
str = subject.ElemItemString(subject.result[i]['__VERBOSE'])
lines = str.splitlines()
for line in lines:
print ('\t' + line)
if len(str) > 0 and str[-1] == '\n':
print('')
if i == 0:
print ("-" * totalSize)

#
# generic printer for std::map  and std::set
#
class PrintGenericMapOrSet (PrintGenericCommon):
"""print generic map/set"""

regex = re.compile('\$count')

maxNoResults = -1

def __init__ (self):
super (PrintGenericCommon, self).__init__ ("PrintGenericMapOrSet")

def setMaxNoResults(self, maxNoResults):
self.maxNoResults = maxNoResults

def invokeCore(self, headlines, map, valueType, isConst, isPointer, valueHandler):
collectedLines = []
map = map['_M_t']['_M_impl']
count = map['_M_node_count']
for x in headlines:
collectedLines.append(self.regex.sub(str(count), x))
node = map['_M_header']['_M_left']
valuetype = gdb.lookup_type (valueType)
if isConst:
valuetype = valuetype.const()
if isPointer:
valuetype = valuetype.pointer()
nodetype = gdb.lookup_type('std::_Rb_tree_node < %s >' % valuetype)
nodetype = nodetype.pointer()
i = 0
while i < count:
collectedLines.append(valueHandler(i, node.cast (nodetype).dereference()['_M_value_field'], node))
if node.dereference()['_M_right']:
node = node.dereference()['_M_right']
while node.dereference()['_M_left']:
node = node.dereference()['_M_left']
else:
parent = node.dereference()['_M_parent']
while node == parent.dereference()['_M_right']:
node = parent
parent = parent.dereference()['_M_parent']
if node.dereference()['_M_right'] != parent:
node = parent
i += 1
if self.maxNoResults > -1 and i >= self.maxNoResults:
break;
return "\n".join(collectedLines)

def invoke (self, headlines, mapLoc, valueType, valueHandler, typeWrapper):
map = gdb.parse_and_eval (mapLoc)
return self.invokeCore(headlines, map, valueType, valueHandler, typeWrapper);

#
# generic printer for std::map
#
class PrintGenericMap (gdb.Function):
"""print generic map"""

handler = PrintGenericMapOrSet()

def __init__ (self):
super (PrintGenericMap, self).__init__ ("PrintGenericMap")

def setMaxNoResults(self, maxNoResults):
return self.handler.setMaxNoResults(maxNoResults)

def invokeCore(self, headlines, map, valueType, valueHandler):
return self.handler.invokeCore(headlines, map, 'std::pair' + valueType, False, False, valueHandler)

def invoke (self, headlines, mapLoc, valueType, valueHandler, maxNoResults):
return self.handler.invoke(headlines, mapLoc, 'std::pair' + valueType, False, False, valueHandler);

def PrintResult(self, subject):
return self.handler.PrintResult(subject)

#
# generic printer for std::set
#
class PrintGenericSet (gdb.Function):
"""print generic set"""

handler = PrintGenericMapOrSet()

def __init__ (self):
super (PrintGenericSet, self).__init__ ("PrintGenericSet")

def setMaxNoResults(self, maxNoResults):
return self.handler.setMaxNoResults(maxNoResults)

def invokeCore(self, headlines, map, valueType, isConst, isPointer, valueHandler):
return self.handler.invokeCore(headlines, map, valueType, isConst, isPointer, valueHandler)

def invoke (self, headlines, mapLoc, valueType, isConst, isPointer, valueHandler, maxNoResults):
return self.handler.invoke(headlines, mapLoc, valueType, isConst, isPointer, valueHandler);

def PrintResult(self, subject):
return self.handler.PrintResult(subject)
Файл №2:

Код: Выделить всё

>  cat main.py
# -*- coding: utf-8 -*-

import gdb, platform, six, copy

from stlhelper import PrintGenericMap, PrintGenericSet

class PrintStaticData (gdb.Command):
"""Print STL data demo.\n"""

printer = None
result = []
headline = {}
sizesDef = {}

elements = [
'key',
'see_1',
'see_2',
'see_3',
]

errorEntry = {
'key'   : '?',
'see_1' : '?',
'see_2' : '?',
'see_3' : '?',
}

def __init__ (self):
super (PrintStaticData, self).__init__ ("PrintStaticData", gdb.COMMAND_USER)
self.headline = {
'key'   : 'Key',
'see_1' : 'Value #1',
'see_2' : 'Value #2',
'see_3' : 'Value #3',
}

def ReInit(self):
if(platform.python_version().startswith("2")):
for key, value in six.iteritems(self.headline):
self.sizesDef[key] = 0
else:
for key in self.headline.keys():
self.sizesDef[key] = 0
self.result = []
self.result.append(self.headline)

def ElemItemString(self, elem):
return elem

def Traverse(self, index, pair, node = None):
first = pair['first']
second = pair['second']
newEntry = copy.deepcopy(self.errorEntry)
newEntry['key'] = str(first)
newEntry['see_1'] = str(second['wantSeeThis_1'])
newEntry['see_2'] = str(second['wantSeeThis_2'])
newEntry['see_3'] = str(second['wantSeeThis_3'])
self.result.append(newEntry)
return ''

def invoke (self, arg, from_tty):
self.ReInit()

self.printer = PrintGenericMap()

data = gdb.parse_and_eval("staticData")
result = self.printer.invokeCore(
[],
data,
'',
self.Traverse)

self.printer.PrintResult(self)

PrintStaticData()
Файл .gdbinit (настройте свои пути):

Код: Выделить всё

cat $HOME/.gdbinit
set print object
set print pretty
set print static off
set pagination off
set auto-load safe-path /

python
sys.path.insert(0, "/home/me/TEST")
import main
end

set history filename ~/.gdb_history
set history save
Запустите демонстрацию в 'gdb', например. gcc 4.8.5

Код: Выделить всё

> gdb main
(gdb) break 35
Breakpoint 1 at 0x400c18: file main.cpp, line 35.

(gdb) r
Starting program: /home/me/TEST/main

Breakpoint 1, main () at main.cpp:35
35              return 0;

(gdb) PrintStaticData
----------------------------------------------
Key  Value #1  Value #2  Value #3
----------------------------------------------
1    1         "hello"   3
2    10        "hi"      0.29999999999999999
3    50        "salute"  11.5
Пока все хорошо.

Проблема в том, что он больше не работает для gcc 9.4.0. :-(

Причина в том, что внутренняя структура данных для типа STL std::map изменилась.

Мои помощники Python на самом деле не являются «универсальными» — они зависят от конкретной реализации STL.

Используя gcc 9.4.0, я нажал

Код: Выделить всё

(gdb) PrintStaticData
Python Exception  There is no member or method named _M_value_field.:
Error occurred in Python: There is no member or method named _M_value_field.
Поля _M_value_field больше нет, которое я использую здесь, в stdlhelper.py:

Код: Выделить всё

                   collectedLines.append(valueHandler(i, node.cast (nodetype).dereference()['_M_value_field'], node))
Поэтому я мог бы попытаться обновить код Python, чтобы он также обрабатывал новую реализацию STL.

Но я думаю (надеюсь), что в наборе инструментов gcc python STL уже есть какой-то универсальный инструмент, позволяющий сделать то же самое:

Обходите любой контейнер STL - без необходимости знать о его реализации - и вызывайте функцию обратного вызова для обработки каждого элемента, который хранится в контейнере.

Доступно ли оно из помощников Python gcc?

Может быть, есть ссылка на документацию/как?


Подробнее здесь: https://stackoverflow.com/questions/790 ... llback-for
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»