xref: /haiku/src/system/kernel/vm/vm_debug.cpp (revision a2cf217f8f0bc7ab6951d9c2ae7c51d6f5e68ffd)
1086f997eSAugustin Cavalier /*
2086f997eSAugustin Cavalier  * Copyright 2024, Haiku, Inc. All rights reserved.
3086f997eSAugustin Cavalier  * Copyright 2010-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
4086f997eSAugustin Cavalier  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
5086f997eSAugustin Cavalier  * Distributed under the terms of the MIT License.
6086f997eSAugustin Cavalier  *
7086f997eSAugustin Cavalier  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8086f997eSAugustin Cavalier  * Distributed under the terms of the NewOS License.
9086f997eSAugustin Cavalier  */
10086f997eSAugustin Cavalier 
11086f997eSAugustin Cavalier 
12086f997eSAugustin Cavalier #include <ctype.h>
13086f997eSAugustin Cavalier 
14*a2cf217fSAugustin Cavalier #include <team.h>
15*a2cf217fSAugustin Cavalier 
16086f997eSAugustin Cavalier #include <vm/vm_page.h>
17086f997eSAugustin Cavalier #include <vm/vm.h>
18086f997eSAugustin Cavalier #include <vm/vm_priv.h>
19086f997eSAugustin Cavalier #include <vm/VMAddressSpace.h>
20086f997eSAugustin Cavalier #include <vm/VMArea.h>
21086f997eSAugustin Cavalier #include <vm/VMCache.h>
22086f997eSAugustin Cavalier 
23086f997eSAugustin Cavalier 
24086f997eSAugustin Cavalier #if DEBUG_CACHE_LIST
25086f997eSAugustin Cavalier 
26086f997eSAugustin Cavalier struct cache_info {
27086f997eSAugustin Cavalier 	VMCache*	cache;
28086f997eSAugustin Cavalier 	addr_t		page_count;
29086f997eSAugustin Cavalier 	addr_t		committed;
30086f997eSAugustin Cavalier };
31086f997eSAugustin Cavalier 
32086f997eSAugustin Cavalier static const uint32 kCacheInfoTableCount = 100 * 1024;
33086f997eSAugustin Cavalier static cache_info* sCacheInfoTable;
34086f997eSAugustin Cavalier 
35086f997eSAugustin Cavalier #endif	// DEBUG_CACHE_LIST
36086f997eSAugustin Cavalier 
37086f997eSAugustin Cavalier 
38086f997eSAugustin Cavalier static int
display_mem(int argc,char ** argv)39086f997eSAugustin Cavalier display_mem(int argc, char** argv)
40086f997eSAugustin Cavalier {
41086f997eSAugustin Cavalier 	bool physical = false;
42086f997eSAugustin Cavalier 	addr_t copyAddress;
43086f997eSAugustin Cavalier 	int32 displayWidth;
44086f997eSAugustin Cavalier 	int32 itemSize;
45086f997eSAugustin Cavalier 	int32 num = -1;
46086f997eSAugustin Cavalier 	addr_t address;
47086f997eSAugustin Cavalier 	int i = 1, j;
48086f997eSAugustin Cavalier 
49086f997eSAugustin Cavalier 	if (argc > 1 && argv[1][0] == '-') {
50086f997eSAugustin Cavalier 		if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "--physical")) {
51086f997eSAugustin Cavalier 			physical = true;
52086f997eSAugustin Cavalier 			i++;
53086f997eSAugustin Cavalier 		} else
54086f997eSAugustin Cavalier 			i = 99;
55086f997eSAugustin Cavalier 	}
56086f997eSAugustin Cavalier 
57086f997eSAugustin Cavalier 	if (argc < i + 1 || argc > i + 2) {
58086f997eSAugustin Cavalier 		kprintf("usage: dl/dw/ds/db/string [-p|--physical] <address> [num]\n"
59086f997eSAugustin Cavalier 			"\tdl - 8 bytes\n"
60086f997eSAugustin Cavalier 			"\tdw - 4 bytes\n"
61086f997eSAugustin Cavalier 			"\tds - 2 bytes\n"
62086f997eSAugustin Cavalier 			"\tdb - 1 byte\n"
63086f997eSAugustin Cavalier 			"\tstring - a whole string\n"
64086f997eSAugustin Cavalier 			"  -p or --physical only allows memory from a single page to be "
65086f997eSAugustin Cavalier 			"displayed.\n");
66086f997eSAugustin Cavalier 		return 0;
67086f997eSAugustin Cavalier 	}
68086f997eSAugustin Cavalier 
69086f997eSAugustin Cavalier 	address = parse_expression(argv[i]);
70086f997eSAugustin Cavalier 
71086f997eSAugustin Cavalier 	if (argc > i + 1)
72086f997eSAugustin Cavalier 		num = parse_expression(argv[i + 1]);
73086f997eSAugustin Cavalier 
74086f997eSAugustin Cavalier 	// build the format string
75086f997eSAugustin Cavalier 	if (strcmp(argv[0], "db") == 0) {
76086f997eSAugustin Cavalier 		itemSize = 1;
77086f997eSAugustin Cavalier 		displayWidth = 16;
78086f997eSAugustin Cavalier 	} else if (strcmp(argv[0], "ds") == 0) {
79086f997eSAugustin Cavalier 		itemSize = 2;
80086f997eSAugustin Cavalier 		displayWidth = 8;
81086f997eSAugustin Cavalier 	} else if (strcmp(argv[0], "dw") == 0) {
82086f997eSAugustin Cavalier 		itemSize = 4;
83086f997eSAugustin Cavalier 		displayWidth = 4;
84086f997eSAugustin Cavalier 	} else if (strcmp(argv[0], "dl") == 0) {
85086f997eSAugustin Cavalier 		itemSize = 8;
86086f997eSAugustin Cavalier 		displayWidth = 2;
87086f997eSAugustin Cavalier 	} else if (strcmp(argv[0], "string") == 0) {
88086f997eSAugustin Cavalier 		itemSize = 1;
89086f997eSAugustin Cavalier 		displayWidth = -1;
90086f997eSAugustin Cavalier 	} else {
91086f997eSAugustin Cavalier 		kprintf("display_mem called in an invalid way!\n");
92086f997eSAugustin Cavalier 		return 0;
93086f997eSAugustin Cavalier 	}
94086f997eSAugustin Cavalier 
95086f997eSAugustin Cavalier 	if (num <= 0)
96086f997eSAugustin Cavalier 		num = displayWidth;
97086f997eSAugustin Cavalier 
98086f997eSAugustin Cavalier 	void* physicalPageHandle = NULL;
99086f997eSAugustin Cavalier 
100086f997eSAugustin Cavalier 	if (physical) {
101086f997eSAugustin Cavalier 		int32 offset = address & (B_PAGE_SIZE - 1);
102086f997eSAugustin Cavalier 		if (num * itemSize + offset > B_PAGE_SIZE) {
103086f997eSAugustin Cavalier 			num = (B_PAGE_SIZE - offset) / itemSize;
104086f997eSAugustin Cavalier 			kprintf("NOTE: number of bytes has been cut to page size\n");
105086f997eSAugustin Cavalier 		}
106086f997eSAugustin Cavalier 
107086f997eSAugustin Cavalier 		address = ROUNDDOWN(address, B_PAGE_SIZE);
108086f997eSAugustin Cavalier 
109086f997eSAugustin Cavalier 		if (vm_get_physical_page_debug(address, &copyAddress,
110086f997eSAugustin Cavalier 				&physicalPageHandle) != B_OK) {
111086f997eSAugustin Cavalier 			kprintf("getting the hardware page failed.");
112086f997eSAugustin Cavalier 			return 0;
113086f997eSAugustin Cavalier 		}
114086f997eSAugustin Cavalier 
115086f997eSAugustin Cavalier 		address += offset;
116086f997eSAugustin Cavalier 		copyAddress += offset;
117086f997eSAugustin Cavalier 	} else
118086f997eSAugustin Cavalier 		copyAddress = address;
119086f997eSAugustin Cavalier 
120086f997eSAugustin Cavalier 	if (!strcmp(argv[0], "string")) {
121086f997eSAugustin Cavalier 		kprintf("%p \"", (char*)copyAddress);
122086f997eSAugustin Cavalier 
123086f997eSAugustin Cavalier 		// string mode
124086f997eSAugustin Cavalier 		for (i = 0; true; i++) {
125086f997eSAugustin Cavalier 			char c;
126086f997eSAugustin Cavalier 			if (debug_memcpy(B_CURRENT_TEAM, &c, (char*)copyAddress + i, 1)
127086f997eSAugustin Cavalier 					!= B_OK
128086f997eSAugustin Cavalier 				|| c == '\0') {
129086f997eSAugustin Cavalier 				break;
130086f997eSAugustin Cavalier 			}
131086f997eSAugustin Cavalier 
132086f997eSAugustin Cavalier 			if (c == '\n')
133086f997eSAugustin Cavalier 				kprintf("\\n");
134086f997eSAugustin Cavalier 			else if (c == '\t')
135086f997eSAugustin Cavalier 				kprintf("\\t");
136086f997eSAugustin Cavalier 			else {
137086f997eSAugustin Cavalier 				if (!isprint(c))
138086f997eSAugustin Cavalier 					c = '.';
139086f997eSAugustin Cavalier 
140086f997eSAugustin Cavalier 				kprintf("%c", c);
141086f997eSAugustin Cavalier 			}
142086f997eSAugustin Cavalier 		}
143086f997eSAugustin Cavalier 
144086f997eSAugustin Cavalier 		kprintf("\"\n");
145086f997eSAugustin Cavalier 	} else {
146086f997eSAugustin Cavalier 		// number mode
147086f997eSAugustin Cavalier 		for (i = 0; i < num; i++) {
148086f997eSAugustin Cavalier 			uint64 value;
149086f997eSAugustin Cavalier 
150086f997eSAugustin Cavalier 			if ((i % displayWidth) == 0) {
151086f997eSAugustin Cavalier 				int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
152086f997eSAugustin Cavalier 				if (i != 0)
153086f997eSAugustin Cavalier 					kprintf("\n");
154086f997eSAugustin Cavalier 
155086f997eSAugustin Cavalier 				kprintf("[0x%lx]  ", address + i * itemSize);
156086f997eSAugustin Cavalier 
157086f997eSAugustin Cavalier 				for (j = 0; j < displayed; j++) {
158086f997eSAugustin Cavalier 					char c;
159086f997eSAugustin Cavalier 					if (debug_memcpy(B_CURRENT_TEAM, &c,
160086f997eSAugustin Cavalier 							(char*)copyAddress + i * itemSize + j, 1) != B_OK) {
161086f997eSAugustin Cavalier 						displayed = j;
162086f997eSAugustin Cavalier 						break;
163086f997eSAugustin Cavalier 					}
164086f997eSAugustin Cavalier 					if (!isprint(c))
165086f997eSAugustin Cavalier 						c = '.';
166086f997eSAugustin Cavalier 
167086f997eSAugustin Cavalier 					kprintf("%c", c);
168086f997eSAugustin Cavalier 				}
169086f997eSAugustin Cavalier 				if (num > displayWidth) {
170086f997eSAugustin Cavalier 					// make sure the spacing in the last line is correct
171086f997eSAugustin Cavalier 					for (j = displayed; j < displayWidth * itemSize; j++)
172086f997eSAugustin Cavalier 						kprintf(" ");
173086f997eSAugustin Cavalier 				}
174086f997eSAugustin Cavalier 				kprintf("  ");
175086f997eSAugustin Cavalier 			}
176086f997eSAugustin Cavalier 
177086f997eSAugustin Cavalier 			if (debug_memcpy(B_CURRENT_TEAM, &value,
178086f997eSAugustin Cavalier 					(uint8*)copyAddress + i * itemSize, itemSize) != B_OK) {
179086f997eSAugustin Cavalier 				kprintf("read fault");
180086f997eSAugustin Cavalier 				break;
181086f997eSAugustin Cavalier 			}
182086f997eSAugustin Cavalier 
183086f997eSAugustin Cavalier 			switch (itemSize) {
184086f997eSAugustin Cavalier 				case 1:
185086f997eSAugustin Cavalier 					kprintf(" %02" B_PRIx8, *(uint8*)&value);
186086f997eSAugustin Cavalier 					break;
187086f997eSAugustin Cavalier 				case 2:
188086f997eSAugustin Cavalier 					kprintf(" %04" B_PRIx16, *(uint16*)&value);
189086f997eSAugustin Cavalier 					break;
190086f997eSAugustin Cavalier 				case 4:
191086f997eSAugustin Cavalier 					kprintf(" %08" B_PRIx32, *(uint32*)&value);
192086f997eSAugustin Cavalier 					break;
193086f997eSAugustin Cavalier 				case 8:
194086f997eSAugustin Cavalier 					kprintf(" %016" B_PRIx64, *(uint64*)&value);
195086f997eSAugustin Cavalier 					break;
196086f997eSAugustin Cavalier 			}
197086f997eSAugustin Cavalier 		}
198086f997eSAugustin Cavalier 
199086f997eSAugustin Cavalier 		kprintf("\n");
200086f997eSAugustin Cavalier 	}
201086f997eSAugustin Cavalier 
202086f997eSAugustin Cavalier 	if (physical) {
203086f997eSAugustin Cavalier 		copyAddress = ROUNDDOWN(copyAddress, B_PAGE_SIZE);
204086f997eSAugustin Cavalier 		vm_put_physical_page_debug(copyAddress, physicalPageHandle);
205086f997eSAugustin Cavalier 	}
206086f997eSAugustin Cavalier 	return 0;
207086f997eSAugustin Cavalier }
208086f997eSAugustin Cavalier 
209086f997eSAugustin Cavalier 
210086f997eSAugustin Cavalier static void
dump_cache_tree_recursively(VMCache * cache,int level,VMCache * highlightCache)211086f997eSAugustin Cavalier dump_cache_tree_recursively(VMCache* cache, int level,
212086f997eSAugustin Cavalier 	VMCache* highlightCache)
213086f997eSAugustin Cavalier {
214086f997eSAugustin Cavalier 	// print this cache
215086f997eSAugustin Cavalier 	for (int i = 0; i < level; i++)
216086f997eSAugustin Cavalier 		kprintf("  ");
217086f997eSAugustin Cavalier 	if (cache == highlightCache)
218086f997eSAugustin Cavalier 		kprintf("%p <--\n", cache);
219086f997eSAugustin Cavalier 	else
220086f997eSAugustin Cavalier 		kprintf("%p\n", cache);
221086f997eSAugustin Cavalier 
222086f997eSAugustin Cavalier 	// recursively print its consumers
223086f997eSAugustin Cavalier 	for (VMCache::ConsumerList::Iterator it = cache->consumers.GetIterator();
224086f997eSAugustin Cavalier 			VMCache* consumer = it.Next();) {
225086f997eSAugustin Cavalier 		dump_cache_tree_recursively(consumer, level + 1, highlightCache);
226086f997eSAugustin Cavalier 	}
227086f997eSAugustin Cavalier }
228086f997eSAugustin Cavalier 
229086f997eSAugustin Cavalier 
230086f997eSAugustin Cavalier static int
dump_cache_tree(int argc,char ** argv)231086f997eSAugustin Cavalier dump_cache_tree(int argc, char** argv)
232086f997eSAugustin Cavalier {
233086f997eSAugustin Cavalier 	if (argc != 2 || !strcmp(argv[1], "--help")) {
234086f997eSAugustin Cavalier 		kprintf("usage: %s <address>\n", argv[0]);
235086f997eSAugustin Cavalier 		return 0;
236086f997eSAugustin Cavalier 	}
237086f997eSAugustin Cavalier 
238086f997eSAugustin Cavalier 	addr_t address = parse_expression(argv[1]);
239086f997eSAugustin Cavalier 	if (address == 0)
240086f997eSAugustin Cavalier 		return 0;
241086f997eSAugustin Cavalier 
242086f997eSAugustin Cavalier 	VMCache* cache = (VMCache*)address;
243086f997eSAugustin Cavalier 	VMCache* root = cache;
244086f997eSAugustin Cavalier 
245086f997eSAugustin Cavalier 	// find the root cache (the transitive source)
246086f997eSAugustin Cavalier 	while (root->source != NULL)
247086f997eSAugustin Cavalier 		root = root->source;
248086f997eSAugustin Cavalier 
249086f997eSAugustin Cavalier 	dump_cache_tree_recursively(root, 0, cache);
250086f997eSAugustin Cavalier 
251086f997eSAugustin Cavalier 	return 0;
252086f997eSAugustin Cavalier }
253086f997eSAugustin Cavalier 
254086f997eSAugustin Cavalier 
255086f997eSAugustin Cavalier const char*
vm_cache_type_to_string(int32 type)256086f997eSAugustin Cavalier vm_cache_type_to_string(int32 type)
257086f997eSAugustin Cavalier {
258086f997eSAugustin Cavalier 	switch (type) {
259086f997eSAugustin Cavalier 		case CACHE_TYPE_RAM:
260086f997eSAugustin Cavalier 			return "RAM";
261086f997eSAugustin Cavalier 		case CACHE_TYPE_DEVICE:
262086f997eSAugustin Cavalier 			return "device";
263086f997eSAugustin Cavalier 		case CACHE_TYPE_VNODE:
264086f997eSAugustin Cavalier 			return "vnode";
265086f997eSAugustin Cavalier 		case CACHE_TYPE_NULL:
266086f997eSAugustin Cavalier 			return "null";
267086f997eSAugustin Cavalier 
268086f997eSAugustin Cavalier 		default:
269086f997eSAugustin Cavalier 			return "unknown";
270086f997eSAugustin Cavalier 	}
271086f997eSAugustin Cavalier }
272086f997eSAugustin Cavalier 
273086f997eSAugustin Cavalier 
274086f997eSAugustin Cavalier #if DEBUG_CACHE_LIST
275086f997eSAugustin Cavalier 
276086f997eSAugustin Cavalier static void
update_cache_info_recursively(VMCache * cache,cache_info & info)277086f997eSAugustin Cavalier update_cache_info_recursively(VMCache* cache, cache_info& info)
278086f997eSAugustin Cavalier {
279086f997eSAugustin Cavalier 	info.page_count += cache->page_count;
280086f997eSAugustin Cavalier 	if (cache->type == CACHE_TYPE_RAM)
281086f997eSAugustin Cavalier 		info.committed += cache->committed_size;
282086f997eSAugustin Cavalier 
283086f997eSAugustin Cavalier 	// recurse
284086f997eSAugustin Cavalier 	for (VMCache::ConsumerList::Iterator it = cache->consumers.GetIterator();
285086f997eSAugustin Cavalier 			VMCache* consumer = it.Next();) {
286086f997eSAugustin Cavalier 		update_cache_info_recursively(consumer, info);
287086f997eSAugustin Cavalier 	}
288086f997eSAugustin Cavalier }
289086f997eSAugustin Cavalier 
290086f997eSAugustin Cavalier 
291086f997eSAugustin Cavalier static int
cache_info_compare_page_count(const void * _a,const void * _b)292086f997eSAugustin Cavalier cache_info_compare_page_count(const void* _a, const void* _b)
293086f997eSAugustin Cavalier {
294086f997eSAugustin Cavalier 	const cache_info* a = (const cache_info*)_a;
295086f997eSAugustin Cavalier 	const cache_info* b = (const cache_info*)_b;
296086f997eSAugustin Cavalier 	if (a->page_count == b->page_count)
297086f997eSAugustin Cavalier 		return 0;
298086f997eSAugustin Cavalier 	return a->page_count < b->page_count ? 1 : -1;
299086f997eSAugustin Cavalier }
300086f997eSAugustin Cavalier 
301086f997eSAugustin Cavalier 
302086f997eSAugustin Cavalier static int
cache_info_compare_committed(const void * _a,const void * _b)303086f997eSAugustin Cavalier cache_info_compare_committed(const void* _a, const void* _b)
304086f997eSAugustin Cavalier {
305086f997eSAugustin Cavalier 	const cache_info* a = (const cache_info*)_a;
306086f997eSAugustin Cavalier 	const cache_info* b = (const cache_info*)_b;
307086f997eSAugustin Cavalier 	if (a->committed == b->committed)
308086f997eSAugustin Cavalier 		return 0;
309086f997eSAugustin Cavalier 	return a->committed < b->committed ? 1 : -1;
310086f997eSAugustin Cavalier }
311086f997eSAugustin Cavalier 
312086f997eSAugustin Cavalier 
313086f997eSAugustin Cavalier static void
dump_caches_recursively(VMCache * cache,cache_info & info,int level)314086f997eSAugustin Cavalier dump_caches_recursively(VMCache* cache, cache_info& info, int level)
315086f997eSAugustin Cavalier {
316086f997eSAugustin Cavalier 	for (int i = 0; i < level; i++)
317086f997eSAugustin Cavalier 		kprintf("  ");
318086f997eSAugustin Cavalier 
319086f997eSAugustin Cavalier 	kprintf("%p: type: %s, base: %" B_PRIdOFF ", size: %" B_PRIdOFF ", "
320086f997eSAugustin Cavalier 		"pages: %" B_PRIu32, cache, vm_cache_type_to_string(cache->type),
321086f997eSAugustin Cavalier 		cache->virtual_base, cache->virtual_end, cache->page_count);
322086f997eSAugustin Cavalier 
323086f997eSAugustin Cavalier 	if (level == 0)
324086f997eSAugustin Cavalier 		kprintf("/%lu", info.page_count);
325086f997eSAugustin Cavalier 
326086f997eSAugustin Cavalier 	if (cache->type == CACHE_TYPE_RAM || (level == 0 && info.committed > 0)) {
327086f997eSAugustin Cavalier 		kprintf(", committed: %" B_PRIdOFF, cache->committed_size);
328086f997eSAugustin Cavalier 
329086f997eSAugustin Cavalier 		if (level == 0)
330086f997eSAugustin Cavalier 			kprintf("/%lu", info.committed);
331086f997eSAugustin Cavalier 	}
332086f997eSAugustin Cavalier 
333086f997eSAugustin Cavalier 	// areas
334086f997eSAugustin Cavalier 	if (cache->areas != NULL) {
335086f997eSAugustin Cavalier 		VMArea* area = cache->areas;
336086f997eSAugustin Cavalier 		kprintf(", areas: %" B_PRId32 " (%s, team: %" B_PRId32 ")", area->id,
337086f997eSAugustin Cavalier 			area->name, area->address_space->ID());
338086f997eSAugustin Cavalier 
339086f997eSAugustin Cavalier 		while (area->cache_next != NULL) {
340086f997eSAugustin Cavalier 			area = area->cache_next;
341086f997eSAugustin Cavalier 			kprintf(", %" B_PRId32, area->id);
342086f997eSAugustin Cavalier 		}
343086f997eSAugustin Cavalier 	}
344086f997eSAugustin Cavalier 
345086f997eSAugustin Cavalier 	kputs("\n");
346086f997eSAugustin Cavalier 
347086f997eSAugustin Cavalier 	// recurse
348086f997eSAugustin Cavalier 	for (VMCache::ConsumerList::Iterator it = cache->consumers.GetIterator();
349086f997eSAugustin Cavalier 			VMCache* consumer = it.Next();) {
350086f997eSAugustin Cavalier 		dump_caches_recursively(consumer, info, level + 1);
351086f997eSAugustin Cavalier 	}
352086f997eSAugustin Cavalier }
353086f997eSAugustin Cavalier 
354086f997eSAugustin Cavalier 
355086f997eSAugustin Cavalier static int
dump_caches(int argc,char ** argv)356086f997eSAugustin Cavalier dump_caches(int argc, char** argv)
357086f997eSAugustin Cavalier {
358086f997eSAugustin Cavalier 	if (sCacheInfoTable == NULL) {
359086f997eSAugustin Cavalier 		kprintf("No cache info table!\n");
360086f997eSAugustin Cavalier 		return 0;
361086f997eSAugustin Cavalier 	}
362086f997eSAugustin Cavalier 
363086f997eSAugustin Cavalier 	bool sortByPageCount = true;
364086f997eSAugustin Cavalier 
365086f997eSAugustin Cavalier 	for (int32 i = 1; i < argc; i++) {
366086f997eSAugustin Cavalier 		if (strcmp(argv[i], "-c") == 0) {
367086f997eSAugustin Cavalier 			sortByPageCount = false;
368086f997eSAugustin Cavalier 		} else {
369086f997eSAugustin Cavalier 			print_debugger_command_usage(argv[0]);
370086f997eSAugustin Cavalier 			return 0;
371086f997eSAugustin Cavalier 		}
372086f997eSAugustin Cavalier 	}
373086f997eSAugustin Cavalier 
374086f997eSAugustin Cavalier 	uint32 totalCount = 0;
375086f997eSAugustin Cavalier 	uint32 rootCount = 0;
376086f997eSAugustin Cavalier 	off_t totalCommitted = 0;
377086f997eSAugustin Cavalier 	page_num_t totalPages = 0;
378086f997eSAugustin Cavalier 
379086f997eSAugustin Cavalier 	VMCache* cache = gDebugCacheList;
380086f997eSAugustin Cavalier 	while (cache) {
381086f997eSAugustin Cavalier 		totalCount++;
382086f997eSAugustin Cavalier 		if (cache->source == NULL) {
383086f997eSAugustin Cavalier 			cache_info stackInfo;
384086f997eSAugustin Cavalier 			cache_info& info = rootCount < kCacheInfoTableCount
385086f997eSAugustin Cavalier 				? sCacheInfoTable[rootCount] : stackInfo;
386086f997eSAugustin Cavalier 			rootCount++;
387086f997eSAugustin Cavalier 			info.cache = cache;
388086f997eSAugustin Cavalier 			info.page_count = 0;
389086f997eSAugustin Cavalier 			info.committed = 0;
390086f997eSAugustin Cavalier 			update_cache_info_recursively(cache, info);
391086f997eSAugustin Cavalier 			totalCommitted += info.committed;
392086f997eSAugustin Cavalier 			totalPages += info.page_count;
393086f997eSAugustin Cavalier 		}
394086f997eSAugustin Cavalier 
395086f997eSAugustin Cavalier 		cache = cache->debug_next;
396086f997eSAugustin Cavalier 	}
397086f997eSAugustin Cavalier 
398086f997eSAugustin Cavalier 	kprintf("total committed memory: %" B_PRIdOFF ", total used pages: %"
399086f997eSAugustin Cavalier 		B_PRIuPHYSADDR "\n", totalCommitted, totalPages);
400086f997eSAugustin Cavalier 	kprintf("%" B_PRIu32 " caches (%" B_PRIu32 " root caches), sorted by %s "
401086f997eSAugustin Cavalier 		"per cache tree...\n\n", totalCount, rootCount, sortByPageCount ?
402086f997eSAugustin Cavalier 			"page count" : "committed size");
403086f997eSAugustin Cavalier 
404086f997eSAugustin Cavalier 	if (rootCount > kCacheInfoTableCount) {
405086f997eSAugustin Cavalier 		kprintf("Cache info table too small! Can't sort and print caches!\n");
406086f997eSAugustin Cavalier 		return 0;
407086f997eSAugustin Cavalier 	}
408086f997eSAugustin Cavalier 
409086f997eSAugustin Cavalier 	qsort(sCacheInfoTable, rootCount, sizeof(cache_info),
410086f997eSAugustin Cavalier 		sortByPageCount
411086f997eSAugustin Cavalier 			? &cache_info_compare_page_count
412086f997eSAugustin Cavalier 			: &cache_info_compare_committed);
413086f997eSAugustin Cavalier 
414086f997eSAugustin Cavalier 	for (uint32 i = 0; i < rootCount; i++) {
415086f997eSAugustin Cavalier 		cache_info& info = sCacheInfoTable[i];
416086f997eSAugustin Cavalier 		dump_caches_recursively(info.cache, info, 0);
417086f997eSAugustin Cavalier 	}
418086f997eSAugustin Cavalier 
419086f997eSAugustin Cavalier 	return 0;
420086f997eSAugustin Cavalier }
421086f997eSAugustin Cavalier 
422086f997eSAugustin Cavalier #endif	// DEBUG_CACHE_LIST
423086f997eSAugustin Cavalier 
424086f997eSAugustin Cavalier 
425086f997eSAugustin Cavalier static int
dump_cache(int argc,char ** argv)426086f997eSAugustin Cavalier dump_cache(int argc, char** argv)
427086f997eSAugustin Cavalier {
428086f997eSAugustin Cavalier 	VMCache* cache;
429086f997eSAugustin Cavalier 	bool showPages = false;
430086f997eSAugustin Cavalier 	int i = 1;
431086f997eSAugustin Cavalier 
432086f997eSAugustin Cavalier 	if (argc < 2 || !strcmp(argv[1], "--help")) {
433086f997eSAugustin Cavalier 		kprintf("usage: %s [-ps] <address>\n"
434086f997eSAugustin Cavalier 			"  if -p is specified, all pages are shown, if -s is used\n"
435086f997eSAugustin Cavalier 			"  only the cache info is shown respectively.\n", argv[0]);
436086f997eSAugustin Cavalier 		return 0;
437086f997eSAugustin Cavalier 	}
438086f997eSAugustin Cavalier 	while (argv[i][0] == '-') {
439086f997eSAugustin Cavalier 		char* arg = argv[i] + 1;
440086f997eSAugustin Cavalier 		while (arg[0]) {
441086f997eSAugustin Cavalier 			if (arg[0] == 'p')
442086f997eSAugustin Cavalier 				showPages = true;
443086f997eSAugustin Cavalier 			arg++;
444086f997eSAugustin Cavalier 		}
445086f997eSAugustin Cavalier 		i++;
446086f997eSAugustin Cavalier 	}
447086f997eSAugustin Cavalier 	if (argv[i] == NULL) {
448086f997eSAugustin Cavalier 		kprintf("%s: invalid argument, pass address\n", argv[0]);
449086f997eSAugustin Cavalier 		return 0;
450086f997eSAugustin Cavalier 	}
451086f997eSAugustin Cavalier 
452086f997eSAugustin Cavalier 	addr_t address = parse_expression(argv[i]);
453086f997eSAugustin Cavalier 	if (address == 0)
454086f997eSAugustin Cavalier 		return 0;
455086f997eSAugustin Cavalier 
456086f997eSAugustin Cavalier 	cache = (VMCache*)address;
457086f997eSAugustin Cavalier 
458086f997eSAugustin Cavalier 	cache->Dump(showPages);
459086f997eSAugustin Cavalier 
460086f997eSAugustin Cavalier 	set_debug_variable("_sourceCache", (addr_t)cache->source);
461086f997eSAugustin Cavalier 
462086f997eSAugustin Cavalier 	return 0;
463086f997eSAugustin Cavalier }
464086f997eSAugustin Cavalier 
465086f997eSAugustin Cavalier 
466086f997eSAugustin Cavalier static void
dump_area_struct(VMArea * area,bool mappings)467086f997eSAugustin Cavalier dump_area_struct(VMArea* area, bool mappings)
468086f997eSAugustin Cavalier {
469086f997eSAugustin Cavalier 	kprintf("AREA: %p\n", area);
470086f997eSAugustin Cavalier 	kprintf("name:\t\t'%s'\n", area->name);
471086f997eSAugustin Cavalier 	kprintf("owner:\t\t0x%" B_PRIx32 "\n", area->address_space->ID());
472086f997eSAugustin Cavalier 	kprintf("id:\t\t0x%" B_PRIx32 "\n", area->id);
473086f997eSAugustin Cavalier 	kprintf("base:\t\t0x%lx\n", area->Base());
474086f997eSAugustin Cavalier 	kprintf("size:\t\t0x%lx\n", area->Size());
475086f997eSAugustin Cavalier 	kprintf("protection:\t0x%" B_PRIx32 "\n", area->protection);
476086f997eSAugustin Cavalier 	kprintf("page_protection:%p\n", area->page_protections);
477086f997eSAugustin Cavalier 	kprintf("wiring:\t\t0x%x\n", area->wiring);
478086f997eSAugustin Cavalier 	kprintf("memory_type:\t%#" B_PRIx32 "\n", area->MemoryType());
479086f997eSAugustin Cavalier 	kprintf("cache:\t\t%p\n", area->cache);
480086f997eSAugustin Cavalier 	kprintf("cache_type:\t%s\n", vm_cache_type_to_string(area->cache_type));
481086f997eSAugustin Cavalier 	kprintf("cache_offset:\t0x%" B_PRIx64 "\n", area->cache_offset);
482086f997eSAugustin Cavalier 	kprintf("cache_next:\t%p\n", area->cache_next);
483086f997eSAugustin Cavalier 	kprintf("cache_prev:\t%p\n", area->cache_prev);
484086f997eSAugustin Cavalier 
485086f997eSAugustin Cavalier 	VMAreaMappings::Iterator iterator = area->mappings.GetIterator();
486086f997eSAugustin Cavalier 	if (mappings) {
487086f997eSAugustin Cavalier 		kprintf("page mappings:\n");
488086f997eSAugustin Cavalier 		while (iterator.HasNext()) {
489086f997eSAugustin Cavalier 			vm_page_mapping* mapping = iterator.Next();
490086f997eSAugustin Cavalier 			kprintf("  %p", mapping->page);
491086f997eSAugustin Cavalier 		}
492086f997eSAugustin Cavalier 		kprintf("\n");
493086f997eSAugustin Cavalier 	} else {
494086f997eSAugustin Cavalier 		uint32 count = 0;
495086f997eSAugustin Cavalier 		while (iterator.Next() != NULL) {
496086f997eSAugustin Cavalier 			count++;
497086f997eSAugustin Cavalier 		}
498086f997eSAugustin Cavalier 		kprintf("page mappings:\t%" B_PRIu32 "\n", count);
499086f997eSAugustin Cavalier 	}
500086f997eSAugustin Cavalier }
501086f997eSAugustin Cavalier 
502086f997eSAugustin Cavalier 
503086f997eSAugustin Cavalier static int
dump_area(int argc,char ** argv)504086f997eSAugustin Cavalier dump_area(int argc, char** argv)
505086f997eSAugustin Cavalier {
506086f997eSAugustin Cavalier 	bool mappings = false;
507086f997eSAugustin Cavalier 	bool found = false;
508086f997eSAugustin Cavalier 	int32 index = 1;
509086f997eSAugustin Cavalier 	VMArea* area;
510086f997eSAugustin Cavalier 	addr_t num;
511086f997eSAugustin Cavalier 
512086f997eSAugustin Cavalier 	if (argc < 2 || !strcmp(argv[1], "--help")) {
513086f997eSAugustin Cavalier 		kprintf("usage: area [-m] [id|contains|address|name] <id|address|name>\n"
514086f997eSAugustin Cavalier 			"All areas matching either id/address/name are listed. You can\n"
515086f997eSAugustin Cavalier 			"force to check only a specific item by prefixing the specifier\n"
516086f997eSAugustin Cavalier 			"with the id/contains/address/name keywords.\n"
517086f997eSAugustin Cavalier 			"-m shows the area's mappings as well.\n");
518086f997eSAugustin Cavalier 		return 0;
519086f997eSAugustin Cavalier 	}
520086f997eSAugustin Cavalier 
521086f997eSAugustin Cavalier 	if (!strcmp(argv[1], "-m")) {
522086f997eSAugustin Cavalier 		mappings = true;
523086f997eSAugustin Cavalier 		index++;
524086f997eSAugustin Cavalier 	}
525086f997eSAugustin Cavalier 
526086f997eSAugustin Cavalier 	int32 mode = 0xf;
527086f997eSAugustin Cavalier 	if (!strcmp(argv[index], "id"))
528086f997eSAugustin Cavalier 		mode = 1;
529086f997eSAugustin Cavalier 	else if (!strcmp(argv[index], "contains"))
530086f997eSAugustin Cavalier 		mode = 2;
531086f997eSAugustin Cavalier 	else if (!strcmp(argv[index], "name"))
532086f997eSAugustin Cavalier 		mode = 4;
533086f997eSAugustin Cavalier 	else if (!strcmp(argv[index], "address"))
534086f997eSAugustin Cavalier 		mode = 0;
535086f997eSAugustin Cavalier 	if (mode != 0xf)
536086f997eSAugustin Cavalier 		index++;
537086f997eSAugustin Cavalier 
538086f997eSAugustin Cavalier 	if (index >= argc) {
539086f997eSAugustin Cavalier 		kprintf("No area specifier given.\n");
540086f997eSAugustin Cavalier 		return 0;
541086f997eSAugustin Cavalier 	}
542086f997eSAugustin Cavalier 
543086f997eSAugustin Cavalier 	num = parse_expression(argv[index]);
544086f997eSAugustin Cavalier 
545086f997eSAugustin Cavalier 	if (mode == 0) {
546086f997eSAugustin Cavalier 		dump_area_struct((struct VMArea*)num, mappings);
547086f997eSAugustin Cavalier 	} else {
548086f997eSAugustin Cavalier 		// walk through the area list, looking for the arguments as a name
549086f997eSAugustin Cavalier 
550086f997eSAugustin Cavalier 		VMAreasTree::Iterator it = VMAreas::GetIterator();
551086f997eSAugustin Cavalier 		while ((area = it.Next()) != NULL) {
552086f997eSAugustin Cavalier 			if (((mode & 4) != 0
553086f997eSAugustin Cavalier 					&& !strcmp(argv[index], area->name))
554086f997eSAugustin Cavalier 				|| (num != 0 && (((mode & 1) != 0 && (addr_t)area->id == num)
555086f997eSAugustin Cavalier 					|| (((mode & 2) != 0 && area->Base() <= num
556086f997eSAugustin Cavalier 						&& area->Base() + area->Size() > num))))) {
557086f997eSAugustin Cavalier 				dump_area_struct(area, mappings);
558086f997eSAugustin Cavalier 				found = true;
559086f997eSAugustin Cavalier 			}
560086f997eSAugustin Cavalier 		}
561086f997eSAugustin Cavalier 
562086f997eSAugustin Cavalier 		if (!found)
563086f997eSAugustin Cavalier 			kprintf("could not find area %s (%ld)\n", argv[index], num);
564086f997eSAugustin Cavalier 	}
565086f997eSAugustin Cavalier 
566086f997eSAugustin Cavalier 	return 0;
567086f997eSAugustin Cavalier }
568086f997eSAugustin Cavalier 
569086f997eSAugustin Cavalier 
570086f997eSAugustin Cavalier static int
dump_area_list(int argc,char ** argv)571086f997eSAugustin Cavalier dump_area_list(int argc, char** argv)
572086f997eSAugustin Cavalier {
573086f997eSAugustin Cavalier 	VMArea* area;
574086f997eSAugustin Cavalier 	const char* name = NULL;
575086f997eSAugustin Cavalier 	int32 id = 0;
576086f997eSAugustin Cavalier 
577086f997eSAugustin Cavalier 	if (argc > 1) {
578086f997eSAugustin Cavalier 		id = parse_expression(argv[1]);
579086f997eSAugustin Cavalier 		if (id == 0)
580086f997eSAugustin Cavalier 			name = argv[1];
581086f997eSAugustin Cavalier 	}
582086f997eSAugustin Cavalier 
583086f997eSAugustin Cavalier 	kprintf("%-*s      id  %-*s    %-*sprotect lock  name\n",
584086f997eSAugustin Cavalier 		B_PRINTF_POINTER_WIDTH, "addr", B_PRINTF_POINTER_WIDTH, "base",
585086f997eSAugustin Cavalier 		B_PRINTF_POINTER_WIDTH, "size");
586086f997eSAugustin Cavalier 
587086f997eSAugustin Cavalier 	VMAreasTree::Iterator it = VMAreas::GetIterator();
588086f997eSAugustin Cavalier 	while ((area = it.Next()) != NULL) {
589086f997eSAugustin Cavalier 		if ((id != 0 && area->address_space->ID() != id)
590086f997eSAugustin Cavalier 			|| (name != NULL && strstr(area->name, name) == NULL))
591086f997eSAugustin Cavalier 			continue;
592086f997eSAugustin Cavalier 
593086f997eSAugustin Cavalier 		kprintf("%p %5" B_PRIx32 "  %p  %p %4" B_PRIx32 " %4d  %s\n", area,
594086f997eSAugustin Cavalier 			area->id, (void*)area->Base(), (void*)area->Size(),
595086f997eSAugustin Cavalier 			area->protection, area->wiring, area->name);
596086f997eSAugustin Cavalier 	}
597086f997eSAugustin Cavalier 	return 0;
598086f997eSAugustin Cavalier }
599086f997eSAugustin Cavalier 
600086f997eSAugustin Cavalier 
601086f997eSAugustin Cavalier static int
dump_available_memory(int argc,char ** argv)602086f997eSAugustin Cavalier dump_available_memory(int argc, char** argv)
603086f997eSAugustin Cavalier {
604086f997eSAugustin Cavalier 	kprintf("Available memory: %" B_PRIdOFF "/%" B_PRIuPHYSADDR " bytes\n",
605086f997eSAugustin Cavalier 		vm_available_memory_debug(), (phys_addr_t)vm_page_num_pages() * B_PAGE_SIZE);
606086f997eSAugustin Cavalier 	return 0;
607086f997eSAugustin Cavalier }
608086f997eSAugustin Cavalier 
609086f997eSAugustin Cavalier 
610086f997eSAugustin Cavalier static int
dump_mapping_info(int argc,char ** argv)611086f997eSAugustin Cavalier dump_mapping_info(int argc, char** argv)
612086f997eSAugustin Cavalier {
613086f997eSAugustin Cavalier 	bool reverseLookup = false;
614086f997eSAugustin Cavalier 	bool pageLookup = false;
615086f997eSAugustin Cavalier 
616086f997eSAugustin Cavalier 	int argi = 1;
617086f997eSAugustin Cavalier 	for (; argi < argc && argv[argi][0] == '-'; argi++) {
618086f997eSAugustin Cavalier 		const char* arg = argv[argi];
619086f997eSAugustin Cavalier 		if (strcmp(arg, "-r") == 0) {
620086f997eSAugustin Cavalier 			reverseLookup = true;
621086f997eSAugustin Cavalier 		} else if (strcmp(arg, "-p") == 0) {
622086f997eSAugustin Cavalier 			reverseLookup = true;
623086f997eSAugustin Cavalier 			pageLookup = true;
624086f997eSAugustin Cavalier 		} else {
625086f997eSAugustin Cavalier 			print_debugger_command_usage(argv[0]);
626086f997eSAugustin Cavalier 			return 0;
627086f997eSAugustin Cavalier 		}
628086f997eSAugustin Cavalier 	}
629086f997eSAugustin Cavalier 
630086f997eSAugustin Cavalier 	// We need at least one argument, the address. Optionally a thread ID can be
631086f997eSAugustin Cavalier 	// specified.
632086f997eSAugustin Cavalier 	if (argi >= argc || argi + 2 < argc) {
633086f997eSAugustin Cavalier 		print_debugger_command_usage(argv[0]);
634086f997eSAugustin Cavalier 		return 0;
635086f997eSAugustin Cavalier 	}
636086f997eSAugustin Cavalier 
637086f997eSAugustin Cavalier 	uint64 addressValue;
638086f997eSAugustin Cavalier 	if (!evaluate_debug_expression(argv[argi++], &addressValue, false))
639086f997eSAugustin Cavalier 		return 0;
640086f997eSAugustin Cavalier 
641086f997eSAugustin Cavalier 	Team* team = NULL;
642086f997eSAugustin Cavalier 	if (argi < argc) {
643086f997eSAugustin Cavalier 		uint64 threadID;
644086f997eSAugustin Cavalier 		if (!evaluate_debug_expression(argv[argi++], &threadID, false))
645086f997eSAugustin Cavalier 			return 0;
646086f997eSAugustin Cavalier 
647086f997eSAugustin Cavalier 		Thread* thread = Thread::GetDebug(threadID);
648086f997eSAugustin Cavalier 		if (thread == NULL) {
649086f997eSAugustin Cavalier 			kprintf("Invalid thread/team ID \"%s\"\n", argv[argi - 1]);
650086f997eSAugustin Cavalier 			return 0;
651086f997eSAugustin Cavalier 		}
652086f997eSAugustin Cavalier 
653086f997eSAugustin Cavalier 		team = thread->team;
654086f997eSAugustin Cavalier 	}
655086f997eSAugustin Cavalier 
656086f997eSAugustin Cavalier 	if (reverseLookup) {
657086f997eSAugustin Cavalier 		phys_addr_t physicalAddress;
658086f997eSAugustin Cavalier 		if (pageLookup) {
659086f997eSAugustin Cavalier 			vm_page* page = (vm_page*)(addr_t)addressValue;
660086f997eSAugustin Cavalier 			physicalAddress = page->physical_page_number * B_PAGE_SIZE;
661086f997eSAugustin Cavalier 		} else {
662086f997eSAugustin Cavalier 			physicalAddress = (phys_addr_t)addressValue;
663086f997eSAugustin Cavalier 			physicalAddress -= physicalAddress % B_PAGE_SIZE;
664086f997eSAugustin Cavalier 		}
665086f997eSAugustin Cavalier 
666086f997eSAugustin Cavalier 		kprintf("    Team     Virtual Address      Area\n");
667086f997eSAugustin Cavalier 		kprintf("--------------------------------------\n");
668086f997eSAugustin Cavalier 
669086f997eSAugustin Cavalier 		struct Callback : VMTranslationMap::ReverseMappingInfoCallback {
670086f997eSAugustin Cavalier 			Callback()
671086f997eSAugustin Cavalier 				:
672086f997eSAugustin Cavalier 				fAddressSpace(NULL)
673086f997eSAugustin Cavalier 			{
674086f997eSAugustin Cavalier 			}
675086f997eSAugustin Cavalier 
676086f997eSAugustin Cavalier 			void SetAddressSpace(VMAddressSpace* addressSpace)
677086f997eSAugustin Cavalier 			{
678086f997eSAugustin Cavalier 				fAddressSpace = addressSpace;
679086f997eSAugustin Cavalier 			}
680086f997eSAugustin Cavalier 
681086f997eSAugustin Cavalier 			virtual bool HandleVirtualAddress(addr_t virtualAddress)
682086f997eSAugustin Cavalier 			{
683086f997eSAugustin Cavalier 				kprintf("%8" B_PRId32 "  %#18" B_PRIxADDR, fAddressSpace->ID(),
684086f997eSAugustin Cavalier 					virtualAddress);
685086f997eSAugustin Cavalier 				if (VMArea* area = fAddressSpace->LookupArea(virtualAddress))
686086f997eSAugustin Cavalier 					kprintf("  %8" B_PRId32 " %s\n", area->id, area->name);
687086f997eSAugustin Cavalier 				else
688086f997eSAugustin Cavalier 					kprintf("\n");
689086f997eSAugustin Cavalier 				return false;
690086f997eSAugustin Cavalier 			}
691086f997eSAugustin Cavalier 
692086f997eSAugustin Cavalier 		private:
693086f997eSAugustin Cavalier 			VMAddressSpace*	fAddressSpace;
694086f997eSAugustin Cavalier 		} callback;
695086f997eSAugustin Cavalier 
696086f997eSAugustin Cavalier 		if (team != NULL) {
697086f997eSAugustin Cavalier 			// team specified -- get its address space
698086f997eSAugustin Cavalier 			VMAddressSpace* addressSpace = team->address_space;
699086f997eSAugustin Cavalier 			if (addressSpace == NULL) {
700086f997eSAugustin Cavalier 				kprintf("Failed to get address space!\n");
701086f997eSAugustin Cavalier 				return 0;
702086f997eSAugustin Cavalier 			}
703086f997eSAugustin Cavalier 
704086f997eSAugustin Cavalier 			callback.SetAddressSpace(addressSpace);
705086f997eSAugustin Cavalier 			addressSpace->TranslationMap()->DebugGetReverseMappingInfo(
706086f997eSAugustin Cavalier 				physicalAddress, callback);
707086f997eSAugustin Cavalier 		} else {
708086f997eSAugustin Cavalier 			// no team specified -- iterate through all address spaces
709086f997eSAugustin Cavalier 			for (VMAddressSpace* addressSpace = VMAddressSpace::DebugFirst();
710086f997eSAugustin Cavalier 				addressSpace != NULL;
711086f997eSAugustin Cavalier 				addressSpace = VMAddressSpace::DebugNext(addressSpace)) {
712086f997eSAugustin Cavalier 				callback.SetAddressSpace(addressSpace);
713086f997eSAugustin Cavalier 				addressSpace->TranslationMap()->DebugGetReverseMappingInfo(
714086f997eSAugustin Cavalier 					physicalAddress, callback);
715086f997eSAugustin Cavalier 			}
716086f997eSAugustin Cavalier 		}
717086f997eSAugustin Cavalier 	} else {
718086f997eSAugustin Cavalier 		// get the address space
719086f997eSAugustin Cavalier 		addr_t virtualAddress = (addr_t)addressValue;
720086f997eSAugustin Cavalier 		virtualAddress -= virtualAddress % B_PAGE_SIZE;
721086f997eSAugustin Cavalier 		VMAddressSpace* addressSpace;
722086f997eSAugustin Cavalier 		if (IS_KERNEL_ADDRESS(virtualAddress)) {
723086f997eSAugustin Cavalier 			addressSpace = VMAddressSpace::Kernel();
724086f997eSAugustin Cavalier 		} else if (team != NULL) {
725086f997eSAugustin Cavalier 			addressSpace = team->address_space;
726086f997eSAugustin Cavalier 		} else {
727086f997eSAugustin Cavalier 			Thread* thread = debug_get_debugged_thread();
728086f997eSAugustin Cavalier 			if (thread == NULL || thread->team == NULL) {
729086f997eSAugustin Cavalier 				kprintf("Failed to get team!\n");
730086f997eSAugustin Cavalier 				return 0;
731086f997eSAugustin Cavalier 			}
732086f997eSAugustin Cavalier 
733086f997eSAugustin Cavalier 			addressSpace = thread->team->address_space;
734086f997eSAugustin Cavalier 		}
735086f997eSAugustin Cavalier 
736086f997eSAugustin Cavalier 		if (addressSpace == NULL) {
737086f997eSAugustin Cavalier 			kprintf("Failed to get address space!\n");
738086f997eSAugustin Cavalier 			return 0;
739086f997eSAugustin Cavalier 		}
740086f997eSAugustin Cavalier 
741086f997eSAugustin Cavalier 		// let the translation map implementation do the job
742086f997eSAugustin Cavalier 		addressSpace->TranslationMap()->DebugPrintMappingInfo(virtualAddress);
743086f997eSAugustin Cavalier 	}
744086f997eSAugustin Cavalier 
745086f997eSAugustin Cavalier 	return 0;
746086f997eSAugustin Cavalier }
747086f997eSAugustin Cavalier 
748086f997eSAugustin Cavalier 
749086f997eSAugustin Cavalier /*!	Copies a range of memory directly from/to a page that might not be mapped
750086f997eSAugustin Cavalier 	at the moment.
751086f997eSAugustin Cavalier 
752086f997eSAugustin Cavalier 	For \a unsafeMemory the current mapping (if any is ignored). The function
753086f997eSAugustin Cavalier 	walks through the respective area's cache chain to find the physical page
754086f997eSAugustin Cavalier 	and copies from/to it directly.
755086f997eSAugustin Cavalier 	The memory range starting at \a unsafeMemory with a length of \a size bytes
756086f997eSAugustin Cavalier 	must not cross a page boundary.
757086f997eSAugustin Cavalier 
758086f997eSAugustin Cavalier 	\param teamID The team ID identifying the address space \a unsafeMemory is
759086f997eSAugustin Cavalier 		to be interpreted in. Ignored, if \a unsafeMemory is a kernel address
760086f997eSAugustin Cavalier 		(the kernel address space is assumed in this case). If \c B_CURRENT_TEAM
761086f997eSAugustin Cavalier 		is passed, the address space of the thread returned by
762086f997eSAugustin Cavalier 		debug_get_debugged_thread() is used.
763086f997eSAugustin Cavalier 	\param unsafeMemory The start of the unsafe memory range to be copied
764086f997eSAugustin Cavalier 		from/to.
765086f997eSAugustin Cavalier 	\param buffer A safely accessible kernel buffer to be copied from/to.
766086f997eSAugustin Cavalier 	\param size The number of bytes to be copied.
767086f997eSAugustin Cavalier 	\param copyToUnsafe If \c true, memory is copied from \a buffer to
768086f997eSAugustin Cavalier 		\a unsafeMemory, the other way around otherwise.
769086f997eSAugustin Cavalier */
770086f997eSAugustin Cavalier status_t
vm_debug_copy_page_memory(team_id teamID,void * unsafeMemory,void * buffer,size_t size,bool copyToUnsafe)771086f997eSAugustin Cavalier vm_debug_copy_page_memory(team_id teamID, void* unsafeMemory, void* buffer,
772086f997eSAugustin Cavalier 	size_t size, bool copyToUnsafe)
773086f997eSAugustin Cavalier {
774086f997eSAugustin Cavalier 	if (size > B_PAGE_SIZE || ROUNDDOWN((addr_t)unsafeMemory, B_PAGE_SIZE)
775086f997eSAugustin Cavalier 			!= ROUNDDOWN((addr_t)unsafeMemory + size - 1, B_PAGE_SIZE)) {
776086f997eSAugustin Cavalier 		return B_BAD_VALUE;
777086f997eSAugustin Cavalier 	}
778086f997eSAugustin Cavalier 
779086f997eSAugustin Cavalier 	// get the address space for the debugged thread
780086f997eSAugustin Cavalier 	VMAddressSpace* addressSpace;
781086f997eSAugustin Cavalier 	if (IS_KERNEL_ADDRESS(unsafeMemory)) {
782086f997eSAugustin Cavalier 		addressSpace = VMAddressSpace::Kernel();
783086f997eSAugustin Cavalier 	} else if (teamID == B_CURRENT_TEAM) {
784086f997eSAugustin Cavalier 		Thread* thread = debug_get_debugged_thread();
785086f997eSAugustin Cavalier 		if (thread == NULL || thread->team == NULL)
786086f997eSAugustin Cavalier 			return B_BAD_ADDRESS;
787086f997eSAugustin Cavalier 
788086f997eSAugustin Cavalier 		addressSpace = thread->team->address_space;
789086f997eSAugustin Cavalier 	} else
790086f997eSAugustin Cavalier 		addressSpace = VMAddressSpace::DebugGet(teamID);
791086f997eSAugustin Cavalier 
792086f997eSAugustin Cavalier 	if (addressSpace == NULL)
793086f997eSAugustin Cavalier 		return B_BAD_ADDRESS;
794086f997eSAugustin Cavalier 
795086f997eSAugustin Cavalier 	// get the area
796086f997eSAugustin Cavalier 	VMArea* area = addressSpace->LookupArea((addr_t)unsafeMemory);
797086f997eSAugustin Cavalier 	if (area == NULL)
798086f997eSAugustin Cavalier 		return B_BAD_ADDRESS;
799086f997eSAugustin Cavalier 
800086f997eSAugustin Cavalier 	// search the page
801086f997eSAugustin Cavalier 	off_t cacheOffset = (addr_t)unsafeMemory - area->Base()
802086f997eSAugustin Cavalier 		+ area->cache_offset;
803086f997eSAugustin Cavalier 	VMCache* cache = area->cache;
804086f997eSAugustin Cavalier 	vm_page* page = NULL;
805086f997eSAugustin Cavalier 	while (cache != NULL) {
806086f997eSAugustin Cavalier 		page = cache->DebugLookupPage(cacheOffset);
807086f997eSAugustin Cavalier 		if (page != NULL)
808086f997eSAugustin Cavalier 			break;
809086f997eSAugustin Cavalier 
810086f997eSAugustin Cavalier 		// Page not found in this cache -- if it is paged out, we must not try
811086f997eSAugustin Cavalier 		// to get it from lower caches.
812086f997eSAugustin Cavalier 		if (cache->DebugHasPage(cacheOffset))
813086f997eSAugustin Cavalier 			break;
814086f997eSAugustin Cavalier 
815086f997eSAugustin Cavalier 		cache = cache->source;
816086f997eSAugustin Cavalier 	}
817086f997eSAugustin Cavalier 
818086f997eSAugustin Cavalier 	if (page == NULL)
819086f997eSAugustin Cavalier 		return B_UNSUPPORTED;
820086f997eSAugustin Cavalier 
821086f997eSAugustin Cavalier 	// copy from/to physical memory
822086f997eSAugustin Cavalier 	phys_addr_t physicalAddress = page->physical_page_number * B_PAGE_SIZE
823086f997eSAugustin Cavalier 		+ (addr_t)unsafeMemory % B_PAGE_SIZE;
824086f997eSAugustin Cavalier 
825086f997eSAugustin Cavalier 	if (copyToUnsafe) {
826086f997eSAugustin Cavalier 		if (page->Cache() != area->cache)
827086f997eSAugustin Cavalier 			return B_UNSUPPORTED;
828086f997eSAugustin Cavalier 
829086f997eSAugustin Cavalier 		return vm_memcpy_to_physical(physicalAddress, buffer, size, false);
830086f997eSAugustin Cavalier 	}
831086f997eSAugustin Cavalier 
832086f997eSAugustin Cavalier 	return vm_memcpy_from_physical(buffer, physicalAddress, size, false);
833086f997eSAugustin Cavalier }
834086f997eSAugustin Cavalier 
835086f997eSAugustin Cavalier 
836086f997eSAugustin Cavalier void
vm_debug_init()837086f997eSAugustin Cavalier vm_debug_init()
838086f997eSAugustin Cavalier {
839086f997eSAugustin Cavalier #if DEBUG_CACHE_LIST
840086f997eSAugustin Cavalier 	if (vm_page_num_free_pages() >= 200 * 1024 * 1024 / B_PAGE_SIZE) {
841086f997eSAugustin Cavalier 		virtual_address_restrictions virtualRestrictions = {};
842086f997eSAugustin Cavalier 		virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
843086f997eSAugustin Cavalier 		physical_address_restrictions physicalRestrictions = {};
844086f997eSAugustin Cavalier 		create_area_etc(VMAddressSpace::KernelID(), "cache info table",
845086f997eSAugustin Cavalier 			ROUNDUP(kCacheInfoTableCount * sizeof(cache_info), B_PAGE_SIZE),
846086f997eSAugustin Cavalier 			B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
847086f997eSAugustin Cavalier 			CREATE_AREA_DONT_WAIT, 0, &virtualRestrictions,
848086f997eSAugustin Cavalier 			&physicalRestrictions, (void**)&sCacheInfoTable);
849086f997eSAugustin Cavalier 	}
850086f997eSAugustin Cavalier #endif	// DEBUG_CACHE_LIST
851086f997eSAugustin Cavalier 
852086f997eSAugustin Cavalier 	// add some debugger commands
853086f997eSAugustin Cavalier 	add_debugger_command("areas", &dump_area_list, "Dump a list of all areas");
854086f997eSAugustin Cavalier 	add_debugger_command("area", &dump_area,
855086f997eSAugustin Cavalier 		"Dump info about a particular area");
856086f997eSAugustin Cavalier 	add_debugger_command("cache", &dump_cache, "Dump VMCache");
857086f997eSAugustin Cavalier 	add_debugger_command("cache_tree", &dump_cache_tree, "Dump VMCache tree");
858086f997eSAugustin Cavalier #if DEBUG_CACHE_LIST
859086f997eSAugustin Cavalier 	if (sCacheInfoTable != NULL) {
860086f997eSAugustin Cavalier 		add_debugger_command_etc("caches", &dump_caches,
861086f997eSAugustin Cavalier 			"List all VMCache trees",
862086f997eSAugustin Cavalier 			"[ \"-c\" ]\n"
863086f997eSAugustin Cavalier 			"All cache trees are listed sorted in decreasing order by number "
864086f997eSAugustin Cavalier 				"of\n"
865086f997eSAugustin Cavalier 			"used pages or, if \"-c\" is specified, by size of committed "
866086f997eSAugustin Cavalier 				"memory.\n",
867086f997eSAugustin Cavalier 			0);
868086f997eSAugustin Cavalier 	}
869086f997eSAugustin Cavalier #endif
870086f997eSAugustin Cavalier 	add_debugger_command("avail", &dump_available_memory,
871086f997eSAugustin Cavalier 		"Dump available memory");
872086f997eSAugustin Cavalier 	add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)");
873086f997eSAugustin Cavalier 	add_debugger_command("dw", &display_mem, "dump memory words (32-bit)");
874086f997eSAugustin Cavalier 	add_debugger_command("ds", &display_mem, "dump memory shorts (16-bit)");
875086f997eSAugustin Cavalier 	add_debugger_command("db", &display_mem, "dump memory bytes (8-bit)");
876086f997eSAugustin Cavalier 	add_debugger_command("string", &display_mem, "dump strings");
877086f997eSAugustin Cavalier 
878086f997eSAugustin Cavalier 	add_debugger_command_etc("mapping", &dump_mapping_info,
879086f997eSAugustin Cavalier 		"Print address mapping information",
880086f997eSAugustin Cavalier 		"[ \"-r\" | \"-p\" ] <address> [ <thread ID> ]\n"
881086f997eSAugustin Cavalier 		"Prints low-level page mapping information for a given address. If\n"
882086f997eSAugustin Cavalier 		"neither \"-r\" nor \"-p\" are specified, <address> is a virtual\n"
883086f997eSAugustin Cavalier 		"address that is looked up in the translation map of the current\n"
884086f997eSAugustin Cavalier 		"team, respectively the team specified by thread ID <thread ID>. If\n"
885086f997eSAugustin Cavalier 		"\"-r\" is specified, <address> is a physical address that is\n"
886086f997eSAugustin Cavalier 		"searched in the translation map of all teams, respectively the team\n"
887086f997eSAugustin Cavalier 		"specified by thread ID <thread ID>. If \"-p\" is specified,\n"
888086f997eSAugustin Cavalier 		"<address> is the address of a vm_page structure. The behavior is\n"
889086f997eSAugustin Cavalier 		"equivalent to specifying \"-r\" with the physical address of that\n"
890086f997eSAugustin Cavalier 		"page.\n",
891086f997eSAugustin Cavalier 		0);
892086f997eSAugustin Cavalier }
893