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