#define dprintf(...)
#endif
+void preset_field_type_size(event_t *event_type,
+ off_t offset_root, off_t offset_parent,
+ enum field_status *fixed_root, enum field_status *fixed_parent,
+ field_t *field);
/* Code printing */
case ARRAY:
dprintf("%s\n", basename);
assert(td->size >= 0);
- if(td->nested_type->type_name == NULL) {
+ if(((field_t*)td->fields.array[0])->type->type_name == NULL) {
/* Not a named nested type : we must print its declaration first */
- if(print_type_declaration(td->nested_type,
+ if(print_type_declaration(((field_t*)td->fields.array[0])->type,
fd, 0, basename, "")) return 1;
}
fprintf(fd, "#define LTTNG_ARRAY_SIZE_%s %llu\n", basename,
td->size);
fprintf(fd, "typedef ");
- if(print_type(td->nested_type, fd, tabs, basename, "")) return 1;
+ if(print_type(((field_t*)td->fields.array[0])->type,
+ fd, tabs, basename, "")) return 1;
fprintf(fd, " lttng_array_%s[LTTNG_ARRAY_SIZE_%s];\n", basename,
basename);
fprintf(fd, "\n");
break;
case SEQUENCE:
- if(td->nested_type->type_name == NULL) {
+ /* We assume that the sequence length type does not need to be declared.
+ */
+ if(((field_t*)td->fields.array[1])->type->type_name == NULL) {
/* Not a named nested type : we must print its declaration first */
- if(print_type_declaration(td->nested_type,
+ if(print_type_declaration(((field_t*)td->fields.array[1])->type,
fd, 0, basename, "")) return 1;
}
fprintf(fd, "typedef struct lttng_sequence_%s lttng_sequence_%s;\n",
print_tabs(1, fd);
fprintf(fd, "unsigned int len;\n");
print_tabs(1, fd);
- if(print_type(td->nested_type, fd, tabs, basename, "")) return 1;
+ if(print_type(((field_t*)td->fields.array[1])->type,
+ fd, tabs, basename, "")) return 1;
fprintf(fd, " *array;\n");
fprintf(fd, "};\n");
fprintf(fd, "\n");
return 0;
}
+
+
+
+
+/*****************************************************************************
+ *Function name
+ * set_named_type_offsets : set the precomputable offset of the named type
+ *Input params
+ * type : the type
+ ****************************************************************************/
+void set_named_type_offsets(type_descriptor_t *type)
+{
+ enum field_status current_child_status = FIELD_FIXED_GENEVENT;
+ off_t current_offset = 0;
+
+ preset_type_size(
+ current_offset,
+ ¤t_child_status,
+ type);
+ if(current_child_status == FIELD_FIXED_GENEVENT) {
+ current_offset += type->size;
+ } else {
+ current_offset = 0;
+ }
+}
+
+
+/*****************************************************************************
+ *Function name
+ * set_event_fields_offsets : set the precomputable offset of the fields
+ *Input params
+ * event : the event
+ ****************************************************************************/
+void set_event_fields_offsets(event_t *event)
+{
+ enum field_status current_child_status = FIELD_FIXED;
+ off_t current_offset = 0;
+
+ for(unsigned int i = 0; i < event->type->fields.position; i++) {
+ /* For each field, set the field offset. */
+ field_t *child_field = (field_t*)event->type->fields.array[i];
+ type_descriptor_t *t = f->type;
+ /* Skip named types */
+ if(t->type_name != NULL) continue;
+
+ preset_type_size(
+ current_offset,
+ ¤t_child_status,
+ t);
+ if(current_child_status == FIELD_FIXED_GENEVENT) {
+ current_offset += type->size;
+ } else {
+ current_offset = 0;
+ }
+ }
+}
+
+
+
+/*****************************************************************************
+ *Function name
+ * print_type_size : print the fixed sizes of the field type
+ * taken from LTTV.
+ *
+ * use offset_parent as offset to calculate alignment.
+ *Input params
+ * offset_parent : offset from the parent
+ * fixed_parent : Do we know a fixed offset to the parent ?
+ * type : type
+ ****************************************************************************/
+void print_type_size(
+ off_t offset_parent,
+ enum field_status *fixed_parent,
+ type_descriptor_t *type,
+ FILE *fd,
+ char *size_name)
+{
+ enum field_status local_fixed_parent;
+ guint i;
+
+ g_assert(type->fixed_size == FIELD_UNKNOWN);
+
+ size_t current_offset;
+ enum field_status current_child_status, final_child_status;
+ size_t max_size;
+
+ switch(type->type) {
+ /* type sizes known by genevent/compiler */
+ case INT_FIXED:
+ case UINT_FIXED:
+ case FLOAT:
+ case CHAR:
+ case UCHAR:
+ case SHORT:
+ case USHORT:
+ /* Align */
+ fprintf(fd, "%s += ltt_align(%s, %s)", size_name);
+ /* Data */
+ type->fixed_size = FIELD_FIXED_GENEVENT;
+ break;
+ /* host type sizes unknown by genevent, but known by the compiler */
+ case INT:
+ case UINT:
+ case ENUM:
+ /* An enum is either : char or int. In gcc, always int. Hope
+ * it's always like this. */
+ type->fixed_size = FIELD_FIXED_COMPILER;
+ type->compiler_size = COMPILER_INT;
+ break;
+ case LONG:
+ case ULONG:
+ type->fixed_size = FIELD_FIXED_COMPILER;
+ type->compiler_size = COMPILER_LONG;
+ break;
+ case POINTER:
+ type->fixed_size = FIELD_FIXED_COMPILER;
+ type->compiler_size = COMPILER_POINTER;
+ break;
+ case SIZE_T:
+ case SSIZE_T:
+ case OFF_T:
+ type->fixed_size = FIELD_FIXED_COMPILER;
+ type->compiler_size = COMPILER_SIZE_T;
+ break;
+ /* compound types :
+ * if all children has fixed size, then the parent size can be
+ * known directly and the copy can be done efficiently.
+ * if only part of the children has fixed size, then the contiguous
+ * elements will be copied in one bulk, but the variable size elements
+ * will be copied separately. This is necessary because those variable
+ * size elements are referenced by pointer in C.
+ */
+ case SEQUENCE:
+ current_offset = 0;
+ local_fixed_parent = FIELD_FIXED_GENEVENT;
+ preset_type_size(
+ 0,
+ &local_fixed_parent,
+ ((field_t*)type->fields.array[0])->type);
+ preset_field_type_size(
+ 0,
+ &local_fixed_parent,
+ ((field_t*)type->fields.array[1])->type);
+ type->fixed_size = FIELD_VARIABLE;
+ *fixed_parent = FIELD_VARIABLE;
+ break;
+ case LTT_STRING:
+ field->fixed_size = FIELD_VARIABLE;
+ *fixed_parent = FIELD_VARIABLE;
+ break;
+ case LTT_ARRAY:
+ local_fixed_parent = FIELD_FIXED_GENEVENT;
+ preset_type_size(
+ 0,
+ &local_fixed_parent,
+ ((field_t*)type->fields.array[0])->type);
+ type->fixed_size = local_fixed_parent;
+ if(type->fixed_size == FIELD_FIXED_GENEVENT) {
+ type->size =
+ type->element_number * ((field_t*)type->fields.array[0])->type->size;
+ } else if(type->fixed_size == FIELD_FIXED_COMPILER) {
+ type->size =
+ type->element_number;
+ } else {
+ type->size = 0;
+ *fixed_parent = FIELD_VARIABLE;
+ }
+ break;
+ case LTT_STRUCT:
+ current_offset = 0;
+ current_child_status = FIELD_FIXED_GENEVENT;
+ for(i=0;i<type->element_number;i++) {
+ preset_field_type_size(
+ current_offset,
+ ¤t_child_status,
+ ((field_t*)type->fields.array[i])->type);
+ if(current_child_status == FIELD_FIXED_GENEVENT) {
+ current_offset += field->child[i]->field_size;
+ } else {
+ current_offset = 0;
+ }
+ }
+ if(current_child_status != FIELD_FIXED_GENEVENT) {
+ *fixed_parent = current_child_status;
+ type->size = 0;
+ type->fixed_size = current_child_status;
+ } else {
+ type->size = current_offset;
+ type->fixed_size = FIELD_FIXED_GENEVENT;
+ }
+ break;
+ case LTT_UNION:
+ current_offset = 0;
+ max_size = 0;
+ final_child_status = FIELD_FIXED_GENEVENT;
+ for(i=0;i<type->element_number;i++) {
+ enum field_status current_child_status = FIELD_FIXED;
+ preset_field_type_size(
+ current_offset,
+ ¤t_child_status,
+ ((field_t*)type->fields.array[i])->type);
+ if(current_child_status != FIELD_FIXED_GENEVENT)
+ final_child_status = current_child_status;
+ else
+ max_size =
+ max(max_size, ((field_t*)type->fields.array[i])->type->size);
+ }
+ if(final_child_status != FIELD_FIXED_GENEVENT AND COMPILER) {
+ g_error("LTTV does not support variable size fields in unions.");
+ /* This will stop the application. */
+ *fixed_parent = final_child_status;
+ type->size = 0;
+ type->fixed_size = current_child_status;
+ } else {
+ type->size = max_size;
+ type->fixed_size = FIELD_FIXED_GENEVENT;
+ }
+ break;
+ }
+
+}
+
+
+size_t get_field_type_size(LttTracefile *tf, LttEventType *event_type,
+ off_t offset_root, off_t offset_parent,
+ LttField *field, void *data)
+{
+ size_t size = 0;
+ guint i;
+ LttType *type;
+
+ g_assert(field->fixed_root != FIELD_UNKNOWN);
+ g_assert(field->fixed_parent != FIELD_UNKNOWN);
+ g_assert(field->fixed_size != FIELD_UNKNOWN);
+
+ field->offset_root = offset_root;
+ field->offset_parent = offset_parent;
+
+ type = field->field_type;
+
+ switch(type->type_class) {
+ case LTT_INT:
+ case LTT_UINT:
+ case LTT_FLOAT:
+ case LTT_ENUM:
+ case LTT_POINTER:
+ case LTT_LONG:
+ case LTT_ULONG:
+ case LTT_SIZE_T:
+ case LTT_SSIZE_T:
+ case LTT_OFF_T:
+ g_assert(field->fixed_size == FIELD_FIXED);
+ size = field->field_size;
+ break;
+ case LTT_SEQUENCE:
+ {
+ gint seqnum = ltt_get_uint(LTT_GET_BO(tf),
+ field->sequ_number_size,
+ data + offset_root);
+
+ if(field->child[0]->fixed_size == FIELD_FIXED) {
+ size = field->sequ_number_size +
+ (seqnum * get_field_type_size(tf, event_type,
+ offset_root, offset_parent,
+ field->child[0], data));
+ } else {
+ size += field->sequ_number_size;
+ for(i=0;i<seqnum;i++) {
+ size_t child_size;
+ child_size = get_field_type_size(tf, event_type,
+ offset_root, offset_parent,
+ field->child[0], data);
+ offset_root += child_size;
+ offset_parent += child_size;
+ size += child_size;
+ }
+ }
+ field->field_size = size;
+ }
+ break;
+ case LTT_STRING:
+ size = strlen((char*)(data+offset_root)) + 1;// length + \0
+ field->field_size = size;
+ break;
+ case LTT_ARRAY:
+ if(field->fixed_size == FIELD_FIXED)
+ size = field->field_size;
+ else {
+ for(i=0;i<field->field_type->element_number;i++) {
+ size_t child_size;
+ child_size = get_field_type_size(tf, event_type,
+ offset_root, offset_parent,
+ field->child[0], data);
+ offset_root += child_size;
+ offset_parent += child_size;
+ size += child_size;
+ }
+ field->field_size = size;
+ }
+ break;
+ case LTT_STRUCT:
+ if(field->fixed_size == FIELD_FIXED)
+ size = field->field_size;
+ else {
+ size_t current_root_offset = offset_root;
+ size_t current_offset = 0;
+ size_t child_size = 0;
+ for(i=0;i<type->element_number;i++) {
+ child_size = get_field_type_size(tf,
+ event_type, current_root_offset, current_offset,
+ field->child[i], data);
+ current_offset += child_size;
+ current_root_offset += child_size;
+
+ }
+ size = current_offset;
+ field->field_size = size;
+ }
+ break;
+ case LTT_UNION:
+ if(field->fixed_size == FIELD_FIXED)
+ size = field->field_size;
+ else {
+ size_t current_root_offset = field->offset_root;
+ size_t current_offset = 0;
+ for(i=0;i<type->element_number;i++) {
+ size = get_field_type_size(tf, event_type,
+ current_root_offset, current_offset,
+ field->child[i], data);
+ size = max(size, field->child[i]->field_size);
+ }
+ field->field_size = size;
+ }
+ break;
+ }
+
+ return size;
+}
+
+
+
+
+
+/* Print the code that calculates the length of an field */
+int print_field_len(type_descriptor_t * td, FILE *fd, unsigned int tabs,
+ char *nest_type_name, char *nest_field_name, char *field_name,
+ char *output_var, char *member_var)
+{
+ /* Type name : basename */
+ char basename[PATH_MAX];
+ unsigned int basename_len = 0;
+
+ strcpy(basename, nest_type_name);
+ basename_len = strlen(basename);
+
+ /* For a named type, we use the type_name directly */
+ if(td->type_name != NULL) {
+ strncpy(basename, td->type_name, PATH_MAX);
+ basename_len = strlen(basename);
+ } else {
+ /* For a unnamed type, there must be a field name */
+ if((basename_len != 0)
+ && (basename[basename_len-1] != '_')
+ && (field_name[0] != '\0')) {
+ strncat(basename, "_", PATH_MAX - basename_len);
+ basename_len = strlen(basename);
+ }
+ strncat(basename, field_name, PATH_MAX - basename_len);
+ }
+
+ /* Field name : basefieldname */
+ char basefieldname[PATH_MAX];
+ unsigned int basefieldname_len = 0;
+
+ strcpy(basefieldname, nest_field_name);
+ basefieldname_len = strlen(basefieldname);
+
+ /* there must be a field name */
+ strncat(basefieldname, field_name, PATH_MAX - basefieldname_len);
+ basefieldname_len = strlen(basefieldname);
+
+ print_tabs(tabs, fd);
+
+ switch(td->type) {
+ case INT_FIXED:
+ case UINT_FIXED:
+ case CHAR:
+ case UCHAR:
+ case SHORT:
+ case USHORT:
+ case INT:
+ case UINT:
+ case FLOAT:
+ case POINTER:
+ case LONG:
+ case ULONG:
+ case SIZE_T:
+ case SSIZE_T:
+ case OFF_T:
+ case ENUM:
+ fprintf(fd, "/* Size of %s */", field_name);
+ print_tabs(tabs, fd);
+ fprintf(fd, "%s = sizeof(", member_var);
+ if(print_type(td, fd, tabs, basename, "")) return 1;
+ fprintf(fd, ");\n");
+ fprintf(fd, "%s += ltt_align(%s, %s);\n", output_var, member_var);
+ print_tabs(tabs, fd);
+ fprintf(fd, "%s += %s;\n", output_var, member_var);
+ break;
+ case STRING:
+ /* strings are made of bytes : no alignment. */
+ fprintf(fd, "/* Size of %s */", basefieldname);
+ print_tabs(tabs, fd);
+ fprintf(fd, "%s = strlen(%s);", member_var, basefieldname);
+ break;
+ case ARRAY:
+ fprintf(fd, "/* Size of %s */", basefieldname);
+ print_tabs(tabs, fd);
+
+ strncat(basefieldname, ".", PATH_MAX - basefieldname_len);
+ basefieldname_len = strlen(basefieldname);
+
+ if(print_field_len(((field_t*)td->fields.array[0])->type,
+ fd, tabs,
+ basename, basefieldname,
+ output_var, member_var)) return 1;
+
+ fprintf(fd, "%s = strlen(%s);", member_var, basefieldname);
+
+ fprintf(fd, "lttng_array_%s", basename);
+ fprintf(fd, " %s", field_name);
+ break;
+ case SEQUENCE:
+ fprintf(fd, "lttng_sequence_%s *", basename);
+ fprintf(fd, " %s", field_name);
+ break;
+ case STRUCT:
+ fprintf(fd, "struct lttng_%s *", basename);
+ fprintf(fd, " %s", field_name);
+ break;
+ case UNION:
+ fprintf(fd, "union lttng_%s *", basename);
+ fprintf(fd, " %s", field_name);
+ break;
+ default:
+ printf("print_type : unknown type\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
/* Print the logging function of an event. This is the core of genevent */
int print_event_logging_function(char *basename, event_t *event, FILE *fd)
{
fprintf(fd,"#else\n");
fprintf(fd, "{\n");
/* Print the function variables */
+ print_tabs(1, fd);
+ fprintf(fd, "size_t member_length;");
+ fprintf(fd, "size_t event_length = 0;");
- /* Calculate event variable len + event alignment offset.
+ /* Calculate event variable len + event data alignment offset.
* Assume that the padding for alignment starts at a void*
- * address. */
+ * address.
+ * This excludes the header size and alignment. */
+
+
+ for(unsigned int j = 0; j < event->fields.position; j++) {
+ /* For each field, calculate the field size. */
+ field_t *f = (field_t*)event->fields.array[j];
+ type_descriptor_t *t = f->type;
+ if(print_field_len(t, fd, 1, basename, "",
+ f->name,
+ "event_length",
+ "member_length")) return 1;
+ if(j < event->fields.position-1) {
+ fprintf(fd, ",");
+ fprintf(fd, "\n");
+ }
+ }
/* Take locks : make sure the trace does not vanish while we write on
* it. A simple preemption disabling is enough (using rcu traces). */
checkNamedTypesImplemented(&fac->named_types);
generateChecksum(fac->name, &checksum, &fac->events);
-
+
generated = TRUE;
}
else {