scripts/gdb: remove exception handling and refine print format
[linux-2.6-block.git] / scripts / gdb / linux / page_owner.py
CommitLineData
2f060190
KYL
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright (c) 2023 MediaTek Inc.
4#
5# Authors:
6# Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>
7#
8
9import gdb
10from linux import utils, stackdepot, constants, mm
11
12if constants.LX_CONFIG_PAGE_OWNER:
13 page_ext_t = utils.CachedType('struct page_ext')
14 page_owner_t = utils.CachedType('struct page_owner')
15
16 PAGE_OWNER_STACK_DEPTH = 16
17 PAGE_EXT_OWNER = constants.LX_PAGE_EXT_OWNER
18 PAGE_EXT_INVALID = 0x1
19 PAGE_EXT_OWNER_ALLOCATED = constants.LX_PAGE_EXT_OWNER_ALLOCATED
20
21def help():
22 t = """Usage: lx-dump-page-owner [Option]
23 Option:
24 --pfn [Decimal pfn]
25 Example:
26 lx-dump-page-owner --pfn 655360\n"""
27 gdb.write("Unrecognized command\n")
28 raise gdb.GdbError(t)
29
30class DumpPageOwner(gdb.Command):
31 """Dump page owner"""
32
33 min_pfn = None
34 max_pfn = None
35 p_ops = None
36 migrate_reason_names = None
37
38 def __init__(self):
39 super(DumpPageOwner, self).__init__("lx-dump-page-owner", gdb.COMMAND_SUPPORT)
40
41 def invoke(self, args, from_tty):
42 if not constants.LX_CONFIG_PAGE_OWNER:
43 raise gdb.GdbError('CONFIG_PAGE_OWNER does not enable')
44
45 page_owner_inited = gdb.parse_and_eval('page_owner_inited')
46 if page_owner_inited['key']['enabled']['counter'] != 0x1:
47 raise gdb.GdbError('page_owner_inited is not enabled')
48
49 self.p_ops = mm.page_ops().ops
50 self.get_page_owner_info()
51 argv = gdb.string_to_argv(args)
52 if len(argv) == 0:
53 self.read_page_owner()
54 elif len(argv) == 2:
55 if argv[0] == "--pfn":
56 pfn = int(argv[1])
57 self.read_page_owner_by_addr(self.p_ops.pfn_to_page(pfn))
58 else:
59 help()
60 else:
61 help()
62
63 def get_page_owner_info(self):
64 self.min_pfn = int(gdb.parse_and_eval("min_low_pfn"))
65 self.max_pfn = int(gdb.parse_and_eval("max_pfn"))
66 self.page_ext_size = int(gdb.parse_and_eval("page_ext_size"))
67 self.migrate_reason_names = gdb.parse_and_eval('migrate_reason_names')
68
69 def page_ext_invalid(self, page_ext):
70 if page_ext == gdb.Value(0):
71 return True
72 if page_ext.cast(utils.get_ulong_type()) & PAGE_EXT_INVALID == PAGE_EXT_INVALID:
73 return True
74 return False
75
76 def get_entry(self, base, index):
77 return (base.cast(utils.get_ulong_type()) + self.page_ext_size * index).cast(page_ext_t.get_type().pointer())
78
79 def lookup_page_ext(self, page):
80 pfn = self.p_ops.page_to_pfn(page)
81 section = self.p_ops.pfn_to_section(pfn)
82 page_ext = section["page_ext"]
83 if self.page_ext_invalid(page_ext):
84 return gdb.Value(0)
85 return self.get_entry(page_ext, pfn)
86
87 def page_ext_get(self, page):
88 page_ext = self.lookup_page_ext(page)
89 if page_ext != gdb.Value(0):
90 return page_ext
91 else:
92 return gdb.Value(0)
93
94 def get_page_owner(self, page_ext):
95 addr = page_ext.cast(utils.get_ulong_type()) + gdb.parse_and_eval("page_owner_ops")["offset"].cast(utils.get_ulong_type())
96 return addr.cast(page_owner_t.get_type().pointer())
97
98 def read_page_owner_by_addr(self, struct_page_addr):
99 page = gdb.Value(struct_page_addr).cast(utils.get_page_type().pointer())
100 pfn = self.p_ops.page_to_pfn(page)
101
102 if pfn < self.min_pfn or pfn > self.max_pfn or (not self.p_ops.pfn_valid(pfn)):
103 gdb.write("pfn is invalid\n")
104 return
105
106 page = self.p_ops.pfn_to_page(pfn)
107 page_ext = self.page_ext_get(page)
108
109 if page_ext == gdb.Value(0):
110 gdb.write("page_ext is null\n")
111 return
112
113 if not (page_ext['flags'] & (1 << PAGE_EXT_OWNER)):
114 gdb.write("page_owner flag is invalid\n")
115 raise gdb.GdbError('page_owner info is not present (never set?)\n')
116
117 if mm.test_bit(PAGE_EXT_OWNER_ALLOCATED, page_ext['flags'].address):
118 gdb.write('page_owner tracks the page as allocated\n')
119 else:
120 gdb.write('page_owner tracks the page as freed\n')
121
122 if not (page_ext['flags'] & (1 << PAGE_EXT_OWNER_ALLOCATED)):
123 gdb.write("page_owner is not allocated\n")
124
e52ec6a2
KYL
125 page_owner = self.get_page_owner(page_ext)
126 gdb.write("Page last allocated via order %d, gfp_mask: 0x%x, pid: %d, tgid: %d (%s), ts %u ns, free_ts %u ns\n" %\
127 (page_owner["order"], page_owner["gfp_mask"],\
128 page_owner["pid"], page_owner["tgid"], page_owner["comm"].string(),\
129 page_owner["ts_nsec"], page_owner["free_ts_nsec"]))
130 gdb.write("PFN: %d, Flags: 0x%x\n" % (pfn, page['flags']))
131 if page_owner["handle"] == 0:
132 gdb.write('page_owner allocation stack trace missing\n')
133 else:
134 stackdepot.stack_depot_print(page_owner["handle"])
2f060190 135
e52ec6a2
KYL
136 if page_owner["free_handle"] == 0:
137 gdb.write('page_owner free stack trace missing\n')
138 else:
139 gdb.write('page last free stack trace:\n')
140 stackdepot.stack_depot_print(page_owner["free_handle"])
141 if page_owner['last_migrate_reason'] != -1:
142 gdb.write('page has been migrated, last migrate reason: %s\n' % self.migrate_reason_names[page_owner['last_migrate_reason']])
2f060190
KYL
143
144 def read_page_owner(self):
145 pfn = self.min_pfn
146
147 # Find a valid PFN or the start of a MAX_ORDER_NR_PAGES area
148 while ((not self.p_ops.pfn_valid(pfn)) and (pfn & (self.p_ops.MAX_ORDER_NR_PAGES - 1))) != 0:
149 pfn += 1
150
151 while pfn < self.max_pfn:
152 #
153 # If the new page is in a new MAX_ORDER_NR_PAGES area,
154 # validate the area as existing, skip it if not
155 #
156 if ((pfn & (self.p_ops.MAX_ORDER_NR_PAGES - 1)) == 0) and (not self.p_ops.pfn_valid(pfn)):
157 pfn += (self.p_ops.MAX_ORDER_NR_PAGES - 1)
158 continue;
159
160 page = self.p_ops.pfn_to_page(pfn)
161 page_ext = self.page_ext_get(page)
162 if page_ext == gdb.Value(0):
163 pfn += 1
164 continue
165
166 if not (page_ext['flags'] & (1 << PAGE_EXT_OWNER)):
167 pfn += 1
168 continue
169 if not (page_ext['flags'] & (1 << PAGE_EXT_OWNER_ALLOCATED)):
170 pfn += 1
171 continue
172
e52ec6a2
KYL
173 page_owner = self.get_page_owner(page_ext)
174 gdb.write("Page allocated via order %d, gfp_mask: 0x%x, pid: %d, tgid: %d (%s), ts %u ns, free_ts %u ns\n" %\
175 (page_owner["order"], page_owner["gfp_mask"],\
176 page_owner["pid"], page_owner["tgid"], page_owner["comm"].string(),\
177 page_owner["ts_nsec"], page_owner["free_ts_nsec"]))
178 gdb.write("PFN: %d, Flags: 0x%x\n" % (pfn, page['flags']))
179 stackdepot.stack_depot_print(page_owner["handle"])
180 pfn += (1 << page_owner["order"])
2f060190
KYL
181
182DumpPageOwner()