Motr  M0
gdb-extensions.py
Go to the documentation of this file.
1 #
2 # Copyright (c) 2020 Seagate Technology LLC and/or its Affiliates
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # For any questions about this software or licensing,
17 # please email opensource@seagate.com or cortx-questions@seagate.com.
18 #
19 
20 #
21 # To know more about Python APIs for gdb visit:
22 # http://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html#Python-API
23 #
24 # Nice series of tutorials about Writing gdb commands in Python
25 # http://sourceware.org/gdb/wiki/PythonGdbTutorial
26 #
27 def field_type(container, field):
28  cmd = "&((({0} *)0)->{1})".format(container, field)
29  tmp = gdb.parse_and_eval(cmd)
30  return tmp.type.target()
31 
32 def offset_of(container, field):
33  macro_call = "offsetof({0}, {1})".format(container, field)
34  offset = long(gdb.parse_and_eval(macro_call))
35  return offset
36 
37 def human_readable(count):
38  k = 1024
39  m = 1024 * k
40  g = 1024 * m
41  saved_count = count
42  result = ""
43  if count >= g:
44  c = count // g
45  result += "{0}G".format(c)
46  count %= g
47 
48  if count >= m:
49  c = count // m
50  result += "{0}M".format(c)
51  count %= m
52 
53  if count >= k:
54  c = count // k
55  result += "{0}K".format(c)
56  count %= k
57 
58  if count != 0 or (count == 0 and result == ""):
59  result += "{0}B".format(count)
60 
61  return str(saved_count) + "<" + result.strip() + ">"
62 
63 def sum(start_addr, count):
64  a = gdb.parse_and_eval("(unsigned char *){0:#x}".format(start_addr))
65  s = 0
66  for i in range(count):
67  s += a[i]
68 
69  return s
70 
71 #
72 #==============================================================================
73 #
74 class M0ListPrint(gdb.Command):
75  """Prints m0_list/m0_tl elements.
76 
77 Usage: m0-list-print [&]list [[struct|union] tag link [visit|"in-detail"]]
78 
79 First argument is only mandatory argument. It can be of type
80 - struct m0_list or struct m0_list *,
81 - struct m0_tl or struct m0_tl *
82 If this is the only argument supplied, then m0-list-print prints
83 address of each of links forming the list.
84 Example:
85 (gdb) m0-list-print session->s_slot_table[0]->sl_item_list
86 0x6257d0
87 0x7fffd80009d0
88 Total: 2
89 
90 Later three arguments can be either all present or all absent.
91 The three arguments together specify name of link field
92 within ambient object. This form of m0-list-print prints pointers to
93 ambient objects.
94 Example:
95 (gdb) m0-list-print session->s_slot_table[0]->sl_item_list struct m0_rpc_item ri_slot_refs[0].sr_link
96 0x6256e0
97 0x7fffd80008e0
98 Total: 2
99 
100 The last parameter is optional, if present controls how the elements
101 are displayed:
102 - If the last parameter == "in-detail", then it prints all the contents of
103  ambient objects(not addreses) of the list
104 - Otherwise the last argument 'visit' if present is name of a user-defined command
105  that takes one argument(think m0-list-print as a list traversing function
106  with pointer to 'visit' function as arguemnt).
107  The visit command will be executed for each object in list.
108  The implementation of visit command can decide which objects to print and how.
109 Example:
110 (gdb) m0-list-print fop_types_list struct m0_fop_type ft_linkage in-detail
111 <Prints all m0_fop_type objects from fop_types_list>
112 
113 (gdb) define session_visit
114 >set $s = (struct m0_rpc_session *)$arg0
115 >printf "session %p id %lu state %d\\n", $s, $s->s_session_id, $s->s_state
116 >end
117 (gdb) m0-list-print session->s_conn->c_sessions struct m0_rpc_session s_link session_visit
118 session 0x604c60 id 191837184000000002 state 4
119 session 0x624e50 id 0 state 4
120 Total: 2
121 (gdb) m0-list-print session->s_conn->c_sessions struct m0_rpc_session s_link
122 0x604c60
123 0x624e50
124 Total: 2
125 """
126 
127  def __init__(self):
128  gdb.Command.__init__(self, "m0-list-print",
129  gdb.COMMAND_SUPPORT, gdb.COMPLETE_SYMBOL)
130 
131  def invoke(self, arg, from_tty):
132  argv = gdb.string_to_argv(arg)
133  argc = len(argv)
134  if argc not in (1, 4, 5):
135  print 'Error: Usage: m0-list-print [&]list' \
136  ' [[struct|union] tag link [visit|"in-detail"]]'
137  return
138 
139  vhead, head, ok = self.get_head(argv)
140  if not ok:
141  return
142  offset, elm_type, ok = self.get_offset(argv)
143  if not ok:
144  return
145 
146  visit = argv[4] if argc == 5 else None
147  vnd = vhead['l_head']
148  nd = long(vnd)
149  total = 0
150 
151  while nd != head:
152  obj_addr = nd - offset
153  if visit is None:
154  print "0x%x" % obj_addr
155  elif visit == "in-detail":
156  cmd = "p *({0} *){1}".format(str(elm_type), obj_addr)
157  gdb.execute(cmd)
158  else:
159  cmd = "{0} {1}".format(visit, obj_addr)
160  gdb.execute(cmd)
161 
162  vnd = vnd['ll_next']
163  nd = long(vnd)
164  total += 1
165 
166  print "Total: %d" % total
167 
168  def get_head(self, argv):
169  ok = True
170  head = 0
171  vhead = gdb.parse_and_eval(argv[0])
172  type = str(vhead.type)
173  if type.startswith('const '):
174  type = type[len('const '):]
175 
176  if type == "struct m0_list":
177  head = long(vhead.address)
178  elif type == "struct m0_list *":
179  head = long(vhead)
180  elif type in ("struct m0_tl", "struct m0_tl *"):
181  vhead = vhead['t_head']
182  head = long(vhead.address)
183  else:
184  print "Error: Invalid argument type: '%s'" % type
185  ok = False
186  return vhead, head, ok
187 
188  def get_offset(self, argv):
189  argc = len(argv)
190  offset = 0
191  elm_type = None
192 
193  if argc in (4, 5):
194  if argv[1] not in ("struct", "union"):
195  print 'Error: Argument 2 must be ' + \
196  'either "struct" or "union"'
197  return 0, None, False
198 
199  str_elm_type = "{0} {1}".format(argv[1], argv[2])
200  anchor = argv[3]
201  try:
202  elm_type = gdb.lookup_type(str_elm_type)
203  except:
204  print "Error: type '{0}' does not exist".format(str_elm_type)
205  return 0, None, False
206 
207  type = str(field_type(str_elm_type, anchor))
208  if type not in ("struct m0_list_link", "struct m0_tlink"):
209  print "Error: Argument 4 must be of type m0_list_link or m0_tlink"
210  return 0, None, False
211 
212  if type == "struct m0_tlink":
213  anchor = anchor.strip() + ".t_link"
214 
215  offset = offset_of(str_elm_type, anchor)
216 
217  return offset, elm_type, True
218 
219 #
220 #==============================================================================
221 #
222 
223 class M0BufvecPrint(gdb.Command):
224  """Prints segments in m0_bufvec
225 
226 Usage: m0-bufvec-print [&]m0_bufvec
227 For each segment, the command prints,
228 - segment number,
229 - [start address, end_address),
230 - offset of first byte of segment, inside entire m0_bufvec, along with its
231  human readable representation,
232 - number of bytes in segment in human readable form,
233 - sumation of all the bytes in the segment. sum = 0, implies all the bytes in
234  the segment are zero.
235 """
236  def __init__(self):
237  gdb.Command.__init__(self, "m0-bufvec-print", \
238  gdb.COMMAND_SUPPORT, gdb.COMPLETE_SYMBOL)
239 
240  def invoke(self, arg, from_tty):
241  argv = gdb.string_to_argv(arg)
242  argc = len(argv)
243 
244  if argc != 1:
245  print "Error: Usage: m0-bufvec-print [&]m0_bufvec"
246  return
247 
248  vbufvec = gdb.parse_and_eval(argv[0])
249  t = str(vbufvec.type)
250  if t != "struct m0_bufvec" and t != "struct m0_bufvec *":
251  print "Error: Argument 1 must be either 'struct m0_bufvec' or" + \
252  " 'struct m0_bufvec *' type"
253  return
254 
255  nr_seg = long(vbufvec['ov_vec']['v_nr'])
256  buf_size = 0
257  offset = 0
258  sum_of_bytes_in_buf = 0
259  print "seg:index start_addr end_addr offset bcount sum"
260  for i in range(nr_seg):
261  start_addr = long(vbufvec['ov_buf'][i])
262  count = long(vbufvec['ov_vec']['v_count'][i])
263  end_addr = start_addr + count
264  sum_of_bytes_in_seg = sum(start_addr, count)
265  print "seg:{0} {1:#x} {2:#x} {3} {4} {5}".format(i, \
266  start_addr, end_addr, human_readable(offset), \
267  human_readable(count), sum_of_bytes_in_seg)
268  buf_size += count
269  offset += count
270  sum_of_bytes_in_buf += sum_of_bytes_in_seg
271 
272  print "nr_seg:", nr_seg
273  print "buf_size:", human_readable(buf_size)
274  print "sum:", sum_of_bytes_in_buf
275 
276 #
277 #==============================================================================
278 #
279 
280 class M0IndexvecPrint(gdb.Command):
281  """Prints segments in m0_indexvec
282 
283 Usage: m0-indexvec-print [&]m0_indexvec
284 """
285  def __init__(self):
286  gdb.Command.__init__(self, "m0-indexvec-print", \
287  gdb.COMMAND_SUPPORT, gdb.COMPLETE_SYMBOL)
288 
289  def invoke(self, arg, from_tty):
290  argv = gdb.string_to_argv(arg)
291  argc = len(argv)
292 
293  if argc != 1:
294  print "Error: Usage: m0-indexvec-print [&]m0_indexvec"
295  return
296 
297  v_ivec = gdb.parse_and_eval(argv[0])
298  t = str(v_ivec.type)
299  if t != "struct m0_indexvec" and t != "struct m0_indexvec *":
300  print "Error: Argument 1 must be of either 'struct m0_indexvec' or" + \
301  " 'struct m0_indexvec *' type."
302  return
303 
304  nr_seg = long(v_ivec['iv_vec']['v_nr'])
305  total_count = 0
306 
307  print " :seg_num index count"
308  for i in range(nr_seg):
309  index = long(v_ivec['iv_index'][i])
310  count = long(v_ivec['iv_vec']['v_count'][i])
311  print "seg:", i, index, count
312  total_count += count
313 
314  print "nr_seg:", nr_seg
315  print "total:", total_count
316 
317 # List of macros to be defined
318 macros = [ \
319 "offsetof(typ,memb) ((unsigned long)((char *)&(((typ *)0)->memb)))", \
320 "container_of(ptr, type, member) " + \
321  "((type *)((char *)(ptr)-(char *)(&((type *)0)->member)))" \
322 ]
323 
324 # Define macros listed in macros[]
325 for m in macros:
326  gdb.execute("macro define %s" % m)
327 
328 M0ListPrint()
331 
332 print "Loading python gdb extensions for Motr..."
333 #print "NOTE: If you've not already loaded, you may also want to load gdb-extensions"
def invoke(self, arg, from_tty)
def invoke(self, arg, from_tty)
def field_type(container, field)
def invoke(self, arg, from_tty)
def sum(start_addr, count)
def offset_of(container, field)
format
Definition: hist.py:128
def human_readable(count)