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