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::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 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: %" 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 314 static int 315 dump_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 374 static int 375 dump_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 420 static int 421 dump_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 444 static int 445 dump_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 459 void 460 remove_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 476 void 477 add_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