1/*
2 * Copyright 2001-2009, Axel D��rfler, axeld@pinc-software.de.
3 * Some code is based on work previously done by Marcus Overhagen.
4 *
5 * This file may be used under the terms of the MIT License.
6 */
7
8
9#include "Debug.h"
10#include "BlockAllocator.h"
11#include "BPlusTree.h"
12#include "Inode.h"
13#include "Journal.h"
14
15
16char*
17get_tupel(uint32 id)
18{
19	static unsigned char tupel[5];
20
21	tupel[0] = 0xff & (id >> 24);
22	tupel[1] = 0xff & (id >> 16);
23	tupel[2] = 0xff & (id >> 8);
24	tupel[3] = 0xff & (id);
25	tupel[4] = 0;
26	for (int16 i = 0;i < 4;i++) {
27		if (tupel[i] < ' ' || tupel[i] > 128)
28			tupel[i] = '.';
29	}
30
31	return (char*)tupel;
32}
33
34
35void
36dump_block_run(const char* prefix, const block_run& run)
37{
38	kprintf("%s(%d, %d, %d)\n", prefix, (int)run.allocation_group, run.start,
39		run.length);
40}
41
42
43void
44dump_super_block(const disk_super_block* superBlock)
45{
46	kprintf("disk_super_block:\n");
47	kprintf("  name           = %s\n", superBlock->name);
48	kprintf("  magic1         = %#08x (%s) %s\n", (int)superBlock->Magic1(),
49		get_tupel(superBlock->magic1),
50		(superBlock->magic1 == SUPER_BLOCK_MAGIC1 ? "valid" : "INVALID"));
51	kprintf("  fs_byte_order  = %#08x (%s)\n", (int)superBlock->fs_byte_order,
52		get_tupel(superBlock->fs_byte_order));
53	kprintf("  block_size     = %u\n", (unsigned)superBlock->BlockSize());
54	kprintf("  block_shift    = %u\n", (unsigned)superBlock->BlockShift());
55	kprintf("  num_blocks     = %" B_PRIdOFF "\n", superBlock->NumBlocks());
56	kprintf("  used_blocks    = %" B_PRIdOFF "\n", superBlock->UsedBlocks());
57	kprintf("  inode_size     = %u\n", (unsigned)superBlock->InodeSize());
58	kprintf("  magic2         = %#08x (%s) %s\n", (int)superBlock->Magic2(),
59		get_tupel(superBlock->magic2),
60		(superBlock->magic2 == (int)SUPER_BLOCK_MAGIC2 ? "valid" : "INVALID"));
61	kprintf("  blocks_per_ag  = %u\n",
62		(unsigned)superBlock->BlocksPerAllocationGroup());
63	kprintf("  ag_shift       = %u (%ld bytes)\n",
64		(unsigned)superBlock->AllocationGroupShift(),
65		1L << superBlock->AllocationGroupShift());
66	kprintf("  num_ags        = %u\n", (unsigned)superBlock->AllocationGroups());
67	kprintf("  flags          = %#08x (%s)\n", (int)superBlock->Flags(),
68		get_tupel(superBlock->Flags()));
69	dump_block_run("  log_blocks     = ", superBlock->log_blocks);
70	kprintf("  log_start      = %" B_PRIdOFF "\n", superBlock->LogStart());
71	kprintf("  log_end        = %" B_PRIdOFF "\n", superBlock->LogEnd());
72	kprintf("  magic3         = %#08x (%s) %s\n", (int)superBlock->Magic3(),
73		get_tupel(superBlock->magic3),
74		(superBlock->magic3 == SUPER_BLOCK_MAGIC3 ? "valid" : "INVALID"));
75	dump_block_run("  root_dir       = ", superBlock->root_dir);
76	dump_block_run("  indices        = ", superBlock->indices);
77}
78
79
80void
81dump_data_stream(const data_stream* stream)
82{
83	kprintf("data_stream:\n");
84	for (int i = 0; i < NUM_DIRECT_BLOCKS; i++) {
85		if (!stream->direct[i].IsZero()) {
86			kprintf("  direct[%02d]                = ", i);
87			dump_block_run("", stream->direct[i]);
88		}
89	}
90	kprintf("  max_direct_range          = %" B_PRIdOFF "\n",
91		stream->MaxDirectRange());
92
93	if (!stream->indirect.IsZero())
94		dump_block_run("  indirect                  = ", stream->indirect);
95
96	kprintf("  max_indirect_range        = %" B_PRIdOFF "\n",
97		stream->MaxIndirectRange());
98
99	if (!stream->double_indirect.IsZero()) {
100		dump_block_run("  double_indirect           = ",
101			stream->double_indirect);
102	}
103
104	kprintf("  max_double_indirect_range = %" B_PRIdOFF "\n",
105		stream->MaxDoubleIndirectRange());
106	kprintf("  size                      = %" B_PRIdOFF "\n", stream->Size());
107}
108
109
110void
111dump_inode(const bfs_inode* inode)
112{
113	kprintf("inode:\n");
114	kprintf("  magic1             = %08x (%s) %s\n", (int)inode->Magic1(),
115		get_tupel(inode->magic1),
116		(inode->magic1 == INODE_MAGIC1 ? "valid" : "INVALID"));
117	dump_block_run(	"  inode_num          = ", inode->inode_num);
118	kprintf("  uid                = %u\n", (unsigned)inode->UserID());
119	kprintf("  gid                = %u\n", (unsigned)inode->GroupID());
120	kprintf("  mode               = %08x\n", (int)inode->Mode());
121	kprintf("  flags              = %08x\n", (int)inode->Flags());
122	kprintf("  create_time        = %" B_PRIx64 " (%" B_PRIdTIME ".%u)\n",
123		inode->CreateTime(), bfs_inode::ToSecs(inode->CreateTime()),
124		(unsigned)bfs_inode::ToNsecs(inode->CreateTime()));
125	kprintf("  last_modified_time = %" B_PRIx64 " (%" B_PRIdTIME ".%u)\n",
126		inode->LastModifiedTime(), bfs_inode::ToSecs(inode->LastModifiedTime()),
127		(unsigned)bfs_inode::ToNsecs(inode->LastModifiedTime()));
128	kprintf("  status_change_time = %" B_PRIx64 " (%" B_PRIdTIME ".%u)\n",
129		inode->StatusChangeTime(), bfs_inode::ToSecs(inode->StatusChangeTime()),
130		(unsigned)bfs_inode::ToNsecs(inode->StatusChangeTime()));
131	dump_block_run(	"  parent             = ", inode->parent);
132	dump_block_run(	"  attributes         = ", inode->attributes);
133	kprintf("  type               = %u\n", (unsigned)inode->Type());
134	kprintf("  inode_size         = %u\n", (unsigned)inode->InodeSize());
135	kprintf("  short_symlink      = %s\n",
136		S_ISLNK(inode->Mode()) && (inode->Flags() & INODE_LONG_SYMLINK) == 0
137			? inode->short_symlink : "-");
138	dump_data_stream(&(inode->data));
139	kprintf("  --\n  pad[0]             = %08x\n", (int)inode->pad[0]);
140	kprintf("  pad[1]             = %08x\n", (int)inode->pad[1]);
141}
142
143
144void
145dump_bplustree_header(const bplustree_header* header)
146{
147	kprintf("bplustree_header:\n");
148	kprintf("  magic                = %#08x (%s) %s\n", (int)header->Magic(),
149		get_tupel(header->magic),
150		(header->magic == BPLUSTREE_MAGIC ? "valid" : "INVALID"));
151	kprintf("  node_size            = %u\n", (unsigned)header->NodeSize());
152	kprintf("  max_number_of_levels = %u\n",
153		(unsigned)header->MaxNumberOfLevels());
154	kprintf("  data_type            = %u\n", (unsigned)header->DataType());
155	kprintf("  root_node_pointer    = %" B_PRIdOFF "\n", header->RootNode());
156	kprintf("  free_node_pointer    = %" B_PRIdOFF "\n", header->FreeNode());
157	kprintf("  maximum_size         = %" B_PRIdOFF "\n", header->MaximumSize());
158}
159
160
161#define DUMPED_BLOCK_SIZE 16
162
163void
164dump_block(const char* buffer,int size)
165{
166	for (int i = 0; i < size;) {
167		int start = i;
168
169		for (; i < start + DUMPED_BLOCK_SIZE; i++) {
170			if (!(i % 4))
171				kprintf(" ");
172
173			if (i >= size)
174				kprintf("  ");
175			else
176				kprintf("%02x", *(unsigned char *)(buffer + i));
177		}
178		kprintf("  ");
179
180		for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) {
181			if (i < size) {
182				char c = *(buffer + i);
183
184				if (c < 30)
185					kprintf(".");
186				else
187					kprintf("%c", c);
188			} else
189				break;
190		}
191		kprintf("\n");
192	}
193}
194
195
196void
197dump_bplustree_node(const bplustree_node* node, const bplustree_header* header,
198	Volume* volume)
199{
200	kprintf("bplustree_node:\n");
201	kprintf("  left_link      = %" B_PRId64 "\n", node->left_link);
202	kprintf("  right_link     = %" B_PRId64 "\n", node->right_link);
203	kprintf("  overflow_link  = %" B_PRId64 "\n", node->overflow_link);
204	kprintf("  all_key_count  = %u\n", node->all_key_count);
205	kprintf("  all_key_length = %u\n", node->all_key_length);
206
207	if (header == NULL)
208		return;
209
210	if (node->all_key_count > node->all_key_length
211		|| uint32(node->all_key_count * 10) > (uint32)header->node_size
212		|| node->all_key_count == 0) {
213		kprintf("\n");
214		dump_block((char *)node, header->node_size/*, sizeof(off_t)*/);
215		return;
216	}
217
218	kprintf("\n");
219	for (int32 i = 0;i < node->all_key_count;i++) {
220		uint16 length;
221		char buffer[256], *key = (char *)node->KeyAt(i, &length);
222		if (length > 255 || length == 0) {
223			kprintf("  %2d. Invalid length (%u)!!\n", (int)i, length);
224			dump_block((char *)node, header->node_size/*, sizeof(off_t)*/);
225			break;
226		}
227		memcpy(buffer, key, length);
228		buffer[length] = '\0';
229
230		Unaligned<off_t>* value = node->Values() + i;
231		if ((addr_t)value < (addr_t)node
232			|| (addr_t)value > (addr_t)node + header->node_size)
233			kprintf("  %2d. Invalid Offset!!\n", (int)i);
234		else {
235			kprintf("  %2d. ", (int)i);
236			if (header->data_type == BPLUSTREE_STRING_TYPE)
237				kprintf("\"%s\"", buffer);
238			else if (header->data_type == BPLUSTREE_INT32_TYPE) {
239				kprintf("int32 = %d (0x%x)", (int)*(int32 *)&buffer,
240					(int)*(int32 *)&buffer);
241			} else if (header->data_type == BPLUSTREE_UINT32_TYPE) {
242				kprintf("uint32 = %u (0x%x)", (unsigned)*(uint32 *)&buffer,
243					(unsigned)*(uint32 *)&buffer);
244			} else if (header->data_type == BPLUSTREE_INT64_TYPE) {
245				kprintf("int64 = %" B_PRId64 " (%#" B_PRIx64 ")",
246					*(int64 *)&buffer, *(int64 *)&buffer);
247			} else
248				kprintf("???");
249
250			off_t offset = *value & 0x3fffffffffffffffLL;
251			kprintf(" (%d bytes) -> %" B_PRIdOFF, length, offset);
252			if (volume != NULL) {
253				block_run run = volume->ToBlockRun(offset);
254				kprintf(" (%d, %d)", (int)run.allocation_group, run.start);
255			}
256			if (bplustree_node::LinkType(*value)
257					== BPLUSTREE_DUPLICATE_FRAGMENT) {
258				kprintf(" (duplicate fragment %" B_PRIdOFF ")\n",
259					*value & 0x3ff);
260			} else if (bplustree_node::LinkType(*value)
261					== BPLUSTREE_DUPLICATE_NODE) {
262				kprintf(" (duplicate node)\n");
263			} else
264				kprintf("\n");
265		}
266	}
267}
268
269
270//	#pragma mark - debugger commands
271
272
273#ifdef BFS_DEBUGGER_COMMANDS
274
275
276static int
277dump_inode(int argc, char** argv)
278{
279	bool block = false;
280	if (argc >= 3 && !strcmp(argv[1], "-b"))
281		block = true;
282
283	if (argc != 2 + (block ? 1 : 0) || !strcmp(argv[1], "--help")) {
284		kprintf("usage: bfsinode [-b] <ptr-to-inode>\n"
285			"  -b the address is regarded as pointer to a block instead of one "
286			"to an inode.\n");
287		return 0;
288	}
289
290	addr_t address = parse_expression(argv[argc - 1]);
291	bfs_inode* node;
292	if (block)
293		node = (bfs_inode*)address;
294	else {
295		Inode* inode = (Inode*)address;
296
297		kprintf("INODE %p\n", inode);
298		kprintf("  rw lock:           %p\n", &inode->Lock());
299		kprintf("  tree:              %p\n", inode->Tree());
300		kprintf("  file cache:        %p\n", inode->FileCache());
301		kprintf("  file map:          %p\n", inode->Map());
302		kprintf("  old size:          %" B_PRIdOFF "\n", inode->OldSize());
303		kprintf("  old last modified: %" B_PRIdOFF "\n",
304			inode->OldLastModified());
305
306		node = &inode->Node();
307	}
308
309	dump_inode(node);
310	return 0;
311}
312
313
314static int
315dump_volume(int argc, char** argv)
316{
317	if (argc < 2 || !strcmp(argv[1], "--help")) {
318		kprintf("usage: bfs <ptr-to-volume> [<block-run>]\n"
319			"Dumps a BFS volume - <block-run> is given, it is converted to a "
320			"block offset instead (and vice versa).\n");
321		return 0;
322	}
323
324	Volume* volume = (Volume*)parse_expression(argv[1]);
325
326	if (argc > 2) {
327		// convert block_runs/offsets
328		for (int i = 2; i < argc; i++) {
329			char* arg = argv[i];
330			if (strchr(arg, '.') != NULL || strchr(arg, ',') != NULL) {
331				// block_run to offset
332				block_run run;
333				run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(
334					strtoul(arg, &arg, 0));
335				run.start = HOST_ENDIAN_TO_BFS_INT16(strtoul(arg + 1, NULL, 0));
336				run.length = 0;
337
338				kprintf("%" B_PRId32 ".%u -> block %" B_PRIdOFF ", bitmap block"
339					" %" B_PRId32 "\n", run.AllocationGroup(), run.Start(),
340					volume->ToBlock(run),
341					volume->SuperBlock().BlocksPerAllocationGroup()
342						* run.AllocationGroup() + 1);
343			} else {
344				// offset to block_run
345				off_t offset = parse_expression(arg);
346				block_run run = volume->ToBlockRun(offset);
347
348				kprintf("block %" B_PRIdOFF " -> %" B_PRId32 ".%u, bitmap block"
349					" %" B_PRId32 "\n", offset, run.AllocationGroup(),
350					run.Start(), volume->SuperBlock().BlocksPerAllocationGroup()
351						* run.AllocationGroup() + 1);
352			}
353		}
354		return 0;
355	}
356
357	kprintf("id:           %" B_PRId32 "\n", volume->ID());
358	kprintf("block cache:  %p\n", volume->BlockCache());
359	kprintf("journal:      %p\n", volume->GetJournal(0));
360	kprintf("allocator:    %p\n", &volume->Allocator());
361	kprintf("root node:    %p\n", volume->RootNode());
362	kprintf("indices node: %p\n\n", volume->IndicesNode());
363
364	dump_super_block(&volume->SuperBlock());
365
366	set_debug_variable("_cache", (addr_t)volume->BlockCache());
367	set_debug_variable("_root", (addr_t)volume->RootNode());
368	set_debug_variable("_indices", (addr_t)volume->IndicesNode());
369
370	return 0;
371}
372
373
374static int
375dump_block_run_array(int argc, char** argv)
376{
377	if (argc < 2 || !strcmp(argv[1], "--help")) {
378		kprintf("usage: %s <ptr-to-array> [number-of-runs] [block-size] "
379			"[start-offset] [search-offset]\n", argv[0]);
380		return 0;
381	}
382
383	const block_run* runs = (const block_run*)parse_expression(argv[1]);
384	uint32 count = 16;
385	if (argc > 2)
386		count = parse_expression(argv[2]);
387
388	uint32 blockSize = 0;
389	if (argc > 3)
390		blockSize = parse_expression(argv[3]);
391
392	off_t offset = 0;
393	if (argc > 4)
394		offset = parse_expression(argv[4]);
395
396	off_t searchOffset = 0;
397	if (argc > 5)
398		searchOffset = parse_expression(argv[5]);
399
400	for (uint32 i = 0; i < count; i++) {
401		if (blockSize != 0)
402			dprintf("[%3" B_PRIu32 "]  %10" B_PRIdOFF "  ", i, offset);
403		else
404			dprintf("[%3" B_PRIu32 "]  ", i);
405
406		uint32 size = runs[i].Length() * blockSize;
407		if (searchOffset != 0 && searchOffset >= offset
408			&& searchOffset < offset + size)
409			dprintf("*  ");
410
411		dump_block_run("", runs[i]);
412
413		offset += size;
414	}
415
416	return 0;
417}
418
419
420static int
421dump_bplustree_node(int argc, char** argv)
422{
423	if (argc < 2 || argc > 4 || !strcmp(argv[1], "--help")) {
424		kprintf("usage: %s <ptr-to-node> [ptr-to-header] [ptr-to-volume]\n",
425			argv[0]);
426		return 0;
427	}
428
429	bplustree_node* node = (bplustree_node*)parse_expression(argv[1]);
430	bplustree_header* header = NULL;
431	Volume* volume = NULL;
432
433	if (argc > 2)
434		header = (bplustree_header*)parse_expression(argv[2]);
435	if (argc > 3)
436		volume = (Volume*)parse_expression(argv[3]);
437
438	dump_bplustree_node(node, header, volume);
439
440	return 0;
441}
442
443
444static int
445dump_bplustree_header(int argc, char** argv)
446{
447	if (argc != 2 || !strcmp(argv[1], "--help")) {
448		kprintf("usage: %s <ptr-to-header>\n", argv[0]);
449		return 0;
450	}
451
452	bplustree_header* header = (bplustree_header*)parse_expression(argv[1]);
453	dump_bplustree_header(header);
454
455	return 0;
456}
457
458
459void
460remove_debugger_commands()
461{
462	remove_debugger_command("bfs_inode", dump_inode);
463	remove_debugger_command("bfs_allocator", dump_block_allocator);
464#if BFS_TRACING
465	remove_debugger_command("bfs_allocator_blocks",
466		dump_block_allocator_blocks);
467#endif
468	remove_debugger_command("bfs_journal", dump_journal);
469	remove_debugger_command("bfs_btree_header", dump_bplustree_header);
470	remove_debugger_command("bfs_btree_node", dump_bplustree_node);
471	remove_debugger_command("bfs", dump_volume);
472	remove_debugger_command("bfs_block_runs", dump_block_run_array);
473}
474
475
476void
477add_debugger_commands()
478{
479	add_debugger_command("bfs_inode", dump_inode, "dump an Inode object");
480	add_debugger_command("bfs_allocator", dump_block_allocator,
481		"dump a BFS block allocator");
482#if BFS_TRACING
483	add_debugger_command("bfs_allocator_blocks", dump_block_allocator_blocks,
484		"dump a BFS block allocator actions that affected a certain block");
485#endif
486	add_debugger_command("bfs_journal", dump_journal,
487		"dump the journal log entries");
488	add_debugger_command("bfs_btree_header", dump_bplustree_header,
489		"dump a BFS B+tree header");
490	add_debugger_command("bfs_btree_node", dump_bplustree_node,
491		"dump a BFS B+tree node");
492	add_debugger_command("bfs", dump_volume, "dump a BFS volume");
493	add_debugger_command("bfs_block_runs", dump_block_run_array,
494		"dump a block run array");
495}
496
497
498#endif	// BFS_DEBUGGER_COMMANDS
499