xref: /haiku/src/add-ons/kernel/file_systems/bfs/Debug.cpp (revision abb72bec4b50661dc326a98824ca0a26500805f7)
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 
16 char*
17 get_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 
35 void
36 dump_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 
43 void
44 dump_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 
80 void
81 dump_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 
110 void
111 dump_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::ToUsecs(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::ToUsecs(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::ToUsecs(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 
144 void
145 dump_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 
163 void
164 dump_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 
196 void
197 dump_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 		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 
276 static int
277 dump_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:          %Ld\n", inode->OldSize());
303 		kprintf("  old last modified: %Ld\n", inode->OldLastModified());
304 
305 		node = &inode->Node();
306 	}
307 
308 	dump_inode(node);
309 	return 0;
310 }
311 
312 
313 static int
314 dump_volume(int argc, char** argv)
315 {
316 	if (argc < 2 || !strcmp(argv[1], "--help")) {
317 		kprintf("usage: bfs <ptr-to-volume> [<block-run>]\n"
318 			"Dumps a BFS volume - <block-run> is given, it is converted to a "
319 			"block offset instead (and vice versa).\n");
320 		return 0;
321 	}
322 
323 	Volume* volume = (Volume*)parse_expression(argv[1]);
324 
325 	if (argc > 2) {
326 		// convert block_runs/offsets
327 		for (int i = 2; i < argc; i++) {
328 			char* arg = argv[i];
329 			if (strchr(arg, '.') != NULL || strchr(arg, ',') != NULL) {
330 				// block_run to offset
331 				block_run run;
332 				run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(
333 					strtoul(arg, &arg, 0));
334 				run.start = HOST_ENDIAN_TO_BFS_INT16(strtoul(arg + 1, NULL, 0));
335 				run.length = 0;
336 
337 				kprintf("%ld.%u -> block %Ld, bitmap block %ld\n",
338 					run.AllocationGroup(), run.Start(), volume->ToBlock(run),
339 					volume->SuperBlock().BlocksPerAllocationGroup()
340 						* run.AllocationGroup() + 1);
341 			} else {
342 				// offset to block_run
343 				off_t offset = parse_expression(arg);
344 				block_run run = volume->ToBlockRun(offset);
345 
346 				kprintf("block %Ld -> %ld.%u, bitmap block %ld\n", offset,
347 					run.AllocationGroup(), run.Start(),
348 					volume->SuperBlock().BlocksPerAllocationGroup()
349 						* run.AllocationGroup() + 1);
350 			}
351 		}
352 		return 0;
353 	}
354 
355 	kprintf("id:           %ld\n", volume->ID());
356 	kprintf("block cache:  %p\n", volume->BlockCache());
357 	kprintf("journal:      %p\n", volume->GetJournal(0));
358 	kprintf("allocator:    %p\n", &volume->Allocator());
359 	kprintf("root node:    %p\n", volume->RootNode());
360 	kprintf("indices node: %p\n\n", volume->IndicesNode());
361 
362 	dump_super_block(&volume->SuperBlock());
363 
364 	set_debug_variable("_cache", (addr_t)volume->BlockCache());
365 	set_debug_variable("_root", (addr_t)volume->RootNode());
366 	set_debug_variable("_indices", (addr_t)volume->IndicesNode());
367 
368 	return 0;
369 }
370 
371 
372 static int
373 dump_block_run_array(int argc, char** argv)
374 {
375 	if (argc < 2 || !strcmp(argv[1], "--help")) {
376 		kprintf("usage: %s <ptr-to-array> [number-of-runs]\n", argv[0]);
377 		return 0;
378 	}
379 
380 	const block_run* runs = (const block_run*)parse_expression(argv[1]);
381 	uint32 count = 16;
382 	if (argc > 2)
383 		count = parse_expression(argv[2]);
384 
385 	for (uint32 i = 0; i < count; i++) {
386 		dprintf("[%3lu]  ", i);
387 		dump_block_run("", runs[i]);
388 	}
389 
390 	return 0;
391 }
392 
393 
394 static int
395 dump_bplustree_node(int argc, char** argv)
396 {
397 	if (argc < 2 || argc > 4 || !strcmp(argv[1], "--help")) {
398 		kprintf("usage: %s <ptr-to-node> [ptr-to-header] [ptr-to-volume]\n",
399 			argv[0]);
400 		return 0;
401 	}
402 
403 	bplustree_node* node = (bplustree_node*)parse_expression(argv[1]);
404 	bplustree_header* header = NULL;
405 	Volume* volume = NULL;
406 
407 	if (argc > 2)
408 		header = (bplustree_header*)parse_expression(argv[2]);
409 	if (argc > 3)
410 		volume = (Volume*)parse_expression(argv[3]);
411 
412 	dump_bplustree_node(node, header, volume);
413 
414 	return 0;
415 }
416 
417 
418 static int
419 dump_bplustree_header(int argc, char** argv)
420 {
421 	if (argc != 2 || !strcmp(argv[1], "--help")) {
422 		kprintf("usage: %s <ptr-to-header>\n", argv[0]);
423 		return 0;
424 	}
425 
426 	bplustree_header* header = (bplustree_header*)parse_expression(argv[1]);
427 	dump_bplustree_header(header);
428 
429 	return 0;
430 }
431 
432 
433 void
434 remove_debugger_commands()
435 {
436 	remove_debugger_command("bfs_inode", dump_inode);
437 	remove_debugger_command("bfs_allocator", dump_block_allocator);
438 #if BFS_TRACING
439 	remove_debugger_command("bfs_allocator_blocks",
440 		dump_block_allocator_blocks);
441 #endif
442 	remove_debugger_command("bfs_journal", dump_journal);
443 	remove_debugger_command("bfs_btree_header", dump_bplustree_header);
444 	remove_debugger_command("bfs_btree_node", dump_bplustree_node);
445 	remove_debugger_command("bfs", dump_volume);
446 	remove_debugger_command("bfs_block_runs", dump_block_run_array);
447 }
448 
449 
450 void
451 add_debugger_commands()
452 {
453 	add_debugger_command("bfs_inode", dump_inode, "dump an Inode object");
454 	add_debugger_command("bfs_allocator", dump_block_allocator,
455 		"dump a BFS block allocator");
456 #if BFS_TRACING
457 	add_debugger_command("bfs_allocator_blocks", dump_block_allocator_blocks,
458 		"dump a BFS block allocator actions that affected a certain block");
459 #endif
460 	add_debugger_command("bfs_journal", dump_journal,
461 		"dump the journal log entries");
462 	add_debugger_command("bfs_btree_header", dump_bplustree_header,
463 		"dump a BFS B+tree header");
464 	add_debugger_command("bfs_btree_node", dump_bplustree_node,
465 		"dump a BFS B+tree node");
466 	add_debugger_command("bfs", dump_volume, "dump a BFS volume");
467 	add_debugger_command("bfs_block_runs", dump_block_run_array,
468 		"dump a block run array");
469 }
470 
471 
472 #endif	// BFS_DEBUGGER_COMMANDS
473