btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / src / add-ons / kernel / file_systems / bfs / Debug.cpp
blob02a8a58972c40fc655cff64dc3093015b485b75b
1 /*
2 * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Some code is based on work previously done by Marcus Overhagen.
5 * This file may be used under the terms of the MIT License.
6 */
9 #include "Debug.h"
10 #include "BlockAllocator.h"
11 #include "BPlusTree.h"
12 #include "Inode.h"
13 #include "Journal.h"
16 char*
17 get_tupel(uint32 id)
19 static unsigned char tupel[5];
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] = '.';
31 return (char*)tupel;
35 void
36 dump_block_run(const char* prefix, const block_run& run)
38 kprintf("%s(%d, %d, %d)\n", prefix, (int)run.allocation_group, run.start,
39 run.length);
43 void
44 dump_super_block(const disk_super_block* superBlock)
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);
80 void
81 dump_data_stream(const data_stream* stream)
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]);
90 kprintf(" max_direct_range = %" B_PRIdOFF "\n",
91 stream->MaxDirectRange());
93 if (!stream->indirect.IsZero())
94 dump_block_run(" indirect = ", stream->indirect);
96 kprintf(" max_indirect_range = %" B_PRIdOFF "\n",
97 stream->MaxIndirectRange());
99 if (!stream->double_indirect.IsZero()) {
100 dump_block_run(" double_indirect = ",
101 stream->double_indirect);
104 kprintf(" max_double_indirect_range = %" B_PRIdOFF "\n",
105 stream->MaxDoubleIndirectRange());
106 kprintf(" size = %" B_PRIdOFF "\n", stream->Size());
110 void
111 dump_inode(const bfs_inode* inode)
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]);
144 void
145 dump_bplustree_header(const bplustree_header* header)
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());
161 #define DUMPED_BLOCK_SIZE 16
163 void
164 dump_block(const char* buffer,int size)
166 for (int i = 0; i < size;) {
167 int start = i;
169 for (; i < start + DUMPED_BLOCK_SIZE; i++) {
170 if (!(i % 4))
171 kprintf(" ");
173 if (i >= size)
174 kprintf(" ");
175 else
176 kprintf("%02x", *(unsigned char *)(buffer + i));
178 kprintf(" ");
180 for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) {
181 if (i < size) {
182 char c = *(buffer + i);
184 if (c < 30)
185 kprintf(".");
186 else
187 kprintf("%c", c);
188 } else
189 break;
191 kprintf("\n");
196 void
197 dump_bplustree_node(const bplustree_node* node, const bplustree_header* header,
198 Volume* volume)
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);
207 if (header == NULL)
208 return;
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;
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;
227 memcpy(buffer, key, length);
228 buffer[length] = '\0';
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("???");
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);
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");
270 // #pragma mark - debugger commands
273 #ifdef BFS_DEBUGGER_COMMANDS
276 static int
277 dump_inode(int argc, char** argv)
279 bool block = false;
280 if (argc >= 3 && !strcmp(argv[1], "-b"))
281 block = true;
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;
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;
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());
306 node = &inode->Node();
309 dump_inode(node);
310 return 0;
314 static int
315 dump_volume(int argc, char** argv)
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;
324 Volume* volume = (Volume*)parse_expression(argv[1]);
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;
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);
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);
354 return 0;
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());
364 dump_super_block(&volume->SuperBlock());
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());
370 return 0;
374 static int
375 dump_block_run_array(int argc, char** argv)
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;
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]);
388 uint32 blockSize = 0;
389 if (argc > 3)
390 blockSize = parse_expression(argv[3]);
392 off_t offset = 0;
393 if (argc > 4)
394 offset = parse_expression(argv[4]);
396 off_t searchOffset = 0;
397 if (argc > 5)
398 searchOffset = parse_expression(argv[5]);
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);
406 uint32 size = runs[i].Length() * blockSize;
407 if (searchOffset != 0 && searchOffset >= offset
408 && searchOffset < offset + size)
409 dprintf("* ");
411 dump_block_run("", runs[i]);
413 offset += size;
416 return 0;
420 static int
421 dump_bplustree_node(int argc, char** argv)
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;
429 bplustree_node* node = (bplustree_node*)parse_expression(argv[1]);
430 bplustree_header* header = NULL;
431 Volume* volume = NULL;
433 if (argc > 2)
434 header = (bplustree_header*)parse_expression(argv[2]);
435 if (argc > 3)
436 volume = (Volume*)parse_expression(argv[3]);
438 dump_bplustree_node(node, header, volume);
440 return 0;
444 static int
445 dump_bplustree_header(int argc, char** argv)
447 if (argc != 2 || !strcmp(argv[1], "--help")) {
448 kprintf("usage: %s <ptr-to-header>\n", argv[0]);
449 return 0;
452 bplustree_header* header = (bplustree_header*)parse_expression(argv[1]);
453 dump_bplustree_header(header);
455 return 0;
459 void
460 remove_debugger_commands()
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);
476 void
477 add_debugger_commands()
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");
498 #endif // BFS_DEBUGGER_COMMANDS