diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2017-01-10 16:45:52 +0100 |
|---|---|---|
| committer | Andrey Konovalov <andreyknvl@google.com> | 2017-01-17 13:25:33 +0100 |
| commit | 54e0cede4384b7c1655f9183577bfccc11d9a7d5 (patch) | |
| tree | 68e1f734a5e82ac7ecbe2968942d9983650ed8f8 /executor | |
| parent | f6c7b90523285663e51fc6804ae2c0c171bb390c (diff) | |
prog: add bitfields to templates
Now it's possible to use `int32:18` to denote a bitfield of size 18 as a struct field.
This fixes #72.
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common.h | 12 | ||||
| -rw-r--r-- | executor/executor.cc | 21 |
2 files changed, 25 insertions, 8 deletions
diff --git a/executor/common.h b/executor/common.h index 004dcc341..40b2bf8d0 100644 --- a/executor/common.h +++ b/executor/common.h @@ -158,6 +158,18 @@ static void install_segv_handler() __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } +#define BITMASK_LEN(type, bf_len) (type)((1ul << bf_len) - 1) + +#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, bf_len) << bf_off) + +#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \ + do { \ + type new_val = *(type*)addr; \ + new_val &= ~BITMASK_LEN_OFF(type, bf_off, bf_len); \ + new_val |= ((type)val & BITMASK_LEN(type, bf_len)) << bf_off; \ + *(type*)addr = new_val; \ + } while (0) + #ifdef __NR_syz_emit_ethernet static void vsnprintf_check(char* str, size_t size, const char* format, va_list args) { diff --git a/executor/executor.cc b/executor/executor.cc index 94658a5cc..22eea9439 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -117,7 +117,7 @@ uint64_t read_input(uint64_t** input_posp, bool peek = false); uint64_t read_arg(uint64_t** input_posp); uint64_t read_result(uint64_t** input_posp); void write_output(uint32_t v); -void copyin(char* addr, uint64_t val, uint64_t size); +void copyin(char* addr, uint64_t val, uint64_t size, uint64_t bf_off, uint64_t bf_len); uint64_t copyout(char* addr, uint64_t size); thread_t* schedule_call(int n, int call_index, int call_num, uint64_t num_args, uint64_t* args, uint64_t* pos); void execute_call(thread_t* th); @@ -299,12 +299,14 @@ retry: switch (typ) { case arg_const: { uint64_t arg = read_input(&input_pos); - copyin(addr, arg, size); + uint64_t bf_off = read_input(&input_pos); + uint64_t bf_len = read_input(&input_pos); + copyin(addr, arg, size, bf_off, bf_len); break; } case arg_result: { uint64_t val = read_result(&input_pos); - copyin(addr, val, size); + copyin(addr, val, size, 0, 0); break; } case arg_data: { @@ -586,20 +588,20 @@ uint64_t cover_dedup(thread_t* th, uint64_t n) return w; } -void copyin(char* addr, uint64_t val, uint64_t size) +void copyin(char* addr, uint64_t val, uint64_t size, uint64_t bf_off, uint64_t bf_len) { NONFAILING(switch (size) { case 1: - *(uint8_t*)addr = val; + STORE_BY_BITMASK(uint8_t, addr, val, bf_off, bf_len); break; case 2: - *(uint16_t*)addr = val; + STORE_BY_BITMASK(uint16_t, addr, val, bf_off, bf_len); break; case 4: - *(uint32_t*)addr = val; + STORE_BY_BITMASK(uint32_t, addr, val, bf_off, bf_len); break; case 8: - *(uint64_t*)addr = val; + STORE_BY_BITMASK(uint64_t, addr, val, bf_off, bf_len); break; default: fail("copyin: bad argument size %lu", size); @@ -637,6 +639,9 @@ uint64_t read_arg(uint64_t** input_posp) switch (typ) { case arg_const: { arg = read_input(input_posp); + // Bitfields can't be args of a normal syscall, so just ignore them. + read_input(input_posp); // bit field offset + read_input(input_posp); // bit field length break; } case arg_result: { |
