]> git.cworth.org Git - apitrace/blob - cli/cli_pickle.cpp
cli: Fix invalid option message.
[apitrace] / cli / cli_pickle.cpp
1 /**************************************************************************
2  *
3  * Copyright 2012 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <string.h>
28 #include <limits.h> // for CHAR_MAX
29 #include <getopt.h>
30
31 #include "pickle.hpp"
32
33 #include "os_binary.hpp"
34
35 #include "cli.hpp"
36 #include "cli_pager.hpp"
37
38 #include "trace_parser.hpp"
39 #include "trace_model.hpp"
40 #include "trace_callset.hpp"
41
42
43 using namespace trace;
44
45
46 class PickleVisitor : public trace::Visitor
47 {
48 protected:
49     PickleWriter &writer;
50     bool symbolic;
51
52 public:
53     PickleVisitor(PickleWriter &_writer, bool _symbolic) :
54         writer(_writer),
55         symbolic(_symbolic) {
56     }
57
58     void visit(Null *node) {
59         writer.writeInt(0);
60     }
61
62     void visit(Bool *node) {
63         writer.writeBool(node->value);
64     }
65
66     void visit(SInt *node) {
67         writer.writeInt(node->value);
68     }
69
70     void visit(UInt *node) {
71         writer.writeInt(node->value);
72     }
73
74     void visit(Float *node) {
75         writer.writeFloat(node->value);
76     }
77
78     void visit(Double *node) {
79         writer.writeFloat(node->value);
80     }
81
82     void visit(String *node) {
83         writer.writeString(node->value);
84     }
85
86     void visit(Enum *node) {
87         if (symbolic) {
88             const EnumValue *it = node->lookup();
89             if (it) {
90                 writer.writeString(it->name);
91                 return;
92             }
93         }
94         writer.writeInt(node->value);
95     }
96
97     void visit(Bitmask *node) {
98         if (symbolic) {
99             unsigned long long value = node->value;
100             const BitmaskSig *sig = node->sig;
101             writer.beginList();
102             for (const BitmaskFlag *it = sig->flags; it != sig->flags + sig->num_flags; ++it) {
103                 if ((it->value && (value & it->value) == it->value) ||
104                     (!it->value && value == 0)) {
105                     writer.writeString(it->name);
106                     value &= ~it->value;
107                 }
108                 if (value == 0) {
109                     break;
110                 }
111             }
112             if (value) {
113                 writer.writeInt(value);
114             }
115             writer.endList();
116         } else {
117             writer.writeInt(node->value);
118         }
119     }
120
121     void visit(Struct *node) {
122         if (false) {
123             writer.beginDict();
124             for (unsigned i = 0; i < node->sig->num_members; ++i) {
125                 writer.beginItem(node->sig->member_names[i]);
126                 _visit(node->members[i]);
127                 writer.endItem();
128             }
129             writer.endDict();
130         } else {
131             writer.beginTuple();
132             for (unsigned i = 0; i < node->sig->num_members; ++i) {
133                 _visit(node->members[i]);
134             }
135             writer.endTuple();
136         }
137     }
138
139     void visit(Array *node) {
140         writer.beginList();
141         for (std::vector<Value *>::iterator it = node->values.begin(); it != node->values.end(); ++it) {
142             _visit(*it);
143         }
144         writer.endList();
145     }
146
147     void visit(Blob *node) {
148         writer.writeByteArray(node->buf, node->size);
149     }
150
151     void visit(Pointer *node) {
152         writer.writeInt(node->value);
153     }
154
155     void visit(Repr *r) {
156         if (symbolic) {
157             _visit(r->humanValue);
158         } else {
159             _visit(r->machineValue);
160         }
161     }
162
163     void visit(Call *call) {
164         writer.beginTuple();
165
166         writer.writeInt(call->no);
167
168         writer.writeString(call->name());
169
170         writer.beginList();
171         for (unsigned i = 0; i < call->args.size(); ++i) {
172             if (call->args[i].value) {
173                 _visit(call->args[i].value);
174             } else {
175                 writer.writeNone();
176             }
177         }
178         writer.endList();
179
180         if (call->ret) {
181             _visit(call->ret);
182         } else {
183             writer.writeNone();
184         }
185
186         writer.endTuple();
187     }
188 };
189
190
191 static trace::CallSet calls(trace::FREQUENCY_ALL);
192
193 static const char *synopsis = "Pickle given trace(s) to standard output.";
194
195 static void
196 usage(void)
197 {
198     std::cout
199         << "usage: apitrace pickle [OPTIONS] TRACE_FILE...\n"
200         << synopsis << "\n"
201         "\n"
202         "    -h, --help           show this help message and exit\n"
203         "    -s, --symbolic       dump symbolic names\n"
204         "    --calls=CALLSET      only dump specified calls\n"
205     ;
206 }
207
208 enum {
209         CALLS_OPT = CHAR_MAX + 1,
210 };
211
212 const static char *
213 shortOptions = "hs";
214
215 const static struct option
216 longOptions[] = {
217     {"help", no_argument, 0, 'h'},
218     {"symbolic", no_argument, 0, 's'},
219     {"calls", required_argument, 0, CALLS_OPT},
220     {0, 0, 0, 0}
221 };
222
223 static int
224 command(int argc, char *argv[])
225 {
226     bool symbolic;
227
228     int opt;
229     while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
230         switch (opt) {
231         case 'h':
232             usage();
233             return 0;
234         case 's':
235             symbolic = true;
236             break;
237         case CALLS_OPT:
238             calls = trace::CallSet(optarg);
239             break;
240         default:
241             std::cerr << "error: unexpected option `" << (char)opt << "`\n";
242             usage();
243             return 1;
244         }
245     }
246
247     os::setBinaryMode(stdout);
248     
249     std::cout.sync_with_stdio(false);
250
251     PickleWriter writer(std::cout);
252     PickleVisitor visitor(writer, symbolic);
253
254     for (int i = optind; i < argc; ++i) {
255         trace::Parser parser;
256
257         if (!parser.open(argv[i])) {
258             return 1;
259         }
260
261         trace::Call *call;
262         while ((call = parser.parse_call())) {
263             if (calls.contains(*call)) {
264                 writer.begin();
265                 visitor.visit(call);
266                 writer.end();
267             }
268             delete call;
269         }
270     }
271
272     return 0;
273 }
274
275 const Command pickle_command = {
276     "pickle",
277     synopsis,
278     usage,
279     command
280 };