1 /* 2 * Copyright 2001-2008, 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(" etc = %#08x\n", (int)inode->etc); 131 Print(" short_symlink = %s\n", 132 S_ISLNK(inode->Mode()) && (inode->Flags() & INODE_LONG_SYMLINK) == 0 133 ? inode->short_symlink : "-"); 134 dump_data_stream(&(inode->data)); 135 Print(" --\n pad[0] = %08x\n", (int)inode->pad[0]); 136 Print(" pad[1] = %08x\n", (int)inode->pad[1]); 137 Print(" pad[2] = %08x\n", (int)inode->pad[2]); 138 Print(" pad[3] = %08x\n", (int)inode->pad[3]); 139 } 140 141 142 void 143 dump_bplustree_header(const bplustree_header* header) 144 { 145 Print("bplustree_header:\n"); 146 Print(" magic = %#08x (%s) %s\n", (int)header->Magic(), 147 get_tupel(header->magic), 148 (header->magic == BPLUSTREE_MAGIC ? "valid" : "INVALID")); 149 Print(" node_size = %u\n", (unsigned)header->NodeSize()); 150 Print(" max_number_of_levels = %u\n", 151 (unsigned)header->MaxNumberOfLevels()); 152 Print(" data_type = %u\n", (unsigned)header->DataType()); 153 Print(" root_node_pointer = %Ld\n", header->RootNode()); 154 Print(" free_node_pointer = %Ld\n", header->FreeNode()); 155 Print(" 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 Print(" "); 170 171 if (i >= size) 172 Print(" "); 173 else 174 Print("%02x", *(unsigned char *)(buffer + i)); 175 } 176 Print(" "); 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 Print("."); 184 else 185 Print("%c", c); 186 } else 187 break; 188 } 189 Print("\n"); 190 } 191 } 192 193 194 void 195 dump_bplustree_node(const bplustree_node* node, const bplustree_header* header, 196 Volume* volume) 197 { 198 Print("bplustree_node:\n"); 199 Print(" left_link = %Ld\n", node->left_link); 200 Print(" right_link = %Ld\n", node->right_link); 201 Print(" overflow_link = %Ld\n", node->overflow_link); 202 Print(" all_key_count = %u\n", node->all_key_count); 203 Print(" 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 Print("\n"); 212 dump_block((char *)node, header->node_size/*, sizeof(off_t)*/); 213 return; 214 } 215 216 Print("\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 Print(" %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 Print(" %2d. Invalid Offset!!\n", (int)i); 232 else { 233 Print(" %2d. ", (int)i); 234 if (header->data_type == BPLUSTREE_STRING_TYPE) 235 Print("\"%s\"", buffer); 236 else if (header->data_type == BPLUSTREE_INT32_TYPE) { 237 Print("int32 = %d (0x%x)", (int)*(int32 *)&buffer, 238 (int)*(int32 *)&buffer); 239 } else if (header->data_type == BPLUSTREE_UINT32_TYPE) { 240 Print("uint32 = %u (0x%x)", (unsigned)*(uint32 *)&buffer, 241 (unsigned)*(uint32 *)&buffer); 242 } else if (header->data_type == BPLUSTREE_INT64_TYPE) { 243 Print("int64 = %Ld (0x%Lx)", *(int64 *)&buffer, 244 *(int64 *)&buffer); 245 } else 246 Print("???"); 247 248 off_t offset = *value & 0x3fffffffffffffffLL; 249 Print(" (%d bytes) -> %Ld", length, offset); 250 if (volume != NULL) { 251 block_run run = volume->ToBlockRun(offset); 252 Print(" (%d, %d)", (int)run.allocation_group, run.start); 253 } 254 if (bplustree_node::LinkType(*value) 255 == BPLUSTREE_DUPLICATE_FRAGMENT) 256 Print(" (duplicate fragment %Ld)\n", *value & 0x3ff); 257 else if (bplustree_node::LinkType(*value) 258 == BPLUSTREE_DUPLICATE_NODE) 259 Print(" (duplicate node)\n"); 260 else 261 Print("\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 node = &((Inode*)address)->Node(); 293 294 dump_inode(node); 295 return 0; 296 } 297 298 299 static int 300 dump_volume(int argc, char** argv) 301 { 302 if (argc < 2 || !strcmp(argv[1], "--help")) { 303 kprintf("usage: bfs <ptr-to-volume> [<block-run>]\n" 304 "Dumps a BFS volume - <block-run> is given, it is converted to a " 305 "block offset instead (and vice versa).\n"); 306 return 0; 307 } 308 309 Volume* volume = (Volume*)parse_expression(argv[1]); 310 311 if (argc > 2) { 312 // convert block_runs/offsets 313 for (int i = 2; i < argc; i++) { 314 char* arg = argv[i]; 315 if (strchr(arg, '.') != NULL) { 316 // block_run to offset 317 block_run run; 318 run.allocation_group = HOST_ENDIAN_TO_BFS_INT32( 319 strtoul(arg, &arg, 0)); 320 run.start = HOST_ENDIAN_TO_BFS_INT16(strtoul(arg, NULL, 0)); 321 run.length = 0; 322 323 kprintf("%ld.%u -> block %Ld\n", run.AllocationGroup(), 324 run.Start(), volume->ToBlock(run)); 325 } else { 326 // offset to block_run 327 off_t offset = parse_expression(arg); 328 block_run run = volume->ToBlockRun(offset); 329 330 kprintf("block %Ld -> %ld.%u\n", offset, run.AllocationGroup(), 331 run.Start()); 332 } 333 } 334 return 0; 335 } 336 337 kprintf("block cache: %p\n", volume->BlockCache()); 338 kprintf("root node: %p\n", volume->RootNode()); 339 kprintf("indices node: %p\n", volume->IndicesNode()); 340 341 dump_super_block(&volume->SuperBlock()); 342 343 set_debug_variable("_cache", (addr_t)volume->BlockCache()); 344 set_debug_variable("_root", (addr_t)volume->RootNode()); 345 set_debug_variable("_indices", (addr_t)volume->IndicesNode()); 346 347 return 0; 348 } 349 350 351 static int 352 dump_bplustree_node(int argc, char** argv) 353 { 354 if (argc < 2 || argc > 4 || !strcmp(argv[1], "--help")) { 355 kprintf("usage: %s <ptr-to-node> [ptr-to-header] [ptr-to-volume]\n", 356 argv[0]); 357 return 0; 358 } 359 360 bplustree_node* node = (bplustree_node*)parse_expression(argv[1]); 361 bplustree_header* header = NULL; 362 Volume* volume = NULL; 363 364 if (argc > 2) 365 header = (bplustree_header*)parse_expression(argv[2]); 366 if (argc > 3) 367 volume = (Volume*)parse_expression(argv[3]); 368 369 dump_bplustree_node(node, header, volume); 370 371 return 0; 372 } 373 374 375 static int 376 dump_bplustree_header(int argc, char** argv) 377 { 378 if (argc != 2 || !strcmp(argv[1], "--help")) { 379 kprintf("usage: %s <ptr-to-header>\n", argv[0]); 380 return 0; 381 } 382 383 bplustree_header* header = (bplustree_header*)parse_expression(argv[1]); 384 dump_bplustree_header(header); 385 386 return 0; 387 } 388 389 390 void 391 remove_debugger_commands() 392 { 393 remove_debugger_command("bfs_inode", dump_inode); 394 remove_debugger_command("bfs_allocator", dump_block_allocator); 395 remove_debugger_command("bfs_journal", dump_journal); 396 remove_debugger_command("bfs_btree_header", dump_bplustree_header); 397 remove_debugger_command("bfs_btree_node", dump_bplustree_node); 398 remove_debugger_command("bfs", dump_volume); 399 } 400 401 402 void 403 add_debugger_commands() 404 { 405 add_debugger_command("bfs_inode", dump_inode, "dump an Inode object"); 406 add_debugger_command("bfs_allocator", dump_block_allocator, 407 "dump a BFS block allocator"); 408 add_debugger_command("bfs_journal", dump_journal, 409 "dump the journal log entries"); 410 add_debugger_command("bfs_btree_header", dump_bplustree_header, 411 "dump a BFS B+tree header"); 412 add_debugger_command("bfs_btree_node", dump_bplustree_node, 413 "dump a BFS B+tree node"); 414 add_debugger_command("bfs", dump_volume, "dump a BFS volume"); 415 } 416 417 418 #endif // BFS_DEBUGGER_COMMANDS 419