Commit 7c489469 authored by Yonghong Song's avatar Yonghong Song

adjust tracepoint field type based on size

Fix issue #1807

tracepoint may have a format like this:
(from syscalls/sys_enter_socket)
	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
	field:unsigned char common_flags;	offset:2;	size:1;	signed:0;
	field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0;
	field:int common_pid;	offset:4;	size:4;	signed:1;

	field:int __syscall_nr;	offset:8;	size:4;	signed:1;
	field:int family;	offset:16;	size:8;	signed:0;
	field:int type;	offset:24;	size:8;	signed:0;
	field:int protocol;	offset:32;	size:8;	signed:0;

Current rewriter generates:
    struct tracepoint__syscalls__sys_enter_socket {
	    u64 __do_not_use__;
	    int __syscall_nr;
	    int family;
	    int type;
	    int protocol;
    };

This is incorrect as in the above structure, offsets of
`family`/`type`/`procotol` becomingg 12/16/20.

This patch fixed the issue by adjusting field type based on its size.
The new structure:
    struct tracepoint__syscalls__sys_enter_socket {
	    u64 __do_not_use__;
	    int __syscall_nr;
	    s64 family;
	    s64 type;
	    s64 protocol;
    };
The offsets of all fields are correct now.
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
parent 62af0eac
......@@ -62,7 +62,15 @@ static inline field_kind_t _get_field_kind(string const& line,
if (field_pos == string::npos)
return field_kind_t::invalid;
auto semi_pos = line.find(';', field_pos);
auto field_semi_pos = line.find(';', field_pos);
if (field_semi_pos == string::npos)
return field_kind_t::invalid;
auto offset_pos = line.find("offset:", field_semi_pos);
if (offset_pos == string::npos)
return field_kind_t::invalid;
auto semi_pos = line.find(';', offset_pos);
if (semi_pos == string::npos)
return field_kind_t::invalid;
......@@ -70,8 +78,16 @@ static inline field_kind_t _get_field_kind(string const& line,
if (size_pos == string::npos)
return field_kind_t::invalid;
semi_pos = line.find(';', size_pos);
if (semi_pos == string::npos)
return field_kind_t::invalid;
auto size_str = line.substr(size_pos + 5,
semi_pos - size_pos - 5);
int size = std::stoi(size_str, nullptr);
auto field = line.substr(field_pos + 6/*"field:"*/,
semi_pos - field_pos - 6);
field_semi_pos - field_pos - 6);
auto pos = field.find_last_of("\t ");
if (pos == string::npos)
return field_kind_t::invalid;
......@@ -83,6 +99,32 @@ static inline field_kind_t _get_field_kind(string const& line,
if (field_name.find("common_") == 0)
return field_kind_t::common;
// adjust the field_type based on the size of field
// otherwise, incorrect value may be retrieved for big endian
// and the field may have incorrect structure offset.
if (size == 2) {
if (field_type == "char" || field_type == "int8_t")
field_type = "s16";
if (field_type == "unsigned char" || field_type == "uint8_t")
field_type = "u16";
} else if (size == 4) {
if (field_type == "char" || field_type == "short" ||
field_type == "int8_t" || field_type == "int16_t")
field_type = "s32";
if (field_type == "unsigned char" || field_type == "unsiggned short" ||
field_type == "uint8_t" || field_type == "uint16_t")
field_type = "u32";
} else if (size == 8) {
if (field_type == "char" || field_type == "short" || field_type == "int" ||
field_type == "int8_t" || field_type == "int16_t" ||
field_type == "int32_t")
field_type = "s64";
if (field_type == "unsigned char" || field_type == "unsiggned short" ||
field_type == "unsigned int" || field_type == "uint8_t" ||
field_type == "uint16_t" || field_type == "uint32_t")
field_type = "u64";
}
return field_kind_t::regular;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment