1/* Debug - debug stuff
2**
3** Initial version by Axel Dörfler, axeld@pinc-software.de
4** Some code is based on work previously done by Marcus Overhagen
5**
6** This file may be used under the terms of the OpenBeOS License.
7*/
8
9
10#include "Debug.h"
11#include "BPlusTree.h"
12#include "Inode.h"
13
14#include <KernelExport.h>
15
16#include <time.h>
17
18#define Print __out
19
20
21char *
22get_tupel(uint32 id)
23{
24	static unsigned char tupel[5];
25
26	tupel[0] = 0xff & (id >> 24);
27	tupel[1] = 0xff & (id >> 16);
28	tupel[2] = 0xff & (id >> 8);
29	tupel[3] = 0xff & (id);
30	tupel[4] = 0;
31	for (int16 i = 0;i < 4;i++) {
32		if (tupel[i] < ' ' || tupel[i] > 128)
33			tupel[i] = '.';
34	}
35
36	return (char *)tupel;
37}
38
39
40void
41dump_block_run(const char *prefix, block_run &run)
42{
43	Print("%s(%ld, %d, %d)\n", prefix, run.allocation_group, run.start, run.length);
44}
45
46
47void
48dump_inode(Inode &inode)
49{
50	Print("Inode (%p) {\n", &inode);
51	Print("\tfVolume = %p\n", inode.fVolume);
52	Print("\tfBlockNumber = 0x%16Lx\n", inode.fBlockNumber);
53	Print("\tfNode = %p\n", inode.Node());
54	Print("\tfTree = %p\n", inode.fTree);
55	Print("\tfAttributes = %p\n", inode.fAttributes);
56	Print("\tfOldSize = 0x%16Lx\n", inode.fOldSize);
57	Print("\tfOldLastModified = 0x%16Lx\n", inode.fOldLastModified);
58	Print("}\n");
59}
60
61
62void
63dump_super_block(disk_super_block *superBlock)
64{
65	Print("disk_super_block:\n");
66	Print("  name           = %s\n", superBlock->name);
67	Print("  magic1         = %#08lx (%s) %s\n", superBlock->magic1, get_tupel(superBlock->magic1), (superBlock->magic1 == SUPER_BLOCK_MAGIC1 ? "valid" : "INVALID"));
68	Print("  fs_byte_order  = %#08lx (%s)\n", superBlock->fs_byte_order, get_tupel(superBlock->fs_byte_order));
69	Print("  block_size     = %lu\n", superBlock->block_size);
70	Print("  block_shift    = %lu\n", superBlock->block_shift);
71	Print("  num_blocks     = %Lu\n", superBlock->num_blocks);
72	Print("  used_blocks    = %Lu\n", superBlock->used_blocks);
73	Print("  inode_size     = %lu\n", superBlock->inode_size);
74	Print("  magic2         = %#08lx (%s) %s\n", superBlock->magic2, get_tupel(superBlock->magic2), (superBlock->magic2 == (int)SUPER_BLOCK_MAGIC2 ? "valid" : "INVALID"));
75	Print("  blocks_per_ag  = %lu\n", superBlock->blocks_per_ag);
76	Print("  ag_shift       = %lu (%ld bytes)\n", superBlock->ag_shift, 1L << superBlock->ag_shift);
77	Print("  num_ags        = %lu\n", superBlock->num_ags);
78	Print("  flags          = %#08lx (%s)\n", superBlock->flags, get_tupel(superBlock->flags));
79	dump_block_run("  log_blocks     = ", superBlock->log_blocks);
80	Print("  log_start      = %Lu\n", superBlock->log_start);
81	Print("  log_end        = %Lu\n", superBlock->log_end);
82	Print("  magic3         = %#08lx (%s) %s\n", superBlock->magic3, get_tupel(superBlock->magic3), (superBlock->magic3 == SUPER_BLOCK_MAGIC3 ? "valid" : "INVALID"));
83	dump_block_run("  root_dir       = ", superBlock->root_dir);
84	dump_block_run("  indices        = ", superBlock->indices);
85}
86
87
88void
89dump_data_stream(data_stream *stream)
90{
91	Print("data_stream:\n");
92	for (int i = 0; i < NUM_DIRECT_BLOCKS; i++) {
93		if (!stream->direct[i].IsZero()) {
94			Print("  direct[%02d]                = ",i);
95			dump_block_run("",stream->direct[i]);
96		}
97	}
98	Print("  max_direct_range          = %Lu\n", stream->max_direct_range);
99
100	if (!stream->indirect.IsZero())
101		dump_block_run("  indirect                  = ", stream->indirect);
102
103	Print("  max_indirect_range        = %Lu\n", stream->max_indirect_range);
104
105	if (!stream->double_indirect.IsZero())
106		dump_block_run("  double_indirect           = ", stream->double_indirect);
107
108	Print("  max_double_indirect_range = %Lu\n", stream->max_double_indirect_range);
109	Print("  size                      = %Lu\n", stream->size);
110}
111
112
113void
114dump_inode(bfs_inode *inode)
115{
116	Print("inode:\n");
117	Print("  magic1             = %08lx (%s) %s\n", inode->magic1,
118		get_tupel(inode->magic1), (inode->magic1 == INODE_MAGIC1 ? "valid" : "INVALID"));
119	dump_block_run(	"  inode_num          = ", inode->inode_num);
120	Print("  uid                = %lu\n", inode->uid);
121	Print("  gid                = %lu\n", inode->gid);
122	Print("  mode               = %08lx\n", inode->mode);
123	Print("  flags              = %08lx\n", inode->flags);
124	Print("  create_time        = %Ld (%Ld)\n", inode->create_time,
125		inode->create_time >> INODE_TIME_SHIFT);
126	Print("  last_modified_time = %Ld (%Ld)\n", inode->last_modified_time,
127		inode->last_modified_time >> INODE_TIME_SHIFT);
128	dump_block_run(	"  parent             = ", inode->parent);
129	dump_block_run(	"  attributes         = ", inode->attributes);
130	Print("  type               = %lu\n", inode->type);
131	Print("  inode_size         = %lu\n", inode->inode_size);
132	Print("  etc                = %#08lx\n", inode->etc);
133	Print("  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	Print("  --\n  pad[0]             = %08lx\n", inode->pad[0]);
138	Print("  pad[1]             = %08lx\n", inode->pad[1]);
139	Print("  pad[2]             = %08lx\n", inode->pad[2]);
140	Print("  pad[3]             = %08lx\n", inode->pad[3]);
141}
142
143
144void
145dump_bplustree_header(bplustree_header *header)
146{
147	Print("bplustree_header:\n");
148	Print("  magic                = %#08lx (%s) %s\n", header->magic,
149		get_tupel(header->magic), (header->magic == BPLUSTREE_MAGIC ? "valid" : "INVALID"));
150	Print("  node_size            = %lu\n", header->node_size);
151	Print("  max_number_of_levels = %lu\n", header->max_number_of_levels);
152	Print("  data_type            = %lu\n", header->data_type);
153	Print("  root_node_pointer    = %Ld\n", header->root_node_pointer);
154	Print("  free_node_pointer    = %Ld\n", header->free_node_pointer);
155	Print("  maximum_size         = %Lu\n", header->maximum_size);
156}
157
158
159#define DUMPED_BLOCK_SIZE 16
160
161void
162dump_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
194void
195dump_bplustree_node(bplustree_node *node,bplustree_header *header,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("  %2ld. Invalid length (%u)!!\n", 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 ((uint32)value < (uint32)node || (uint32)value > (uint32)node + header->node_size)
229			Print("  %2ld. Invalid Offset!!\n", i);
230		else {
231			Print("  %2ld. ", i);
232			if (header->data_type == BPLUSTREE_STRING_TYPE)
233				Print("\"%s\"", buffer);
234			else if (header->data_type == BPLUSTREE_INT32_TYPE)
235				Print("int32 = %ld (0x%lx)", *(int32 *)&buffer, *(int32 *)&buffer);
236			else if (header->data_type == BPLUSTREE_UINT32_TYPE)
237				Print("uint32 = %lu (0x%lx)", *(uint32 *)&buffer, *(uint32 *)&buffer);
238			else if (header->data_type == BPLUSTREE_INT64_TYPE)
239				Print("int64 = %Ld (0x%Lx)", *(int64 *)&buffer, *(int64 *)&buffer);
240			else
241				Print("???");
242
243			off_t offset = *value & 0x3fffffffffffffffLL;
244			Print(" (%d bytes) -> %Ld", length, offset);
245			if (volume != NULL) {
246				block_run run = volume->ToBlockRun(offset);
247				Print(" (%ld, %d)", run.allocation_group, run.start);
248			}
249			if (bplustree_node::LinkType(*value) == BPLUSTREE_DUPLICATE_FRAGMENT)
250				Print(" (duplicate fragment %Ld)\n", *value & 0x3ff);
251			else if (bplustree_node::LinkType(*value) == BPLUSTREE_DUPLICATE_NODE)
252				Print(" (duplicate node)\n");
253			else
254				Print("\n");
255		}
256	}
257}
258
259
260//	#pragma mark -
261
262
263#ifndef USER
264//#warn Don't mount more than once... would register twice the debugger commands!
265
266static int
267dbg_inode(int argc, char **argv)
268{
269	if (argc < 2) {
270		kprintf("usage: obfsinode ptr-to-inode\n");
271		return 0;
272	}
273
274	Inode *inode = (Inode *)parse_expression(argv[1]);
275	dump_inode(*inode);
276
277	return B_OK;
278}
279
280#endif
281
282void
283remove_debugger_commands()
284{
285#ifndef USER
286	remove_debugger_command("obfsinode", dbg_inode);
287#endif
288}
289
290
291void
292add_debugger_commands()
293{
294#ifndef USER
295	add_debugger_command("obfsinode", dbg_inode, "dump an Inode object");
296#endif
297}
298
299