From 62dc3eda871827b333f7b75a8393472b8c02f1bf Mon Sep 17 00:00:00 2001 From: Lourival Vieira Neto Date: Sun, 7 Sep 2014 18:14:16 -0300 Subject: [PATCH 4/5] lua: added luadata kernel module --- distrib/sets/lists/modules/md.evbppc.powerpc | 4 + distrib/sets/lists/modules/mi | 2 + lib/lua/data/Makefile | 16 ++ lib/lua/data/binary.c | 187 ++++++++++++++ lib/lua/data/binary.h | 52 ++++ lib/lua/data/ctest.lua | 22 ++ lib/lua/data/data.c | 276 +++++++++++++++++++++ lib/lua/data/data.h | 76 ++++++ lib/lua/data/handle.c | 159 ++++++++++++ lib/lua/data/handle.h | 77 ++++++ lib/lua/data/layout.c | 199 +++++++++++++++ lib/lua/data/layout.h | 65 +++++ lib/lua/data/luadata.c | 353 +++++++++++++++++++++++++++ lib/lua/data/luadata.h | 52 ++++ lib/lua/data/luautil.c | 104 ++++++++ lib/lua/data/luautil.h | 63 +++++ lib/lua/data/test.c | 93 +++++++ lib/lua/data/test.lua | 142 +++++++++++ sys/modules/Makefile | 1 + sys/modules/luadata/Makefile | 17 ++ 20 files changed, 1960 insertions(+) create mode 100644 lib/lua/data/Makefile create mode 100644 lib/lua/data/binary.c create mode 100644 lib/lua/data/binary.h create mode 100644 lib/lua/data/ctest.lua create mode 100644 lib/lua/data/data.c create mode 100644 lib/lua/data/data.h create mode 100644 lib/lua/data/handle.c create mode 100644 lib/lua/data/handle.h create mode 100644 lib/lua/data/layout.c create mode 100644 lib/lua/data/layout.h create mode 100644 lib/lua/data/luadata.c create mode 100644 lib/lua/data/luadata.h create mode 100644 lib/lua/data/luautil.c create mode 100644 lib/lua/data/luautil.h create mode 100644 lib/lua/data/test.c create mode 100644 lib/lua/data/test.lua create mode 100644 sys/modules/luadata/Makefile diff --git a/distrib/sets/lists/modules/md.evbppc.powerpc b/distrib/sets/lists/modules/md.evbppc.powerpc index 449cace..605b4ad9 100644 --- a/distrib/sets/lists/modules/md.evbppc.powerpc +++ b/distrib/sets/lists/modules/md.evbppc.powerpc @@ -116,6 +116,8 @@ ./stand/powerpc-4xx/@OSRELEASE@/modules/lua/lua.kmod base-kernel-modules kmod,compatmodules ./stand/powerpc-4xx/@OSRELEASE@/modules/luacore base-obsolete obsolete ./stand/powerpc-4xx/@OSRELEASE@/modules/luacore/luacore.kmod base-obsolete obsolete +./stand/powerpc-4xx/@OSRELEASE@/modules/luadata base-kernel-modules kmod,compatmodules +./stand/powerpc-4xx/@OSRELEASE@/modules/luadata/luadata.kmod base-kernel-modules kmod,compatmodules ./stand/powerpc-4xx/@OSRELEASE@/modules/luapmf base-kernel-modules kmod,compatmodules ./stand/powerpc-4xx/@OSRELEASE@/modules/luapmf/luapmf.kmod base-kernel-modules kmod,compatmodules ./stand/powerpc-4xx/@OSRELEASE@/modules/luasystm base-kernel-modules kmod,compatmodules @@ -351,6 +353,8 @@ ./stand/powerpc-booke/@OSRELEASE@/modules/lua/lua.kmod base-kernel-modules kmod,compatmodules ./stand/powerpc-booke/@OSRELEASE@/modules/luacore base-obsolete obsolete ./stand/powerpc-booke/@OSRELEASE@/modules/luacore/luacore.kmod base-obsolete obsolete +./stand/powerpc-booke/@OSRELEASE@/modules/luadata base-kernel-modules kmod,compatmodules +./stand/powerpc-booke/@OSRELEASE@/modules/luadata/luadata.kmod base-kernel-modules kmod,compatmodules ./stand/powerpc-booke/@OSRELEASE@/modules/luapmf base-kernel-modules kmod,compatmodules ./stand/powerpc-booke/@OSRELEASE@/modules/luapmf/luapmf.kmod base-kernel-modules kmod,compatmodules ./stand/powerpc-booke/@OSRELEASE@/modules/luasystm base-kernel-modules kmod,compatmodules diff --git a/distrib/sets/lists/modules/mi b/distrib/sets/lists/modules/mi index 312e580..632c547 100644 --- a/distrib/sets/lists/modules/mi +++ b/distrib/sets/lists/modules/mi @@ -118,6 +118,8 @@ ./@MODULEDIR@/lua/lua.kmod base-kernel-modules kmod ./@MODULEDIR@/luacore base-obsolete obsolete ./@MODULEDIR@/luacore/luacore.kmod base-obsolete obsolete +./@MODULEDIR@/luadata base-kernel-modules kmod +./@MODULEDIR@/luadata/luadata.kmod base-kernel-modules kmod ./@MODULEDIR@/luapmf base-kernel-modules kmod ./@MODULEDIR@/luapmf/luapmf.kmod base-kernel-modules kmod ./@MODULEDIR@/luasystm base-kernel-modules kmod diff --git a/lib/lua/data/Makefile b/lib/lua/data/Makefile new file mode 100644 index 0000000..12b3fdf --- /dev/null +++ b/lib/lua/data/Makefile @@ -0,0 +1,16 @@ +LUA_MODULES= data + +LUA_SRCS.data= luadata.c +LUA_SRCS.data+= data.c +LUA_SRCS.data+= handle.c +LUA_SRCS.data+= layout.c +LUA_SRCS.data+= luautil.c +LUA_SRCS.data+= binary.c + +DATA= data.so +LDLIBS= -llua ${DATA} +test: test.c ${DATA} + +CLEANFILES+= test + +.include diff --git a/lib/lua/data/binary.c b/lib/lua/data/binary.c new file mode 100644 index 0000000..b909596 --- /dev/null +++ b/lib/lua/data/binary.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _KERNEL +#include +#else +#include +#endif + +#include + +#include "binary.h" + +#define BYTE_MAX UCHAR_MAX +#define UINT64_BIT (64) + +inline static void +set_bits(uint64_t *value, uint64_t clear_mask, uint64_t set_mask) +{ + *value &= clear_mask; + *value |= set_mask; +} + +#define CONTIGUOUS_BITS(widt, truncated) (width - truncated) + +static void +expand(uint64_t *value, size_t width, size_t msb_offset, byte_t truncated) +{ + size_t contiguous = CONTIGUOUS_BITS(width, truncated); + + size_t trunc_msb_offset = BYTE_BIT - truncated; + size_t trunc_lsb_offset = contiguous + trunc_msb_offset; + + size_t clear_offset = msb_offset + truncated; + + uint64_t clear_mask = UINT64_MAX >> clear_offset; + uint64_t trunc_mask = *value >> trunc_lsb_offset << contiguous; + + set_bits(value, clear_mask, trunc_mask); +} + +static void +contract(uint64_t *value, size_t width, size_t msb_offset, byte_t truncated) +{ + size_t contiguous = CONTIGUOUS_BITS(width, truncated); + + size_t trunc_lsb_offset = BYTE_BIT - truncated; + size_t trunc_msb_offset = contiguous + trunc_lsb_offset; + + size_t clear_offset = msb_offset + truncated; + + uint64_t clear_mask = UINT64_MAX << clear_offset; + uint64_t trunc_mask = *value << trunc_msb_offset >> contiguous; + + set_bits(value, clear_mask, trunc_mask); +} + +#define TRUNCATED_BITS(width) (width % BYTE_BIT) + +#define VALUE_MSB_OFFSET(width) (UINT64_BIT - width) + +static void +swap_bytes_in(uint64_t *value, size_t width) +{ + size_t msb_offset = VALUE_MSB_OFFSET(width); + + *value <<= msb_offset; + + *value = bswap64(*value); + + byte_t truncated = TRUNCATED_BITS(width); + if (truncated > 0) + expand(value, width, msb_offset, truncated); +} + +static void +swap_bytes_out(uint64_t *value, size_t width) +{ + size_t msb_offset = VALUE_MSB_OFFSET(width); + + *value = bswap64(*value); + + byte_t truncated = TRUNCATED_BITS(width); + if (truncated > 0) + contract(value, width, msb_offset, truncated); + + *value >>= msb_offset; +} + +#define MSB_OFFSET(offset) (offset % BYTE_BIT) + +#define LSB_OFFSET(width, msb_offset) \ + MAX((ssize_t) (BYTE_BIT - msb_offset - width), 0) + +#define BYTE_POSITION(offset) (offset / BYTE_BIT) + +#define OVERFLOW_BITS(width, msb_offset, lsb_offset) \ + (width - (BYTE_BIT - msb_offset - lsb_offset)) + +#define MASK(msb_offset, lsb_offset) \ + ((byte_t) BYTE_MAX >> (msb_offset + lsb_offset) << lsb_offset) + +#define OVERFLOW_LSB_OFFSET(overflow) (BYTE_BIT - overflow) + +#define NEED_SWAP(width, endian) \ + (width > BYTE_BIT && endian == LITTLE_ENDIAN) + +uint64_t +binary_get_uint64(byte_t *bytes, size_t offset, size_t width, int endian) +{ + size_t msb_offset = MSB_OFFSET(offset); + size_t lsb_offset = LSB_OFFSET(width, msb_offset); + size_t pos = BYTE_POSITION(offset); + size_t overflow = OVERFLOW_BITS(width, msb_offset, lsb_offset); + byte_t mask = MASK(msb_offset, lsb_offset); + + uint64_t value = (byte_t) (bytes[ pos ] & mask) >> lsb_offset; + + for (; overflow >= BYTE_BIT; overflow -= BYTE_BIT) + value = (value << BYTE_BIT) | bytes[ ++pos ]; + + if (overflow > 0) { + /* assertion: overflow < BYTE_BIT */ + size_t overflow_lsb_offset = OVERFLOW_LSB_OFFSET(overflow); + + value <<= overflow; + value |= (byte_t) bytes[ ++pos ] >> overflow_lsb_offset; + } + + if (NEED_SWAP(width, endian)) + swap_bytes_in(&value, width); + + return value; +} + +void +binary_set_uint64(byte_t *bytes, size_t offset, size_t width, int endian, + uint64_t value) +{ + size_t msb_offset = MSB_OFFSET(offset); + size_t lsb_offset = LSB_OFFSET(width, msb_offset); + size_t pos = BYTE_POSITION(offset); + size_t overflow = OVERFLOW_BITS(width, msb_offset, lsb_offset); + byte_t clear_mask = ~MASK(msb_offset, lsb_offset); + + if (NEED_SWAP(width, endian)) + swap_bytes_out(&value, width); + + bytes[ pos ] &= clear_mask; + bytes[ pos ] |= (uint64_t) value << lsb_offset >> overflow; + + for (; overflow >= BYTE_BIT; overflow -= BYTE_BIT) + bytes[ ++pos ] = (uint64_t) value >> (overflow - BYTE_BIT); + + if (overflow > 0) { + /* assertion: overflow < BYTE_BIT */ + size_t overflow_lsb_offset = OVERFLOW_LSB_OFFSET(overflow); + byte_t overflow_clear_mask = ~(BYTE_MAX << overflow_lsb_offset); + + bytes[ ++pos ] &= overflow_clear_mask; + bytes[ pos ] |= value << overflow_lsb_offset; + } +} diff --git a/lib/lua/data/binary.h b/lib/lua/data/binary.h new file mode 100644 index 0000000..7bb21e1 --- /dev/null +++ b/lib/lua/data/binary.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _BINARY_H_ +#define _BINARY_H_ + +#include + +#ifdef _KERNEL +#include +#else +#include +#include +#endif + +#define BYTE_BIT CHAR_BIT + +typedef unsigned char byte_t; + +uint64_t binary_get_uint64(byte_t *, size_t, size_t, int); + +void binary_set_uint64(byte_t *, size_t, size_t, int, uint64_t); + +#define CEIL_DIV(x, y) ((x + y - 1) / y) +#define BIT_TO_BYTE(x) (CEIL_DIV(x, BYTE_BIT)) +#define BYTE_TO_BIT(x) (x * BYTE_BIT) + +#endif /* _BINARY_H_ */ diff --git a/lib/lua/data/ctest.lua b/lib/lua/data/ctest.lua new file mode 100644 index 0000000..c1535cd --- /dev/null +++ b/lib/lua/data/ctest.lua @@ -0,0 +1,22 @@ +function filter(d) + -- store d in a global + gd = d + d:layout{ + -- most significant 4-bytes + uint4_msb = {0,4}, + -- inner 16-bytes + uint16 = {4, 16}, + -- least significant 4-bytes + uint4_lsb = {20, 4} + } + return d.uint4_msb == 0xa and + d.uint16 == 0xbcde and + d.uint4_lsb == 0xf +end + +function access_global() + -- should return nil if ldata_unref(d) has been called from C + return gd.uint16 +end + +d = data.new{0xff, 0xee, 0xdd, 0x00} diff --git a/lib/lua/data/data.c b/lib/lua/data/data.c new file mode 100644 index 0000000..1670346 --- /dev/null +++ b/lib/lua/data/data.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _KERNEL +#include +#else +#include +#endif + +#include + +#include + +#include "luautil.h" + +#include "data.h" +#include "binary.h" +#include "layout.h" + +#define LUA_INTEGER_BYTE (sizeof(lua_Integer)) +#define LUA_INTEGER_BIT (LUA_INTEGER_BYTE * BYTE_BIT) + +inline static bool +check_offset(data_t *data, size_t offset, size_t length) +{ + size_t last_pos = data->offset + data->length - 1; + return offset >= data->offset && offset <= last_pos; +} + +inline static bool +check_length(data_t *data, size_t offset, size_t length) +{ + return offset + length <= data->offset + data->length; +} + +inline static bool +check_limits(data_t *data, size_t offset, size_t length) +{ + return check_offset(data, offset, length) && + check_length(data, offset, length); +} + +#define ENTRY_BYTE_OFFSET(data, entry) \ + ((BIT_TO_BYTE(entry->offset + 1) - 1) + data->offset) + +inline static bool +check_num_limits(data_t *data, layout_entry_t *entry) +{ + size_t offset = ENTRY_BYTE_OFFSET(data, entry); + size_t length = BIT_TO_BYTE(entry->length); + + return entry->length <= LUA_INTEGER_BIT && + check_limits(data, offset, length); +} + +inline static bool +check_str_limits(data_t *data, layout_entry_t *entry) +{ + size_t offset = entry->offset + data->offset; + size_t length = entry->length; + return check_limits(data, offset, length); +} + +inline static layout_entry_t * +get_entry(lua_State *L, data_t *data, int key_ix) +{ + if (!luau_isvalidref(data->layout)) + return NULL; + + return layout_get_entry(L, data->layout, key_ix); +} + +static data_t * +new_data(lua_State *L, handle_t *handle, size_t offset, size_t length) +{ + data_t *data = lua_newuserdata(L, sizeof(data_t)); + + data->handle = handle; + data->offset = offset; + data->length = length; + data->layout = LUA_REFNIL; + + luau_setmetatable(L, DATA_USERDATA); + + return data; +} + +#define BINARY_PARMS(data, entry, ptr) \ + ptr, entry->offset, entry->length, entry->endian + +inline static int +get_num(lua_State *L, data_t *data, layout_entry_t *entry) +{ + if (!check_num_limits(data, entry)) + return 0; + + byte_t *ptr = (byte_t *) data_get_ptr(data); + if (ptr == NULL) + return 0; + + /* assertion: LUA_INTEGER_BIT <= 64 */ + lua_Integer value = binary_get_uint64(BINARY_PARMS(data, entry, ptr)); + lua_pushinteger(L, value); + return 1; +} + +inline static int +get_str(lua_State *L, data_t *data, layout_entry_t *entry) +{ + if (!check_str_limits(data, entry)) + return 0; + + const char *ptr = (const char *) data_get_ptr(data); + const char *s = ptr + entry->offset; + lua_pushlstring(L, s, entry->length); + return 1; +} + +inline static void +set_num(lua_State *L, data_t *data, layout_entry_t *entry, int value_ix) +{ + if (!check_num_limits(data, entry)) + return; + + byte_t *ptr = (byte_t *) data_get_ptr(data); + if (ptr == NULL) + return; + + /* assertion: LUA_INTEGER_BIT <= 64 */ + lua_Integer value = lua_tointeger(L, value_ix); + binary_set_uint64(BINARY_PARMS(data, entry, ptr), value); +} + +static void +set_str(lua_State *L, data_t *data, layout_entry_t *entry, int value_ix) +{ + if (!check_str_limits(data, entry)) + return; + + size_t len; + const char *s = lua_tolstring(L, value_ix, &len); + if (s == NULL) + return; + + char *ptr = (char *) data_get_ptr(data); + memcpy(ptr + entry->offset, s, MIN(len, entry->length)); +} + +inline data_t * +data_new(lua_State *L, void *ptr, size_t size, bool free) +{ + handle_t *handle = handle_new_single(L, ptr, size, free); + data_t *data = new_data(L, handle, 0, size); + return data; +} + +#ifdef _KERNEL +inline data_t * +data_new_chain(lua_State *L, struct mbuf *chain, bool free) +{ + handle_t *handle = handle_new_chain(L, chain, free); + data_t *data = new_data(L, handle, 0, chain->m_len); + return data; +} +#endif + +int +data_new_segment(lua_State *L, data_t *data, size_t offset, size_t length) +{ + if (!check_limits(data, offset, length)) + return 0; + + handle_t *handle = data->handle; + + handle->refcount++; + + new_data(L, handle, offset, length); + return 1; +} + +inline void +data_delete(lua_State *L, data_t *data) +{ + handle_delete(L, data->handle); + + if (luau_isvalidref(data->layout)) + luau_unref(L, data->layout); +} + +inline data_t * +data_test(lua_State *L, int index) +{ +#if LUA_VERSION_NUM >= 502 + return (data_t *) luaL_testudata(L, index, DATA_USERDATA); +#else + return (data_t *) luaL_checkudata(L, index, DATA_USERDATA); +#endif +} + +inline void +data_apply_layout(lua_State *L, data_t *data, int layout_ix) +{ + luau_unref(L, data->layout); + lua_pushvalue(L, layout_ix); + data->layout = luau_ref(L); +} + +int +data_get_field(lua_State *L, data_t *data, int key_ix) +{ + layout_entry_t *entry = get_entry(L, data, key_ix); + if (entry == NULL) + return 0; + + switch (entry->type) { + case LAYOUT_TNUMBER: + return get_num(L, data, entry); + case LAYOUT_TSTRING: + return get_str(L, data, entry); + } + return 0; /* unreached */ +} + +void +data_set_field(lua_State *L, data_t *data, int key_ix, int value_ix) +{ + layout_entry_t *entry = get_entry(L, data, key_ix); + if (entry == NULL) + return; + + switch (entry->type) { + case LAYOUT_TNUMBER: + set_num(L, data, entry, value_ix); + break; + case LAYOUT_TSTRING: + set_str(L, data, entry, value_ix); + break; + } +} + +inline void * +data_get_ptr(data_t *data) +{ + return handle_get_ptr(data->handle, data->offset, data->length); +} + +inline void +data_unref(data_t *data) +{ + handle_unref(data->handle); +} + diff --git a/lib/lua/data/data.h b/lib/lua/data/data.h new file mode 100644 index 0000000..8784daa --- /dev/null +++ b/lib/lua/data/data.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _DATA_H_ +#define _DATA_H_ + +#ifndef _KERNEL +#include +#include +#else +#include +#include +#endif + +#include + +#include "handle.h" +#include "layout.h" + +#define DATA_LIB "data" +#define DATA_USERDATA "data.data" + +typedef struct { + handle_t *handle; + size_t offset; + size_t length; + int layout; +} data_t; + +data_t * data_new(lua_State *, void *, size_t, bool); + +#ifdef _KERNEL +data_t * data_new_chain(lua_State *, struct mbuf *, bool); +#endif + +int data_new_segment(lua_State *, data_t *, size_t, size_t); + +void data_delete(lua_State *, data_t *); + +data_t * data_test(lua_State *, int); + +void data_apply_layout(lua_State *, data_t *, int); + +int data_get_field(lua_State *, data_t *, int); + +void data_set_field(lua_State *, data_t *, int, int); + +void * data_get_ptr(data_t *); + +void data_unref(data_t *); + +#endif /* _DATA_H_ */ diff --git a/lib/lua/data/handle.c b/lib/lua/data/handle.c new file mode 100644 index 0000000..0ae4bba --- /dev/null +++ b/lib/lua/data/handle.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifdef _KERNEL +#include +#endif + +#include + +#include "luautil.h" + +#include "handle.h" + +static void +free_handle(lua_State *L, handle_t *handle) +{ + switch (handle->type) { + case HANDLE_TYPE_SINGLE: + { + single_t *single = &handle->bucket.single; + luau_free(L, single->ptr, single->size); + break; + } + case HANDLE_TYPE_CHAIN: + { +#ifdef _KERNEL + struct mbuf *chain = handle->bucket.chain; + m_free(chain); +#endif + break; + } + } +} + +handle_t * +handle_new_single(lua_State *L, void *ptr, size_t size, bool free) +{ + handle_t *handle = (handle_t *) luau_malloc(L, sizeof(handle_t)); + + single_t *single = &handle->bucket.single; + single->ptr = ptr; + single->size = size; + + handle->type = HANDLE_TYPE_SINGLE; + handle->refcount = 0; + handle->free = free; + + return handle; +} + +#ifdef _KERNEL +handle_t * +handle_new_chain(lua_State *L, struct mbuf *chain, bool free) +{ + handle_t *handle = (handle_t *) luau_malloc(L, sizeof(handle_t)); + + handle->bucket.chain = chain; + + handle->type = HANDLE_TYPE_CHAIN; + handle->refcount = 0; + handle->free = free; + + return handle; +} +#endif + +void +handle_delete(lua_State *L, handle_t *handle) +{ + if (handle->refcount == 0) { + if (handle->free) + free_handle(L, handle); + + luau_free(L, handle, sizeof(handle_t)); + } + else + handle->refcount--; +} + +void * +handle_get_ptr(handle_t *handle, size_t offset, size_t length) +{ + void *ptr = NULL; + + switch (handle->type) { + case HANDLE_TYPE_SINGLE: + { + single_t *single = &handle->bucket.single; + if (single->ptr == NULL) + return NULL; + + ptr = (char *) single->ptr + offset; + break; + } + case HANDLE_TYPE_CHAIN: + { +#ifdef _KERNEL + struct mbuf *chain = handle->bucket.chain; + if (chain == NULL || offset > INT_MAX || length > INT_MAX) + return NULL; + + struct mbuf *m = m_pulldown(chain, (int) offset, (int) length, + NULL); + if (m == NULL) + return NULL; + + ptr = mtod(m, void *); +#endif + } + } + + return ptr; +} + +void +handle_unref(handle_t *handle) +{ + switch (handle->type) { + case HANDLE_TYPE_SINGLE: + { + single_t *single = &handle->bucket.single; + single->ptr = NULL; + single->size = 0; + break; + } + case HANDLE_TYPE_CHAIN: + { +#ifdef _KERNEL + handle->bucket.chain = NULL; +#endif + break; + } + } +} + diff --git a/lib/lua/data/handle.h b/lib/lua/data/handle.h new file mode 100644 index 0000000..d66a634 --- /dev/null +++ b/lib/lua/data/handle.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _HANDLE_H_ +#define _HANDLE_H_ + +#ifndef _KERNEL +#include +#include +#else +#include +#include +#endif + +#include + +typedef struct { + void *ptr; + size_t size; +} single_t; + +typedef union { + single_t single; +#ifdef _KERNEL + struct mbuf *chain; +#endif +} bucket_t; + +typedef enum { + HANDLE_TYPE_SINGLE = 0, + HANDLE_TYPE_CHAIN, +} handle_type_t; + +typedef struct { + bucket_t bucket; + handle_type_t type; + size_t refcount; + bool free; +} handle_t; + +handle_t * handle_new_single(lua_State *, void *, size_t, bool); + +#ifdef _KERNEL +handle_t * handle_new_chain(lua_State *, struct mbuf *, bool); +#endif + +void handle_delete(lua_State *, handle_t *); + +void * handle_get_ptr(handle_t *, size_t, size_t); + +void handle_unref(handle_t *); + +#endif /* _HANDLE_H_ */ diff --git a/lib/lua/data/layout.c b/lib/lua/data/layout.c new file mode 100644 index 0000000..72120ac --- /dev/null +++ b/lib/lua/data/layout.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include + +#include "luautil.h" + +#include "layout.h" + +inline static layout_entry_t * +test_entry(lua_State *L, int index) +{ +#if LUA_VERSION_NUM >= 502 + return (layout_entry_t *) + luaL_testudata(L, index, LAYOUT_ENTRY_USERDATA); +#else + return (layout_entry_t *) + luaL_checkudata(L, index, LAYOUT_ENTRY_USERDATA); +#endif +} + +inline static void +init_layout(layout_entry_t *entry) +{ + entry->offset = 0; + entry->length = 0; + entry->type = LAYOUT_TYPE_DEFAULT; + entry->endian = LAYOUT_ENDIAN_DEFAULT; +} + +static void +load_type(lua_State *L, layout_entry_t *entry) +{ + const char *type = lua_tostring(L, -1); + + if (type[0] == 'n') + entry->type = LAYOUT_TNUMBER; + else if (type[0] == 's') + entry->type = LAYOUT_TSTRING; +} + +static void +load_endian(lua_State *L, layout_entry_t *entry) +{ + const char *endian = lua_tostring(L, -1); + + if (endian[0] == 'n' || endian[0] == 'b') + entry->endian = BIG_ENDIAN; + else if (endian[0] == 'l') + entry->endian = LITTLE_ENDIAN; + else if (endian[0] == 'h') + entry->endian = BYTE_ORDER; +} + +static void +load_entry_numbered(lua_State *L, layout_entry_t *entry) +{ +#if LUA_VERSION_NUM >= 502 + size_t array_len = lua_rawlen(L, -1); +#else + size_t array_len = lua_objlen(L, -1); +#endif + + if (array_len >= 1) + entry->offset = luau_getarray_integer(L, -1, 1); + if (array_len >= 2) + entry->length = luau_getarray_integer(L, -1, 2); + if (array_len >= 3) { + luau_getarray(L, -1, 3); + load_type(L, entry); + lua_pop(L, 1); + } + if (array_len >= 4) { + luau_getarray(L, -1, 4); + load_endian(L, entry); + lua_pop(L, 1); + } +} + +static void +load_entry_named(lua_State *L, layout_entry_t *entry) +{ + lua_getfield(L, -1, "offset"); + if (lua_isnumber(L, -1)) + entry->offset = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "length"); + if (lua_isnumber(L, -1)) + entry->length = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "type"); + if (lua_isstring(L, -1)) + load_type(L, entry); + lua_pop(L, 1); + + lua_getfield(L, -1, "endian"); + if (lua_isstring(L, -1)) + load_endian(L, entry); + lua_pop(L, 1); +} + +static void +load_entry(lua_State *L, layout_entry_t *entry) +{ + init_layout(entry); + load_entry_numbered(L, entry); + load_entry_named(L, entry); +} + +static void +copy_entry(layout_entry_t *dst, layout_entry_t *src) +{ + dst->offset = src->offset; + dst->length = src->length; + dst->type = src->type; + dst->endian = src->endian; +} + +static int +new_entry(lua_State *L, layout_entry_t *entry) +{ + layout_entry_t *nentry = + (layout_entry_t *) lua_newuserdata(L, sizeof(layout_entry_t)); + + luau_setmetatable(L, LAYOUT_ENTRY_USERDATA); + + copy_entry(nentry, entry); + return 1; +} + +void +layout_load(lua_State *L, int index) +{ + layout_entry_t entry; + + lua_pushnil(L); /* first key */ + while (lua_next(L, index) != 0) { + /* uses 'key' (at index -2) and 'value' (at index -1) */ + load_entry(L, &entry); + if (entry.length == 0) + lua_pushnil(L); + else + new_entry(L, &entry); + + /* layout[ key ] = entry */ + luau_settable(L, index, -3, -1); + + /* removes 'value' and 'entry'; keeps 'key' for next iteration */ + lua_pop(L, 2); + } + + lua_pushboolean(L, true); + lua_setfield(L, index, LAYOUT_STAMP); +} + +layout_entry_t * +layout_get_entry(lua_State *L, int layout_ix, int key_ix) +{ + void *entry = NULL; + + luau_getref(L, layout_ix); + luau_gettable(L, -1, key_ix); + if (lua_isnil(L, -1)) + goto end; + + entry = test_entry(L, -1); + +end: + lua_pop(L, 2); + return entry; +} + diff --git a/lib/lua/data/layout.h b/lib/lua/data/layout.h new file mode 100644 index 0000000..bf80d61 --- /dev/null +++ b/lib/lua/data/layout.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _LAYOUT_H_ +#define _LAYOUT_H_ + +#ifndef _KERNEL +#include +#include +#else +#include +#endif + +#include + +#include + +#define LAYOUT_ENTRY_USERDATA "data.layout.entry" + +#define LAYOUT_STAMP "__layout_stamp" + +#define LAYOUT_TYPE_DEFAULT LAYOUT_TNUMBER +#define LAYOUT_ENDIAN_DEFAULT BIG_ENDIAN + +typedef enum { + LAYOUT_TNUMBER = 0, + LAYOUT_TSTRING +} layout_type_t; + +typedef struct { + size_t offset; + size_t length; + layout_type_t type; + int endian; +} layout_entry_t; + +void layout_load(lua_State *, int); + +layout_entry_t * layout_get_entry(lua_State *, int, int); + +#endif /* _LAYOUT_H_ */ diff --git a/lib/lua/data/luadata.c b/lib/lua/data/luadata.c new file mode 100644 index 0000000..08e0cc4 --- /dev/null +++ b/lib/lua/data/luadata.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2013, 2014 Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _KERNEL +#include +#else +#include +#endif + +#include +#include + +#include "luautil.h" + +#include "luadata.h" +#include "data.h" +#include "layout.h" + +static char * +new_data_num(lua_State *L, size_t *len) +{ + *len = luau_tosize(L, 1); + if (*len == 0) + return NULL; + + char *data = (char *) luau_malloc(L, *len); + if (data == NULL) + return NULL; + + memset(data, 0, *len); + return data; +} + +static char * +new_data_tab(lua_State *L, size_t *len) +{ +#if LUA_VERSION_NUM >= 502 + *len = lua_rawlen(L, 1); +#else + *len = lua_objlen(L, 1); +#endif + if (*len == 0) + return NULL; + + char *data = (char *) luau_malloc(L, *len); + if (data == NULL) + return NULL; + + size_t i = 0; + lua_pushnil(L); /* first key */ + while (lua_next(L, 1) != 0 && i < *len) { + /* uses 'key' (at index -2) and 'value' (at index -1) */ + data[ i++ ] = (char) lua_tointeger(L, -1); + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 1); + } + return data; +} + +static char * +new_data_str(lua_State *L, size_t *len) +{ + const char *str = lua_tolstring(L, 1, len); + if (str == NULL || *len == 0) + return NULL; + + char *data = (char *) luau_malloc(L, *len); + if (data == NULL) + return NULL; + + memcpy(data, str, *len); + return data; +} + +static int +new_data(lua_State *L) +{ + char *data = NULL; + size_t len = 0; + + int type = lua_type(L, 1); + if (type == LUA_TNUMBER) + data = new_data_num(L, &len); + else if (type == LUA_TTABLE) + data = new_data_tab(L, &len); + else if (type == LUA_TSTRING) + data = new_data_str(L, &len); + + if (data == NULL || len == 0) + return 0; + + data_new(L, (void *) data, len, true); + return 1; +} + +static int +new_layout(lua_State *L) +{ + if (!lua_istable(L, 1)) + return 0; + + layout_load(L, 1); + return 1; +} + +static int +new_segment(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + + size_t offset = data->offset; + size_t length = data->length; + + int nargs = lua_gettop(L); + if (nargs >= 2) { + size_t seg_offset = luau_tosize(L, 2); + + offset += seg_offset; + + if (nargs >= 3) + length = luau_tosize(L, 3); + else + length -= seg_offset; + } + + return data_new_segment(L, data, offset, length); +} + +static int +apply_layout(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + + if (!lua_istable(L, 2)) + return 0; + + lua_getfield(L, 2, LAYOUT_STAMP); + bool is_layout = (bool) lua_toboolean(L, -1); + lua_pop(L, 1); + + if (!is_layout) + layout_load(L, 2); + + data_apply_layout(L, data, 2); + + /* return data object */ + lua_pushvalue(L, 1); + return 1; +} + +static int +__gc(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + data_delete(L, data); + return 0; +} + +static int +__index(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + + /* try object-oriented access first */ + luau_getmetatable(L, 1, 2); + if (!lua_isnil(L, -1)) + /* return this method */ + return 1; + + lua_pop(L, 1); + return data_get_field(L, data, 2); +} + +static int +__newindex(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + + /* try object-oriented access first */ + luau_getmetatable(L, 1, 2); + if (!lua_isnil(L, -1)) + /* shouldn't overwrite a method */ + goto end; + + data_set_field(L, data, 2, 3); +end: + lua_pop(L, 1); + return 0; +} + +inline static int +__len(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + + luau_pushsize(L, data->length); + return 1; +} + +inline static int +__tostring(lua_State *L) +{ + data_t *data = lua_touserdata(L, 1); + + const char * ptr = (const char *) data_get_ptr(data); + lua_pushlstring(L, ptr, data->length); + return 1; +} + +static const luaL_Reg data_lib[ ] = { + {"new" , new_data}, + {"layout", new_layout}, + {NULL , NULL} +}; + +static const luaL_Reg data_m[ ] = { + {"layout" , apply_layout}, + {"segment" , new_segment}, + {"__index" , __index}, + {"__newindex", __newindex}, + {"__gc" , __gc}, + {"__len" , __len}, + {"__tostring", __tostring}, + {NULL , NULL} +}; + +static const luaL_Reg layout_entry_m[ ] = { + {NULL, NULL} +}; + +int +luaopen_data(lua_State *L) +{ + luaL_newmetatable(L, LAYOUT_ENTRY_USERDATA); +#if LUA_VERSION_NUM >= 502 + luaL_setfuncs(L, layout_entry_m, 0); +#else + luaL_register(L, NULL, layout_entry_m); +#endif + lua_pop(L, 1); + + luaL_newmetatable(L, DATA_USERDATA); +#if LUA_VERSION_NUM >= 502 + luaL_setfuncs(L, data_m, 0); + luaL_newlib(L, data_lib); +#else + luaL_register(L, NULL, data_m); + luaL_register(L, DATA_LIB, data_lib); +#endif + + return 1; +} + +int +ldata_newref(lua_State *L, void *ptr, size_t size) +{ + data_new(L, ptr, size, false); + /* keep the new data object on the stack */ + lua_pushvalue(L, -1); + return luau_ref(L); +} + +#if _KERNEL +int +ldata_newref_chain(lua_State *L, struct mbuf *chain) +{ + data_new_chain(L, chain, false); + /* keep the new data object on the stack */ + lua_pushvalue(L, -1); + return luau_ref(L); +} +#endif + +void +ldata_unref(lua_State *L, int r) +{ + luau_getref(L, r); + + data_t *data = data_test(L, -1); + if (data == NULL) + return; + + data_unref(data); + + /* pop data object */ + lua_pop(L, 1); + luau_unref(L, r); +} + +void * +ldata_topointer(lua_State *L, int index, size_t *size) +{ + data_t *data = data_test(L, index); + if (data == NULL) { + if (size != NULL) + *size = 0; + return NULL; + } + + if (size != NULL) + *size = data->length; + + return data_get_ptr(data); +} + +#ifdef _MODULE +#include +#include + +MODULE(MODULE_CLASS_MISC, luadata, "lua"); + +static int +luadata_modcmd(modcmd_t cmd, void *opaque) +{ + int error; + + switch (cmd) { + case MODULE_CMD_INIT: + error = klua_mod_register(DATA_LIB, luaopen_data); + break; + case MODULE_CMD_FINI: + error = klua_mod_unregister(DATA_LIB); + break; + default: + error = ENOTTY; + } + return error; +} +#endif diff --git a/lib/lua/data/luadata.h b/lib/lua/data/luadata.h new file mode 100644 index 0000000..bd14e93 --- /dev/null +++ b/lib/lua/data/luadata.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _LUA_DATA_H_ +#define _LUA_DATA_H_ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +#include + +extern int luaopen_data(lua_State *); + +extern int ldata_newref(lua_State *, void *, size_t); + +#if _KERNEL +extern int ldata_newref_chain(lua_State *, struct mbuf *); +#endif + +extern void ldata_unref(lua_State *, int); + +extern void * ldata_topointer(lua_State *, int, size_t *); + +#endif /* _LUA_DATA_H_ */ diff --git a/lib/lua/data/luautil.c b/lib/lua/data/luautil.c new file mode 100644 index 0000000..f342fbf --- /dev/null +++ b/lib/lua/data/luautil.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013, 2014, Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "luautil.h" + +inline static void +adjust_index(int *index, int factor) +{ + if (*index < 0) + (*index) -= factor; +} + +void +luau_getarray(lua_State *L, int index, lua_Integer n) +{ + lua_pushinteger(L, n); + adjust_index(&index, 1); + lua_gettable(L, index); +} + +lua_Integer +luau_getarray_integer(lua_State *L, int index, lua_Integer n) +{ + luau_getarray(L, index, n); + lua_Integer result = lua_tointeger(L, -1); + lua_pop(L, 1); + return result; +} + +void +luau_gettable(lua_State *L, int index, int field_index) +{ + lua_pushvalue(L, field_index); + adjust_index(&index, 1); + lua_gettable(L, index); +} + +void +luau_settable(lua_State *L, int index, int field_index, int value_index) +{ + lua_pushvalue(L, field_index); + adjust_index(&value_index, 1); + lua_pushvalue(L, value_index); + adjust_index(&index, 2); + lua_settable(L, index); +} + +void +luau_getmetatable(lua_State *L, int index, int field_index) +{ + lua_getmetatable(L, index); + adjust_index(&field_index, 1); + luau_gettable(L, -1, field_index); + /* pop metatable */ + lua_remove(L, -2); +} + +inline void +luau_setmetatable(lua_State *L, const char *tname) +{ + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + +void * +luau_malloc(lua_State *L, size_t size) +{ + void * ud = NULL; + lua_Alloc alloc = lua_getallocf(L, &ud); + return alloc(ud, NULL, 0, size); +} + +void +luau_free(lua_State *L, void * ptr, size_t size) +{ + void * ud = NULL; + lua_Alloc alloc = lua_getallocf(L, &ud); + alloc(ud, ptr, size, 0); +} + diff --git a/lib/lua/data/luautil.h b/lib/lua/data/luautil.h new file mode 100644 index 0000000..6e916b1 --- /dev/null +++ b/lib/lua/data/luautil.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, 2014 Lourival Vieira Neto . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _LUA_UTIL_H_ +#define _LUA_UTIL_H_ + +#ifndef _KERNEL +#include +#endif + +#include +#include + +#define luau_isvalidref(ref) (ref != LUA_REFNIL && ref != LUA_NOREF) + +#define luau_ref(L) luaL_ref(L, LUA_REGISTRYINDEX) +#define luau_unref(L, r) luaL_unref(L, LUA_REGISTRYINDEX, r) +#define luau_getref(L, r) lua_rawgeti(L, LUA_REGISTRYINDEX, r) + +#define luau_tosize(L, index) ((size_t) lua_tointeger(L, index)) +#define luau_pushsize(L, size) lua_pushinteger(L, (lua_Integer) size) + +void luau_getarray(lua_State *, int, lua_Integer); + +lua_Integer luau_getarray_integer(lua_State *, int, lua_Integer); + +void luau_gettable(lua_State *, int, int); + +void luau_settable(lua_State *, int, int, int); + +void luau_getmetatable(lua_State *, int, int); + +void luau_setmetatable(lua_State *, const char *); + +void * luau_malloc(lua_State *, size_t); + +void luau_free(lua_State *, void *, size_t); + +#endif /* _LUA_UTIL_H_ */ diff --git a/lib/lua/data/test.c b/lib/lua/data/test.c new file mode 100644 index 0000000..ee5d4b2 --- /dev/null +++ b/lib/lua/data/test.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +#include +#include + +#include "luadata.h" + +typedef unsigned char byte_t; + +int +main(void) +{ + /* create a new Lua state */ + lua_State *L = luaL_newstate(); + + /* open luadata library */ +#if LUA_VERSION_NUM >= 502 + luaL_requiref(L, "data", luaopen_data, 1); +#else + luaopen_data(L); +#endif + lua_pop(L, 1); /* remove lib */ + + /* load a script */ + assert(luaL_dofile(L, "ctest.lua") == 0); + + /* get the filter function */ + lua_getglobal(L, "filter"); + + /* create a new data ptr */ + size_t data_size = 3; + byte_t *data_ptr = (byte_t *) malloc(data_size); + data_ptr[0] = 0xAB; + data_ptr[1] = 0xCD; + data_ptr[2] = 0xEF; + + /* create a new data object */ + int rd = ldata_newref(L, data_ptr, data_size); + + /* call data_filter(d)*/ + assert(lua_pcall(L, 1, 1, 0) == 0); + + /* get filter result */ + int passed = lua_toboolean(L, -1); + assert(passed); + + /* unregister the Lua data object */ + ldata_unref(L, rd); + + /* now we can safely free the data pointer */ + free(data_ptr); + data_ptr = NULL; + data_size = 0; + + /* get the access_global function */ + lua_getglobal(L, "access_global"); + + /* call access_global() to try to access a data with a freed ptr */ + assert(lua_pcall(L, 0, 1, 0) == 0); + + /* should return nil */ + assert(lua_isnil(L, -1)); + + /* get a pointer of data object created by the Lua script */ + lua_getglobal(L, "d"); + data_ptr = (byte_t *) ldata_topointer(L, -1, &data_size); + assert(data_ptr != NULL); + + /* check size and values */ + assert(data_size == 4); + assert(data_ptr[0] == 0xFF); + assert(data_ptr[1] == 0xEE); + assert(data_ptr[2] == 0xDD); + assert(data_ptr[3] == 0x00); + lua_pop(L, 1); + + /* remove data object refered by 'd' from Lua */ + lua_pushnil(L); + lua_setglobal(L, "d"); + lua_gc(L, LUA_GCCOLLECT, 0); + + lua_getglobal(L, "d"); + data_ptr = (byte_t *) ldata_topointer(L, -1, &data_size); + assert(data_ptr == NULL); + assert(data_size == 0); + + printf("test passed ;-)\n"); + return 0; +} + diff --git a/lib/lua/data/test.lua b/lib/lua/data/test.lua new file mode 100644 index 0000000..f585ca5 --- /dev/null +++ b/lib/lua/data/test.lua @@ -0,0 +1,142 @@ +local data = require'data' + +-- create a new data object +d1 = data.new{0x0f} + +-- with no layout applied, __index and __newindex should return nil +d1.no = 0xdead +assert(d1.no == nil) + +-- create and apply a data layout +d1:layout{byte = {0, 8}, lsb = {7, 1}} + +-- access the whole byte +assert(d1.byte == 0x0f) + +-- set 0 to the least significant bit +d1.lsb = 0 + +-- access the whole byte again +assert(d1.byte == 0x0e) + +-- create a new layout +l = data.layout{ + uint16be = {0, 16}, + uint16le = {0, 16, 'number', 'le'}, + uint4 = {16, 4}, + uint9 = {20, 9}, + overflow = {32, 1}, +} + +-- create a new data object +d2 = data.new{0xaa, 0xbb, 0xcc, 0xdd} + +-- check byte length of d2 +assert(#d2 == 4) + +-- apply the layout 'l' to data 'd2' +d2:layout(l) + +-- access 2 bytes using big-endian ordering +assert(d2.uint16be == 0xaabb) + +-- access 2 bytes using little-endian ordering +assert(d2.uint16le == 0xbbaa) + +-- access 4 bits +assert(d2.uint4 == 0xc) + +-- access out of bounds +assert(d2.overflow == nil) + +-- create a new data segment, where offset = 1, length = 3 +d3 = d2:segment(1, 3) + +-- check bit length of d3 +assert(#d3 == 3) + +-- apply the layout 'l' into data 'd3' +d3:layout(l) + +-- access the first 16 bits of 'd3' segment +assert(d3.uint16be == 0xbbcc) + +-- create a new data segment, where offset = 1, length is unbounded +d4 = d3:segment(1) + +-- apply the layout 'l' into data 'd4' +d4:layout(l) + +-- access the first 16 bits of 'd4' segment +assert(d4.uint16be == 0xccdd) + +-- create a new data segment comprehending the whole original data +d5 = d2:segment() + +-- apply the layout 'l' into data 'd5' +d5:layout(l) + +-- set 0xf into 'uint4' position +d5.uint4 = 0xf + +-- check that it was set +assert(d5.uint4 == 0xf) + +-- check that d5 points to the same raw data of d2 +assert(d2.uint4 == 0xf) + +-- force the collecting of d2, d3, d4 +d2 = nil +d3 = nil +d4 = nil +collectgarbage() + +-- check that d5 is still valid +assert(d5.uint4 == 0xf) + +-- create a new data object with 2 bytes +d = data.new(2) +d:layout(l) +d.uint16be = 0xBEEF +assert(d.uint16be == 0xBEEF) + +d = data.new(128) +l = data.layout{ + toobig = {0, 65}, + uint64 = {0, 64}, +} + +d:layout(l) +d.uint64 = -1 +assert(d.toobig == nil) +assert(d.uint64 == -1) + +-- create a new data object from a string +d = data.new'\a' +d:layout{ascii = {1, 7}} +assert(d.ascii == 7) + +-- create a string field in a layout +d6 = data.new("abcdef") +d6:layout{str = {0, 6, 's'}, overflow = {1, 6, 's'}} + +assert(d6.str == "abcdef") +assert(d6.overflow == nil) + +d6.str = "hij" +assert(d6.str == "hijdef") + +-- check invalid data creation +d = data.new() +assert(d == nil) + +d = data.new(0) +assert(d == nil) + +d = data.new{} +assert(d == nil) + +d = data.new('') +assert(d == nil) + +print("test passed ;-)") diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 7edcca9..d1275fa 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -49,6 +49,7 @@ SUBDIR+= kernfs SUBDIR+= layerfs SUBDIR+= lfs SUBDIR+= lua +SUBDIR+= luadata SUBDIR+= luasystm SUBDIR+= luapmf SUBDIR+= mfs diff --git a/sys/modules/luadata/Makefile b/sys/modules/luadata/Makefile new file mode 100644 index 0000000..b619ffa --- /dev/null +++ b/sys/modules/luadata/Makefile @@ -0,0 +1,17 @@ +.include "../Makefile.inc" + +.PATH: ${S}/../lib/lua/data + +KMOD= luadata + +SRCS= luadata.c +SRCS+= data.c +SRCS+= layout.c +SRCS+= luautil.c +SRCS+= binary.c +SRCS+= handle.c + +CPPFLAGS+= -I${S}/../external/mit/lua/dist/src + +.include + -- 1.8.5.5