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