Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5Odbg.c |
16 | | * |
17 | | * Purpose: Object header debugging routines. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #include "H5Omodule.h" /* This source code file is part of the H5O module */ |
27 | | |
28 | | /***********/ |
29 | | /* Headers */ |
30 | | /***********/ |
31 | | #include "H5private.h" /* Generic Functions */ |
32 | | #include "H5Eprivate.h" /* Error handling */ |
33 | | #include "H5MMprivate.h" /* Memory management */ |
34 | | #include "H5Opkg.h" /* Object headers */ |
35 | | |
36 | | /****************/ |
37 | | /* Local Macros */ |
38 | | /****************/ |
39 | | |
40 | | /******************/ |
41 | | /* Local Typedefs */ |
42 | | /******************/ |
43 | | |
44 | | /********************/ |
45 | | /* Package Typedefs */ |
46 | | /********************/ |
47 | | |
48 | | /********************/ |
49 | | /* Local Prototypes */ |
50 | | /********************/ |
51 | | |
52 | | /*********************/ |
53 | | /* Package Variables */ |
54 | | /*********************/ |
55 | | |
56 | | /*****************************/ |
57 | | /* Library Private Variables */ |
58 | | /*****************************/ |
59 | | |
60 | | /*******************/ |
61 | | /* Local Variables */ |
62 | | /*******************/ |
63 | | |
64 | | /*------------------------------------------------------------------------- |
65 | | * Function: H5O__print_time_field |
66 | | * |
67 | | * Purpose: Format and print a time_t value as a debug field. |
68 | | * Prints "(invalid time)" if localtime_r fails. |
69 | | * |
70 | | * Return: void |
71 | | *------------------------------------------------------------------------- |
72 | | */ |
73 | | static void |
74 | | H5O__print_time_field(FILE *stream, int indent, int fwidth, const char *label, const time_t *time_val) |
75 | 0 | { |
76 | 0 | struct tm tm_buf; |
77 | 0 | char buf[128]; |
78 | |
|
79 | 0 | if (HDlocaltime_r(time_val, &tm_buf) != NULL) |
80 | 0 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", &tm_buf); |
81 | 0 | else |
82 | 0 | snprintf(buf, sizeof(buf), "(invalid time)"); |
83 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, label, buf); |
84 | 0 | } /* end H5O__print_time_field() */ |
85 | | |
86 | | #ifdef H5O_DEBUG |
87 | | |
88 | | /*------------------------------------------------------------------------- |
89 | | * Function: H5O__assert |
90 | | * |
91 | | * Purpose: Sanity check the information for an object header data |
92 | | * structure. |
93 | | * |
94 | | * Return: SUCCEED (Doesn't fail, just crashes) |
95 | | * |
96 | | *------------------------------------------------------------------------- |
97 | | */ |
98 | | herr_t |
99 | | H5O__assert(const H5O_t *oh) |
100 | | { |
101 | | H5O_mesg_t *curr_msg; /* Pointer to current message to examine */ |
102 | | H5O_mesg_t *tmp_msg; /* Pointer to temporary message to examine */ |
103 | | unsigned cont_msgs_found = 0; /* # of continuation messages for object */ |
104 | | size_t meta_space; /* Size of header metadata */ |
105 | | size_t mesg_space; /* Size of message raw data */ |
106 | | size_t free_space; /* Size of free space in header */ |
107 | | size_t hdr_size; /* Size of header's chunks */ |
108 | | unsigned u, v; /* Local index variables */ |
109 | | |
110 | | FUNC_ENTER_PACKAGE_NOERR |
111 | | |
112 | | assert(oh); |
113 | | assert(oh->chunk || oh->nchunks == 0); |
114 | | assert(oh->mesg || oh->nmesgs == 0); |
115 | | |
116 | | /* Initialize the tracking variables */ |
117 | | hdr_size = 0; |
118 | | meta_space = (size_t)H5O_SIZEOF_HDR(oh) + (size_t)(H5O_SIZEOF_CHKHDR_OH(oh) * (oh->nchunks - 1)); |
119 | | mesg_space = 0; |
120 | | free_space = 0; |
121 | | |
122 | | /* Loop over all chunks in object header */ |
123 | | for (u = 0; u < oh->nchunks; u++) { |
124 | | /* Accumulate the size of the header on header */ |
125 | | hdr_size += oh->chunk[u].size; |
126 | | |
127 | | /* If the chunk has a gap, add it to the free space */ |
128 | | free_space += oh->chunk[u].gap; |
129 | | |
130 | | /* Check for valid raw data image */ |
131 | | assert(oh->chunk[u].image); |
132 | | assert(oh->chunk[u].size > (size_t)H5O_SIZEOF_CHKHDR_OH(oh)); |
133 | | |
134 | | /* All chunks must be allocated on disk */ |
135 | | assert(H5_addr_defined(oh->chunk[u].addr)); |
136 | | |
137 | | /* Version specific checks */ |
138 | | if (oh->version > H5O_VERSION_1) { |
139 | | /* Make certain that the magic number is correct for each chunk */ |
140 | | assert(!memcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC)); |
141 | | |
142 | | /* Check for valid gap size */ |
143 | | assert(oh->chunk[u].gap < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)); |
144 | | } /* end if */ |
145 | | else |
146 | | /* Gaps should never occur in version 1 of the format */ |
147 | | assert(oh->chunk[u].gap == 0); |
148 | | } /* end for */ |
149 | | |
150 | | /* Check for correct chunk #0 size flags */ |
151 | | if (oh->version > H5O_VERSION_1) { |
152 | | uint64_t chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh); |
153 | | |
154 | | if (chunk0_size <= 255) |
155 | | assert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1); |
156 | | else if (chunk0_size <= 65535) |
157 | | assert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_2); |
158 | | else if (chunk0_size <= 4294967295) |
159 | | assert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_4); |
160 | | else |
161 | | assert((oh->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_8); |
162 | | } /* end if */ |
163 | | |
164 | | /* Loop over all messages in object header */ |
165 | | for (u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { |
166 | | uint8_t H5_ATTR_NDEBUG_UNUSED *curr_hdr; /* Start of current message header */ |
167 | | size_t curr_tot_size; /* Total size of current message (including header) */ |
168 | | |
169 | | assert(curr_msg->type); |
170 | | |
171 | | curr_hdr = curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh); |
172 | | curr_tot_size = curr_msg->raw_size + (size_t)H5O_SIZEOF_MSGHDR_OH(oh); |
173 | | |
174 | | /* Accumulate information, based on the type of message */ |
175 | | if (H5O_NULL_ID == curr_msg->type->id) |
176 | | free_space += curr_tot_size; |
177 | | else if (H5O_CONT_ID == curr_msg->type->id) { |
178 | | H5O_cont_t *cont = (H5O_cont_t *)curr_msg->native; |
179 | | bool H5_ATTR_NDEBUG_UNUSED found_chunk = false; /* Found a chunk that matches */ |
180 | | |
181 | | assert(cont); |
182 | | |
183 | | /* Increment # of continuation messages found */ |
184 | | cont_msgs_found++; |
185 | | |
186 | | /* Sanity check that every continuation message has a matching chunk */ |
187 | | /* (and only one) */ |
188 | | for (v = 0; v < oh->nchunks; v++) { |
189 | | if (H5_addr_eq(cont->addr, oh->chunk[v].addr) && cont->size == oh->chunk[v].size) { |
190 | | assert(cont->chunkno == v); |
191 | | assert(!found_chunk); |
192 | | found_chunk = true; |
193 | | } /* end if */ |
194 | | } /* end for */ |
195 | | assert(found_chunk); |
196 | | |
197 | | meta_space += curr_tot_size; |
198 | | } /* end if */ |
199 | | else { |
200 | | meta_space += (size_t)H5O_SIZEOF_MSGHDR_OH(oh); |
201 | | mesg_space += curr_msg->raw_size; |
202 | | |
203 | | /* Make sure the message has a native form if it is marked dirty */ |
204 | | assert(curr_msg->native || !curr_msg->dirty); |
205 | | } /* end else */ |
206 | | |
207 | | /* Make certain that the message is in a valid chunk */ |
208 | | assert(curr_msg->chunkno < oh->nchunks); |
209 | | |
210 | | /* Make certain null messages aren't in chunks with gaps */ |
211 | | if (H5O_NULL_ID == curr_msg->type->id) |
212 | | assert(oh->chunk[curr_msg->chunkno].gap == 0); |
213 | | |
214 | | /* Make certain that the message is completely in a chunk message area */ |
215 | | assert(curr_tot_size <= (oh->chunk[curr_msg->chunkno].size) - |
216 | | (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); |
217 | | if (curr_msg->chunkno == 0) |
218 | | assert(curr_hdr >= |
219 | | oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); |
220 | | else |
221 | | assert(curr_hdr >= oh->chunk[curr_msg->chunkno].image + |
222 | | (H5O_SIZEOF_CHKHDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); |
223 | | assert(curr_msg->raw + curr_msg->raw_size <= |
224 | | (oh->chunk[curr_msg->chunkno].image + oh->chunk[curr_msg->chunkno].size) - |
225 | | (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); |
226 | | |
227 | | /* Make certain that no other messages overlap this message */ |
228 | | for (v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) { |
229 | | if (u != v) |
230 | | assert(!((tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) >= curr_hdr && |
231 | | (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) < (curr_hdr + curr_tot_size))); |
232 | | } /* end for */ |
233 | | } /* end for */ |
234 | | |
235 | | /* Sanity check that the # of cont. messages is correct for the # of chunks */ |
236 | | assert(oh->nchunks == (cont_msgs_found + 1)); |
237 | | |
238 | | /* Sanity check that all the bytes are accounted for */ |
239 | | assert(hdr_size == (free_space + meta_space + mesg_space)); |
240 | | |
241 | | FUNC_LEAVE_NOAPI(SUCCEED) |
242 | | } /* end H5O__assert() */ |
243 | | #endif /* H5O_DEBUG */ |
244 | | |
245 | | /*------------------------------------------------------------------------- |
246 | | * Function: H5O_debug_id |
247 | | * |
248 | | * Purpose: Act as a proxy for calling the 'debug' method for a |
249 | | * particular class of object header. |
250 | | * |
251 | | * Return: Non-negative on success/Negative on failure |
252 | | * |
253 | | *------------------------------------------------------------------------- |
254 | | */ |
255 | | herr_t |
256 | | H5O_debug_id(unsigned type_id, H5F_t *f, const void *mesg, FILE *stream, int indent, int fwidth) |
257 | 0 | { |
258 | 0 | const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ |
259 | 0 | herr_t ret_value = FAIL; /* Return value */ |
260 | |
|
261 | 0 | FUNC_ENTER_NOAPI(FAIL) |
262 | | |
263 | | /* Check args */ |
264 | 0 | assert(type_id < NELMTS(H5O_msg_class_g)); |
265 | 0 | type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ |
266 | 0 | assert(type); |
267 | 0 | assert(type->debug); |
268 | 0 | assert(f); |
269 | 0 | assert(mesg); |
270 | 0 | assert(stream); |
271 | 0 | assert(indent >= 0); |
272 | 0 | assert(fwidth >= 0); |
273 | | |
274 | | /* Call the debug method in the class */ |
275 | 0 | if ((ret_value = (type->debug)(f, mesg, stream, indent, fwidth)) < 0) |
276 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "unable to debug message"); |
277 | | |
278 | 0 | done: |
279 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
280 | 0 | } /* end H5O_debug_id() */ |
281 | | |
282 | | /*------------------------------------------------------------------------- |
283 | | * Function: H5O__debug_real |
284 | | * |
285 | | * Purpose: Prints debugging info about an object header. |
286 | | * |
287 | | * Return: SUCCEED/FAIL |
288 | | * |
289 | | *------------------------------------------------------------------------- |
290 | | */ |
291 | | herr_t |
292 | | H5O__debug_real(H5F_t *f, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth) |
293 | 0 | { |
294 | 0 | size_t mesg_total = 0, chunk_total = 0, gap_total = 0; |
295 | 0 | unsigned *sequence = NULL; |
296 | 0 | unsigned i; /* Local index variable */ |
297 | 0 | herr_t ret_value = SUCCEED; |
298 | |
|
299 | 0 | FUNC_ENTER_PACKAGE |
300 | | |
301 | | /* check args */ |
302 | 0 | assert(f); |
303 | 0 | assert(oh); |
304 | 0 | assert(H5_addr_defined(addr)); |
305 | 0 | assert(stream); |
306 | 0 | assert(indent >= 0); |
307 | 0 | assert(fwidth >= 0); |
308 | | |
309 | | /* debug */ |
310 | 0 | fprintf(stream, "%*sObject Header...\n", indent, ""); |
311 | |
|
312 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Dirty:", oh->cache_info.is_dirty ? "TRUE" : "FALSE"); |
313 | 0 | fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Version:", oh->version); |
314 | 0 | fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, |
315 | 0 | "Header size (in bytes):", (unsigned)H5O_SIZEOF_HDR(oh)); |
316 | 0 | fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Number of links:", oh->nlink); |
317 | | |
318 | | /* Extra information for later versions */ |
319 | 0 | if (oh->version > H5O_VERSION_1) { |
320 | | /* Display object's status flags */ |
321 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Attribute creation order tracked:", |
322 | 0 | (oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED) ? "Yes" : "No"); |
323 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Attribute creation order indexed:", |
324 | 0 | (oh->flags & H5O_HDR_ATTR_CRT_ORDER_INDEXED) ? "Yes" : "No"); |
325 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Attribute storage phase change values:", |
326 | 0 | (oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) ? "Non-default" : "Default"); |
327 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, |
328 | 0 | "Timestamps:", (oh->flags & H5O_HDR_STORE_TIMES) ? "Enabled" : "Disabled"); |
329 | 0 | if (oh->flags & ~H5O_HDR_ALL_FLAGS) |
330 | 0 | fprintf(stream, "*** UNKNOWN OBJECT HEADER STATUS FLAG: %02x!\n", (unsigned)oh->flags); |
331 | | |
332 | | /* Only dump times, if they are tracked */ |
333 | 0 | if (oh->flags & H5O_HDR_STORE_TIMES) { |
334 | 0 | H5O__print_time_field(stream, indent, fwidth, "Access Time:", &oh->atime); |
335 | 0 | H5O__print_time_field(stream, indent, fwidth, "Modification Time:", &oh->mtime); |
336 | 0 | H5O__print_time_field(stream, indent, fwidth, "Change Time:", &oh->ctime); |
337 | 0 | H5O__print_time_field(stream, indent, fwidth, "Birth Time:", &oh->btime); |
338 | 0 | } /* end if */ |
339 | | |
340 | | /* Attribute tracking fields */ |
341 | 0 | if (oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) { |
342 | 0 | fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, |
343 | 0 | "Max. compact attributes:", (unsigned)oh->max_compact); |
344 | 0 | fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, |
345 | 0 | "Min. dense attributes:", (unsigned)oh->min_dense); |
346 | 0 | } /* end if */ |
347 | 0 | } /* end if */ |
348 | |
|
349 | 0 | fprintf(stream, "%*s%-*s %zu (%zu)\n", indent, "", fwidth, "Number of messages (allocated):", oh->nmesgs, |
350 | 0 | oh->alloc_nmesgs); |
351 | 0 | fprintf(stream, "%*s%-*s %zu (%zu)\n", indent, "", fwidth, "Number of chunks (allocated):", oh->nchunks, |
352 | 0 | oh->alloc_nchunks); |
353 | | |
354 | | /* debug each chunk */ |
355 | 0 | for (i = 0, chunk_total = 0; i < oh->nchunks; i++) { |
356 | 0 | size_t chunk_size; |
357 | |
|
358 | 0 | fprintf(stream, "%*sChunk %d...\n", indent, "", i); |
359 | |
|
360 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent + 3, "", MAX(0, fwidth - 3), |
361 | 0 | "Address:", oh->chunk[i].addr); |
362 | | |
363 | | /* Decrement chunk 0's size by the object header prefix size */ |
364 | 0 | if (0 == i) { |
365 | 0 | if (H5_addr_ne(oh->chunk[i].addr, addr)) |
366 | 0 | fprintf(stream, "*** WRONG ADDRESS FOR CHUNK #0!\n"); |
367 | 0 | chunk_size = oh->chunk[i].size - (size_t)H5O_SIZEOF_HDR(oh); |
368 | 0 | } /* end if */ |
369 | 0 | else |
370 | 0 | chunk_size = oh->chunk[i].size; |
371 | | |
372 | | /* Accumulate chunk's size to total */ |
373 | 0 | chunk_total += chunk_size; |
374 | 0 | gap_total += oh->chunk[i].gap; |
375 | |
|
376 | 0 | fprintf(stream, "%*s%-*s %zu\n", indent + 3, "", MAX(0, fwidth - 3), "Size in bytes:", chunk_size); |
377 | |
|
378 | 0 | fprintf(stream, "%*s%-*s %zu\n", indent + 3, "", MAX(0, fwidth - 3), "Gap:", oh->chunk[i].gap); |
379 | 0 | } /* end for */ |
380 | | |
381 | | /* debug each message */ |
382 | 0 | if (NULL == (sequence = (unsigned *)H5MM_calloc(NELMTS(H5O_msg_class_g) * sizeof(unsigned)))) |
383 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
384 | 0 | for (i = 0, mesg_total = 0; i < oh->nmesgs; i++) { |
385 | 0 | const H5O_msg_class_t *debug_type; /* Type of message to use for callbacks */ |
386 | 0 | unsigned chunkno; /* Chunk for message */ |
387 | | |
388 | | /* Accumulate message's size to total */ |
389 | 0 | mesg_total += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[i].raw_size; |
390 | | |
391 | | /* For version 2 object header, add size of "OCHK" for continuation chunk */ |
392 | 0 | if (oh->mesg[i].type->id == H5O_CONT_ID) |
393 | 0 | mesg_total += H5O_SIZEOF_CHKHDR_OH(oh); |
394 | |
|
395 | 0 | fprintf(stream, "%*sMessage %d...\n", indent, "", i); |
396 | | |
397 | | /* check for bad message id */ |
398 | 0 | if (oh->mesg[i].type->id >= (int)NELMTS(H5O_msg_class_g)) { |
399 | 0 | fprintf(stream, "*** BAD MESSAGE ID 0x%04x\n", oh->mesg[i].type->id); |
400 | 0 | continue; |
401 | 0 | } /* end if */ |
402 | | |
403 | | /* message name and size */ |
404 | 0 | fprintf(stream, "%*s%-*s 0x%04x `%s' (%d)\n", indent + 3, "", MAX(0, fwidth - 3), |
405 | 0 | "Message ID (sequence number):", (unsigned)(oh->mesg[i].type->id), oh->mesg[i].type->name, |
406 | 0 | sequence[oh->mesg[i].type->id]++); |
407 | 0 | fprintf(stream, "%*s%-*s %s\n", indent + 3, "", MAX(0, fwidth - 3), |
408 | 0 | "Dirty:", oh->mesg[i].dirty ? "TRUE" : "FALSE"); |
409 | 0 | fprintf(stream, "%*s%-*s ", indent + 3, "", MAX(0, fwidth - 3), "Message flags:"); |
410 | 0 | if (oh->mesg[i].flags) { |
411 | 0 | bool flag_printed = false; |
412 | | |
413 | | /* Sanity check that all flags in format are covered below */ |
414 | 0 | HDcompile_assert(H5O_MSG_FLAG_BITS == |
415 | 0 | (H5O_MSG_FLAG_CONSTANT | H5O_MSG_FLAG_SHARED | H5O_MSG_FLAG_DONTSHARE | |
416 | 0 | H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE | H5O_MSG_FLAG_MARK_IF_UNKNOWN | |
417 | 0 | H5O_MSG_FLAG_WAS_UNKNOWN | H5O_MSG_FLAG_SHAREABLE | |
418 | 0 | H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS)); |
419 | |
|
420 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_CONSTANT) { |
421 | 0 | fprintf(stream, "%sC", (flag_printed ? ", " : "<")); |
422 | 0 | flag_printed = true; |
423 | 0 | } /* end if */ |
424 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_SHARED) { |
425 | 0 | fprintf(stream, "%sS", (flag_printed ? ", " : "<")); |
426 | 0 | flag_printed = true; |
427 | 0 | } /* end if */ |
428 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_DONTSHARE) { |
429 | 0 | fprintf(stream, "%sDS", (flag_printed ? ", " : "<")); |
430 | 0 | flag_printed = true; |
431 | 0 | } /* end if */ |
432 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE) { |
433 | 0 | fprintf(stream, "%sFIUW", (flag_printed ? ", " : "<")); |
434 | 0 | flag_printed = true; |
435 | 0 | } /* end if */ |
436 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) { |
437 | 0 | fprintf(stream, "%sMIU", (flag_printed ? ", " : "<")); |
438 | 0 | flag_printed = true; |
439 | 0 | } /* end if */ |
440 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_WAS_UNKNOWN) { |
441 | 0 | assert(oh->mesg[i].flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN); |
442 | 0 | fprintf(stream, "%sWU", (flag_printed ? ", " : "<")); |
443 | 0 | flag_printed = true; |
444 | 0 | } /* end if */ |
445 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_SHAREABLE) { |
446 | 0 | fprintf(stream, "%sSA", (flag_printed ? ", " : "<")); |
447 | 0 | flag_printed = true; |
448 | 0 | } /* end if */ |
449 | 0 | if (oh->mesg[i].flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS) { |
450 | 0 | fprintf(stream, "%sFIUA", (flag_printed ? ", " : "<")); |
451 | 0 | flag_printed = true; |
452 | 0 | } /* end if */ |
453 | 0 | if (!flag_printed) |
454 | 0 | fprintf(stream, "-"); |
455 | 0 | fprintf(stream, ">\n"); |
456 | 0 | if (oh->mesg[i].flags & ~H5O_MSG_FLAG_BITS) |
457 | 0 | fprintf(stream, "%*s%-*s 0x%02x\n", indent + 3, "", MAX(0, fwidth - 3), |
458 | 0 | "*** ADDITIONAL UNKNOWN FLAGS --->", oh->mesg[i].flags & ~H5O_MSG_FLAG_BITS); |
459 | 0 | } /* end if */ |
460 | 0 | else |
461 | 0 | fprintf(stream, "<none>\n"); |
462 | |
|
463 | 0 | fprintf(stream, "%*s%-*s %u\n", indent + 3, "", MAX(0, fwidth - 3), |
464 | 0 | "Chunk number:", oh->mesg[i].chunkno); |
465 | 0 | chunkno = oh->mesg[i].chunkno; |
466 | 0 | if (chunkno >= oh->nchunks) |
467 | 0 | fprintf(stream, "*** BAD CHUNK NUMBER\n"); |
468 | 0 | fprintf(stream, "%*s%-*s (%zu, %zu) bytes\n", indent + 3, "", MAX(0, fwidth - 3), |
469 | 0 | "Raw message data (offset, size) in chunk:", |
470 | 0 | (size_t)(oh->mesg[i].raw - oh->chunk[chunkno].image), oh->mesg[i].raw_size); |
471 | | |
472 | | /* check the size */ |
473 | 0 | if ((oh->mesg[i].raw + oh->mesg[i].raw_size > oh->chunk[chunkno].image + oh->chunk[chunkno].size) || |
474 | 0 | (oh->mesg[i].raw < oh->chunk[chunkno].image)) |
475 | 0 | fprintf(stream, "*** BAD MESSAGE RAW ADDRESS\n"); |
476 | | |
477 | | /* decode the message */ |
478 | 0 | debug_type = oh->mesg[i].type; |
479 | 0 | if (NULL == oh->mesg[i].native && debug_type->decode) |
480 | 0 | H5O_LOAD_NATIVE(f, H5O_DECODEIO_NOCHANGE, oh, &oh->mesg[i], FAIL) |
481 | | |
482 | | /* print the message */ |
483 | 0 | fprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3), "Message Information:"); |
484 | 0 | if (debug_type->debug && oh->mesg[i].native != NULL) |
485 | 0 | (debug_type->debug)(f, oh->mesg[i].native, stream, indent + 6, MAX(0, fwidth - 6)); |
486 | 0 | else |
487 | 0 | fprintf(stream, "%*s<No info for this message>\n", indent + 6, ""); |
488 | 0 | } /* end for */ |
489 | | |
490 | 0 | if ((mesg_total + gap_total) != chunk_total) |
491 | 0 | fprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n"); |
492 | |
|
493 | 0 | done: |
494 | | /* Release resources */ |
495 | 0 | if (sequence) |
496 | 0 | sequence = (unsigned *)H5MM_xfree(sequence); |
497 | |
|
498 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
499 | 0 | } /* end H5O__debug_real() */ |
500 | | |
501 | | /*------------------------------------------------------------------------- |
502 | | * Function: H5O_debug |
503 | | * |
504 | | * Purpose: Prints debugging info about an object header. |
505 | | * |
506 | | * Return: Non-negative on success/Negative on failure |
507 | | * |
508 | | *------------------------------------------------------------------------- |
509 | | */ |
510 | | herr_t |
511 | | H5O_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth) |
512 | 0 | { |
513 | 0 | H5O_t *oh = NULL; /* Object header to display */ |
514 | 0 | H5O_loc_t loc; /* Object location for object to delete */ |
515 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
516 | |
|
517 | 0 | FUNC_ENTER_NOAPI(FAIL) |
518 | | |
519 | | /* check args */ |
520 | 0 | assert(f); |
521 | 0 | assert(H5_addr_defined(addr)); |
522 | 0 | assert(stream); |
523 | 0 | assert(indent >= 0); |
524 | 0 | assert(fwidth >= 0); |
525 | | |
526 | | /* Set up the object location */ |
527 | 0 | loc.file = f; |
528 | 0 | loc.addr = addr; |
529 | 0 | loc.holding_file = false; |
530 | |
|
531 | 0 | if (NULL == (oh = H5O_protect(&loc, H5AC__READ_ONLY_FLAG, false))) |
532 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header"); |
533 | | |
534 | | /* debug */ |
535 | 0 | if (H5O__debug_real(f, oh, addr, stream, indent, fwidth) < 0) |
536 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, FAIL, "debug dump call failed"); |
537 | | |
538 | 0 | done: |
539 | 0 | if (oh && H5O_unprotect(&loc, oh, H5AC__NO_FLAGS_SET) < 0) |
540 | 0 | HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header"); |
541 | |
|
542 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
543 | 0 | } /* end H5O_debug() */ |