1 /* Sysprof -- Sampling, systemwide CPU profiler
2 * Copyright 2006, 2007, Soeren Sandmann
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "binparser.h"
22 typedef struct Field Field
;
30 const char * error_msg
;
39 char name
[BIN_MAX_NAME
];
40 guint offset
; /* from beginning of struct */
52 bin_parser_new (const guchar
*data
,
55 BinParser
*parser
= g_new0 (BinParser
, 1);
58 parser
->length
= length
;
60 parser
->error_msg
= NULL
;
61 parser
->records
= NULL
;
62 parser
->endian
= BIN_NATIVE_ENDIAN
;
68 bin_parser_free (BinParser
*parser
)
72 for (list
= parser
->records
; list
!= NULL
; list
= list
->next
)
74 BinRecord
*record
= list
->data
;
79 g_list_free (parser
->records
);
85 bin_parser_get_data (BinParser
*parser
)
91 bin_parser_get_length (BinParser
*parser
)
93 return parser
->length
;
97 align (guint64 offset
, int alignment
)
99 /* Note that we can speed this up by assuming alignment'
100 * is a power of two, since
102 * offset % alignment == offset & (alignemnt - 1)
106 if (offset
% alignment
!= 0)
107 offset
+= (alignment
- (offset
% alignment
));
113 get_align (const BinField
*field
)
115 if (field
->type
== BIN_UNINTERPRETED
)
118 return field
->n_bytes
;
122 bin_parser_create_record (BinParser
*parser
,
123 const BinField
*fields
)
130 while (fields
[n_fields
].name
[0] != '\0')
134 g_print ("type: %d\n", fields
[n_fields
].type
);
138 record
= g_malloc0 (sizeof (BinRecord
) +
139 (n_fields
- 1) * sizeof (Field
));
142 record
->n_fields
= n_fields
;
143 for (i
= 0; i
< n_fields
; ++i
)
145 const BinField
*bin_field
= &(fields
[i
]);
146 Field
*field
= &(record
->fields
[i
]);
148 offset
= align (offset
, get_align (bin_field
));
150 strncpy (field
->name
, bin_field
->name
, BIN_MAX_NAME
- 1);
151 field
->offset
= offset
;
152 field
->type
= bin_field
->type
;
153 field
->width
= bin_field
->n_bytes
;
155 offset
+= record
->fields
[i
].width
;
158 parser
->records
= g_list_prepend (parser
->records
, record
);
164 bin_parser_error (BinParser
*parser
)
166 return parser
->error_msg
!= NULL
;
170 bin_parser_clear_error (BinParser
*parser
)
172 parser
->error_msg
= NULL
;
176 bin_parser_get_error_msg (BinParser
*parser
)
178 return parser
->error_msg
;
182 bin_parser_set_endian (BinParser
*parser
,
185 parser
->endian
= endian
;
188 /* Move current offset */
190 bin_parser_get_offset (BinParser
*parser
)
192 return parser
->offset
;
196 bin_parser_set_offset (BinParser
*parser
,
199 parser
->offset
= offset
;
203 bin_parser_align (BinParser
*parser
,
206 parser
->offset
= align (parser
->offset
, byte_width
);
210 bin_record_get_size (BinRecord
*record
)
212 Field
*last_field
= &(record
->fields
[record
->n_fields
- 1]);
213 Field
*first_field
= &(record
->fields
[0]);
215 /* align to first field, since that's the alignment of the record
219 return align (last_field
->offset
+ last_field
->width
, first_field
->width
);
223 bin_parser_seek_record (BinParser
*parser
,
227 gsize record_size
= bin_record_get_size (record
);
229 parser
->offset
+= record_size
* n_records
;
233 bin_parser_save (BinParser
*parser
)
235 parser
->saved_offset
= parser
->offset
;
239 bin_parser_restore (BinParser
*parser
)
241 parser
->offset
= parser
->saved_offset
;
246 convert_uint (const guchar
*data
,
257 g_print ("converting at %p %d %d %d %d\n", data
, data
[0], data
[1], data
[2], data
[3]);
260 /* FIXME: check that we are within the file */
265 r8
= *(guint8
*)data
;
269 r16
= *(guint16
*)data
;
271 if (endian
== BIN_BIG_ENDIAN
)
272 r16
= GUINT16_FROM_BE (r16
);
273 else if (endian
== BIN_LITTLE_ENDIAN
)
274 r16
= GUINT16_FROM_LE (r16
);
279 r32
= *(guint32
*)data
;
281 if (endian
== BIN_BIG_ENDIAN
)
282 r32
= GUINT32_FROM_BE (r32
);
283 else if (endian
== BIN_LITTLE_ENDIAN
)
284 r32
= GUINT32_FROM_LE (r32
);
289 r64
= *(guint64
*)data
;
291 if (endian
== BIN_BIG_ENDIAN
)
292 r64
= GUINT64_FROM_BE (r64
);
293 else if (endian
== BIN_LITTLE_ENDIAN
)
294 r64
= GUINT64_FROM_LE (r64
);
299 g_assert_not_reached();
305 bin_parser_get_uint (BinParser
*parser
,
308 guint64 r
= convert_uint (parser
->data
+ parser
->offset
, parser
->endian
, width
);
310 parser
->offset
+= width
;
316 bin_parser_get_string (BinParser
*parser
)
320 /* FIXME: check that the string is within the file */
322 result
= (const char *)parser
->data
+ parser
->offset
;
324 parser
->offset
+= strlen (result
) + 1;
331 get_field (BinRecord
*format
,
336 for (i
= 0; i
< format
->n_fields
; ++i
)
338 Field
*field
= &(format
->fields
[i
]);
340 if (strcmp (field
->name
, name
) == 0)
343 g_print ("found field: %s (offset: %d, type %d)\n", field
->name
, field
->offset
, field
->type
);
355 bin_parser_get_uint_field (BinParser
*parser
,
359 const Field
*field
= get_field (record
, name
);
363 g_print ("moving to %d (%d + %d)\n", parser
->offset
+ field
->offset
, parser
->offset
, field
->offset
);
366 pos
= parser
->data
+ parser
->offset
+ field
->offset
;
369 g_print (" record offset: %d\n", record
->offset
);
370 g_print (" record index: %d\n", record
->index
);
371 g_print (" field offset %d\n", field
->offset
);
374 if (pos
> parser
->data
+ parser
->length
)
376 /* FIXME: generate error */
381 g_print (" uint %d at %p => %d\n", field
->width
, pos
, convert_uint (pos
, record
->format
->big_endian
, field
->width
));
384 return convert_uint (pos
, parser
->endian
, field
->width
);