1 /**************************************************************************
3 * Copyright 2011 Jose Fonseca
4 * Copyright 2010 VMware, Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
31 #include "trace_file.hpp"
32 #include "trace_snappyfile.hpp"
33 #include "trace_parser.hpp"
36 #define TRACE_VERBOSE 0
54 bool Parser::open(const char *filename) {
56 if (File::isZLibCompressed(filename)) {
59 file = new SnappyFile;
62 if (!file->open(filename, File::Read)) {
66 version = read_uint();
67 if (version > TRACE_VERSION) {
68 std::cerr << "error: unsupported trace format version " << version << "\n";
75 template <typename Iter>
77 deleteAll(Iter begin, Iter end)
79 while (begin != end) {
85 template <typename Container>
87 deleteAll(Container &c)
89 deleteAll(c.begin(), c.end());
93 void Parser::close(void) {
101 deleteAll(functions);
108 void Parser::getBookmark(ParseBookmark &bookmark) {
109 bookmark.offset = file->currentOffset();
110 bookmark.next_call_no = next_call_no;
114 void Parser::setBookmark(const ParseBookmark &bookmark) {
115 file->setCurrentOffset(bookmark.offset);
116 next_call_no = bookmark.next_call_no;
118 // Simply ignore all pending calls
123 Call *Parser::parse_call(void) {
127 case Trace::EVENT_ENTER:
130 case Trace::EVENT_LEAVE:
131 return parse_leave();
133 std::cerr << "error: unknown event " << c << "\n";
136 for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
137 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
138 std::cerr << **it << "\n";
146 Call * Parser::scan_call()
151 case Trace::EVENT_ENTER:
154 case Trace::EVENT_LEAVE:
157 std::cerr << "error: unknown event " << c << "\n";
160 for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
161 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
162 std::cerr << **it << "\n";
171 * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
174 T *lookup(std::vector<T *> &map, size_t index) {
175 if (index >= map.size()) {
176 map.resize(index + 1);
184 FunctionSig *Parser::parse_function_sig(void) {
185 size_t id = read_uint();
187 FunctionSigState *sig = lookup(functions, id);
190 /* parse the signature */
191 sig = new FunctionSigState;
193 sig->name = read_string();
194 sig->num_args = read_uint();
195 const char **arg_names = new const char *[sig->num_args];
196 for (unsigned i = 0; i < sig->num_args; ++i) {
197 arg_names[i] = read_string();
199 sig->arg_names = arg_names;
200 sig->offset = file->currentOffset();
202 } else if (file->currentOffset() < sig->offset) {
203 /* skip over the signature */
204 skip_string(); /* name */
205 int num_args = read_uint();
206 for (unsigned i = 0; i < num_args; ++i) {
207 skip_string(); /*arg_name*/
216 StructSig *Parser::parse_struct_sig() {
217 size_t id = read_uint();
219 StructSigState *sig = lookup(structs, id);
222 /* parse the signature */
223 sig = new StructSigState;
225 sig->name = read_string();
226 sig->num_members = read_uint();
227 const char **member_names = new const char *[sig->num_members];
228 for (unsigned i = 0; i < sig->num_members; ++i) {
229 member_names[i] = read_string();
231 sig->member_names = member_names;
232 sig->offset = file->currentOffset();
234 } else if (file->currentOffset() < sig->offset) {
235 /* skip over the signature */
236 skip_string(); /* name */
237 unsigned num_members = read_uint();
238 for (unsigned i = 0; i < num_members; ++i) {
239 skip_string(); /* member_name */
248 EnumSig *Parser::parse_enum_sig() {
249 size_t id = read_uint();
251 EnumSigState *sig = lookup(enums, id);
254 /* parse the signature */
255 sig = new EnumSigState;
257 sig->name = read_string();
258 Value *value = parse_value();
259 sig->value = value->toSInt();
261 sig->offset = file->currentOffset();
263 } else if (file->currentOffset() < sig->offset) {
264 /* skip over the signature */
265 skip_string(); /*name*/
274 BitmaskSig *Parser::parse_bitmask_sig() {
275 size_t id = read_uint();
277 BitmaskSigState *sig = lookup(bitmasks, id);
280 /* parse the signature */
281 sig = new BitmaskSigState;
283 sig->num_flags = read_uint();
284 BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
285 for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
286 it->name = read_string();
287 it->value = read_uint();
288 if (it->value == 0 && it != flags) {
289 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
293 sig->offset = file->currentOffset();
295 } else if (file->currentOffset() < sig->offset) {
296 /* skip over the signature */
297 int num_flags = read_uint();
298 for (int i = 0; i < num_flags; ++i) {
299 skip_string(); /*name */
300 skip_uint(); /* value */
309 void Parser::parse_enter(void) {
310 FunctionSig *sig = parse_function_sig();
312 Call *call = new Call(sig);
314 call->no = next_call_no++;
316 if (parse_call_details(call)) {
317 calls.push_back(call);
324 void Parser::scan_enter(void) {
325 FunctionSig *sig = parse_function_sig();
327 Call *call = new Call(sig);
328 call->no = next_call_no++;
330 if (scan_call_details(call)) {
331 calls.push_back(call);
338 Call *Parser::parse_leave(void) {
339 unsigned call_no = read_uint();
341 for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
342 if ((*it)->no == call_no) {
352 if (parse_call_details(call)) {
361 Call *Parser::scan_leave(void) {
362 unsigned call_no = read_uint();
364 for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
365 if ((*it)->no == call_no) {
375 if (scan_call_details(call)) {
384 bool Parser::parse_call_details(Call *call) {
388 case Trace::CALL_END:
390 case Trace::CALL_ARG:
393 case Trace::CALL_RET:
394 call->ret = parse_value();
397 std::cerr << "error: ("<<call->name()<< ") unknown call detail "
407 bool Parser::scan_call_details(Call *call) {
411 case Trace::CALL_END:
413 case Trace::CALL_ARG:
416 case Trace::CALL_RET:
420 std::cerr << "error: ("<<call->name()<< ") unknown call detail "
430 void Parser::parse_arg(Call *call) {
431 unsigned index = read_uint();
432 Value *value = parse_value();
433 if (index >= call->args.size()) {
434 call->args.resize(index + 1);
436 call->args[index] = value;
440 void Parser::scan_arg(Call *call) {
441 skip_uint(); /* index */
442 scan_value(); /* value */
446 Value *Parser::parse_value(void) {
451 case Trace::TYPE_NULL:
454 case Trace::TYPE_FALSE:
455 value = new Bool(false);
457 case Trace::TYPE_TRUE:
458 value = new Bool(true);
460 case Trace::TYPE_SINT:
461 value = parse_sint();
463 case Trace::TYPE_UINT:
464 value = parse_uint();
466 case Trace::TYPE_FLOAT:
467 value = parse_float();
469 case Trace::TYPE_DOUBLE:
470 value = parse_double();
472 case Trace::TYPE_STRING:
473 value = parse_string();
475 case Trace::TYPE_ENUM:
476 value = parse_enum();
478 case Trace::TYPE_BITMASK:
479 value = parse_bitmask();
481 case Trace::TYPE_ARRAY:
482 value = parse_array();
484 case Trace::TYPE_STRUCT:
485 value = parse_struct();
487 case Trace::TYPE_BLOB:
488 value = parse_blob();
490 case Trace::TYPE_OPAQUE:
491 value = parse_opaque();
494 std::cerr << "error: unknown type " << c << "\n";
502 std::cerr << "\tVALUE " << value << "\n";
509 void Parser::scan_value(void) {
512 case Trace::TYPE_NULL:
513 case Trace::TYPE_FALSE:
514 case Trace::TYPE_TRUE:
516 case Trace::TYPE_SINT:
519 case Trace::TYPE_UINT:
522 case Trace::TYPE_FLOAT:
525 case Trace::TYPE_DOUBLE:
528 case Trace::TYPE_STRING:
531 case Trace::TYPE_ENUM:
534 case Trace::TYPE_BITMASK:
537 case Trace::TYPE_ARRAY:
540 case Trace::TYPE_STRUCT:
543 case Trace::TYPE_BLOB:
546 case Trace::TYPE_OPAQUE:
550 std::cerr << "error: unknown type " << c << "\n";
558 Value *Parser::parse_sint() {
559 return new SInt(-(signed long long)read_uint());
563 void Parser::scan_sint() {
568 Value *Parser::parse_uint() {
569 return new UInt(read_uint());
573 void Parser::scan_uint() {
578 Value *Parser::parse_float() {
580 file->read(&value, sizeof value);
581 return new Float(value);
585 void Parser::scan_float() {
586 file->skip(sizeof(float));
590 Value *Parser::parse_double() {
592 file->read(&value, sizeof value);
593 return new Float(value);
597 void Parser::scan_double() {
598 file->skip(sizeof(double));
602 Value *Parser::parse_string() {
603 return new String(read_string());
607 void Parser::scan_string() {
612 Value *Parser::parse_enum() {
613 EnumSig *sig = parse_enum_sig();
614 return new Enum(sig);
618 void Parser::scan_enum() {
623 Value *Parser::parse_bitmask() {
624 BitmaskSig *sig = parse_bitmask_sig();
626 unsigned long long value = read_uint();
628 return new Bitmask(sig, value);
632 void Parser::scan_bitmask() {
634 skip_uint(); /* value */
638 Value *Parser::parse_array(void) {
639 size_t len = read_uint();
640 Array *array = new Array(len);
641 for (size_t i = 0; i < len; ++i) {
642 array->values[i] = parse_value();
648 void Parser::scan_array(void) {
649 size_t len = read_uint();
650 for (size_t i = 0; i < len; ++i) {
656 Value *Parser::parse_blob(void) {
657 size_t size = read_uint();
658 Blob *blob = new Blob(size);
660 file->read(blob->buf, (unsigned)size);
666 void Parser::scan_blob(void) {
667 size_t size = read_uint();
674 Value *Parser::parse_struct() {
675 StructSig *sig = parse_struct_sig();
676 Struct *value = new Struct(sig);
678 for (size_t i = 0; i < sig->num_members; ++i) {
679 value->members[i] = parse_value();
686 void Parser::scan_struct() {
687 StructSig *sig = parse_struct_sig();
688 for (size_t i = 0; i < sig->num_members; ++i) {
694 Value *Parser::parse_opaque() {
695 unsigned long long addr;
697 return new Pointer(addr);
701 void Parser::scan_opaque() {
706 const char * Parser::read_string(void) {
707 size_t len = read_uint();
708 char * value = new char[len + 1];
710 file->read(value, (unsigned)len);
714 std::cerr << "\tSTRING \"" << value << "\"\n";
720 void Parser::skip_string(void) {
721 size_t len = read_uint();
726 unsigned long long Parser::read_uint(void) {
727 unsigned long long value = 0;
735 value |= (unsigned long long)(c & 0x7f) << shift;
739 std::cerr << "\tUINT " << value << "\n";
745 void Parser::skip_uint(void) {
756 inline int Parser::read_byte(void) {
757 int c = file->getc();
760 std::cerr << "\tEOF" << "\n";
762 std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
768 inline void Parser::skip_byte(void) {
773 } /* namespace Trace */