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