]> git.cworth.org Git - apitrace/blob - cli/cli_pickle.cpp
Pickle blobs as bytearrays.
[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(Call *call) {
156         writer.beginTuple();
157
158         writer.writeInt(call->no);
159
160         writer.writeString(call->name());
161
162         writer.beginList();
163         for (unsigned i = 0; i < call->args.size(); ++i) {
164             if (call->args[i].value) {
165                 _visit(call->args[i].value);
166             } else {
167                 writer.writeNone();
168             }
169         }
170         writer.endList();
171
172         if (call->ret) {
173             _visit(call->ret);
174         } else {
175             writer.writeNone();
176         }
177
178         writer.endTuple();
179     }
180 };
181
182
183 static trace::CallSet calls(trace::FREQUENCY_ALL);
184
185 static const char *synopsis = "Pickle given trace(s) to standard output.";
186
187 static void
188 usage(void)
189 {
190     std::cout
191         << "usage: apitrace pickle [OPTIONS] TRACE_FILE...\n"
192         << synopsis << "\n"
193         "\n"
194         "    -h, --help           show this help message and exit\n"
195         "    -s, --symbolic       dump symbolic names\n"
196         "    --calls=CALLSET      only dump specified calls\n"
197     ;
198 }
199
200 enum {
201         CALLS_OPT = CHAR_MAX + 1,
202 };
203
204 const static char *
205 shortOptions = "hs";
206
207 const static struct option
208 longOptions[] = {
209     {"help", no_argument, 0, 'h'},
210     {"symbolic", no_argument, 0, 's'},
211     {"calls", required_argument, 0, CALLS_OPT},
212     {0, 0, 0, 0}
213 };
214
215 static int
216 command(int argc, char *argv[])
217 {
218     bool symbolic;
219
220     int opt;
221     while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
222         switch (opt) {
223         case 'h':
224             usage();
225             return 0;
226         case 's':
227             symbolic = true;
228             break;
229         case CALLS_OPT:
230             calls = trace::CallSet(optarg);
231             break;
232         default:
233             std::cerr << "error: unexpected option `" << opt << "`\n";
234             usage();
235             return 1;
236         }
237     }
238
239     os::setBinaryMode(stdout);
240     
241     PickleWriter writer(std::cout);
242     PickleVisitor visitor(writer, symbolic);
243
244     for (int i = optind; i < argc; ++i) {
245         trace::Parser parser;
246
247         if (!parser.open(argv[i])) {
248             std::cerr << "error: failed to open " << argv[i] << "\n";
249             return 1;
250         }
251
252         trace::Call *call;
253         while ((call = parser.parse_call())) {
254             if (calls.contains(*call)) {
255                 writer.begin();
256                 visitor.visit(call);
257                 writer.end();
258             }
259             delete call;
260         }
261     }
262
263     return 0;
264 }
265
266 const Command pickle_command = {
267     "pickle",
268     synopsis,
269     usage,
270     command
271 };