X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fc_utils.c;fp=src%2Fc_utils.c;h=d413ff8a36b42d7d2f585ed374ec342f11bed52c;hb=5b2d80650c4f01c64452b1aee2f024b25dd22e3f;hp=0000000000000000000000000000000000000000;hpb=3b56c80718ca0eb1dbde633b569f5ca7313cb4be;p=virt-dmesg.git diff --git a/src/c_utils.c b/src/c_utils.c new file mode 100644 index 0000000..d413ff8 --- /dev/null +++ b/src/c_utils.c @@ -0,0 +1,330 @@ +/* virt-dmesg + * (C) Copyright 2008-2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* This contains functions written in C. We can drop into C wherever + * we need to do something that would be much faster than OCaml or + * where it's just awkward to do something in OCaml or much easier in + * C. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* This vital function returns the offset of the virtual address + * relative to the base address. If the virtual address is outside + * the kernel, then it returns -1. + * + * Note that the function is declared "noalloc" for speed. It must + * not allocate anything on the OCaml heap. + * + * str_mapping : int64 -> int64 -> int -> int + */ +value +virt_dmesg_str_mapping (value base_addrv, value addrv, value str_lenv) +{ + uint64_t base_addr = Int64_val (base_addrv); + uint64_t addr = Int64_val (addrv); + int str_len = Int_val (str_lenv); + uint64_t off; + + off = addr - base_addr; + if (off < str_len) + return Val_int (off); + else + return Val_int (-1); +} + +/* NOTE: Declared as a "noalloc" function for speed. */ +value +virt_dmesg_addr_compare (value a1v, value a2v) +{ + uint64_t a1 = Int64_val (a1v); + uint64_t a2 = Int64_val (a2v); + + if (a1 < a2) + return (Val_int (-1)); + else if (a1 > a2) + return (Val_int (1)); + else + return (Val_int (0)); +} + +/* Find 'needle' in 'haystack', but start searching haystack from 'off'. + * + * strstr_from : string -> string -> int -> int + */ +value +virt_dmesg_strstr_from (value haystackv, value needlev, value offv) +{ + CAMLparam3 (haystackv, needlev, offv); + const char *haystack = String_val (haystackv); + int off = Int_val (offv); + const char *r; + ptrdiff_t i; + + /* Because OCaml strings can contain '\0' characters, use memmem + * not strstr. + */ + r = memmem (haystack + off, caml_string_length (haystackv) - off, + String_val (needlev), caml_string_length (needlev)); + if (r == 0) + caml_raise_not_found (); + + i = r - haystack; + CAMLreturn (Val_int (i)); +} + +/* This is like 'strstr_from' but it only tests for aligned 'needle', + * eg. if 'needle' was 4 bytes long then it would only look every 4 + * bytes. + */ +value +virt_dmesg_strstr_from_aligned (value haystackv, value needlev, value offv) +{ + CAMLparam3 (haystackv, needlev, offv); + const char *haystack = String_val (haystackv); + size_t haystack_len = caml_string_length (haystackv); + const char *needle = String_val (needlev); + size_t needle_len = caml_string_length (needlev); + int off = Int_val (offv); + int r; + + for (r = off; r < haystack_len; r += needle_len) { + if (memcmp (haystack + r, needle, needle_len) == 0) + goto found; + } + caml_raise_not_found (); + + found: + CAMLreturn (Val_int (r)); +} + +/* Extract endian 32 and 64 bit integers (or pointers) from strings. */ +value +virt_dmesg_str_get_le32 (value strv, value offv) +{ + CAMLparam2 (strv, offv); + CAMLlocal1 (rv); + const char *str = String_val (strv); + int off = Int_val (offv); + uint64_t r; + + r = le32toh (*(const uint32_t *)(str + off)); + rv = caml_copy_int64 (r); + + CAMLreturn (rv); +} + +value +virt_dmesg_str_get_be32 (value strv, value offv) +{ + CAMLparam2 (strv, offv); + CAMLlocal1 (rv); + const char *str = String_val (strv); + int off = Int_val (offv); + uint64_t r; + + r = be32toh (*(const uint32_t *)(str + off)); + rv = caml_copy_int64 (r); + + CAMLreturn (rv); +} + +value +virt_dmesg_str_get_le64 (value strv, value offv) +{ + CAMLparam2 (strv, offv); + CAMLlocal1 (rv); + const char *str = String_val (strv); + int off = Int_val (offv); + uint64_t r; + + r = le64toh (*(const uint64_t *)(str + off)); + rv = caml_copy_int64 (r); + + CAMLreturn (rv); +} + +value +virt_dmesg_str_get_be64 (value strv, value offv) +{ + CAMLparam2 (strv, offv); + CAMLlocal1 (rv); + const char *str = String_val (strv); + int off = Int_val (offv); + uint64_t r; + + r = be64toh (*(const uint64_t *)(str + off)); + rv = caml_copy_int64 (r); + + CAMLreturn (rv); +} + +/* Convert integers of various endianness/word size to strings of bytes. + * + * str_of_*32 returns a 4 byte string + * str_of_*64 returns an 8 byte string + */ +value +virt_dmesg_str_of_le32 (value addrv) +{ + CAMLparam1 (addrv); + CAMLlocal1 (rv); + const char *str; + + rv = caml_alloc_string (4); + str = String_val (rv); + *(uint32_t *)str = htole32 (Int64_val (addrv)); + + CAMLreturn (rv); +} + +value +virt_dmesg_str_of_be32 (value addrv) +{ + CAMLparam1 (addrv); + CAMLlocal1 (rv); + const char *str; + + rv = caml_alloc_string (4); + str = String_val (rv); + *(uint32_t *)str = htobe32 (Int64_val (addrv)); + + CAMLreturn (rv); +} + +value +virt_dmesg_str_of_le64 (value addrv) +{ + CAMLparam1 (addrv); + CAMLlocal1 (rv); + const char *str; + + rv = caml_alloc_string (8); + str = String_val (rv); + *(uint64_t *)str = htole64 (Int64_val (addrv)); + + CAMLreturn (rv); +} + +value +virt_dmesg_str_of_be64 (value addrv) +{ + CAMLparam1 (addrv); + CAMLlocal1 (rv); + const char *str; + + rv = caml_alloc_string (8); + str = String_val (rv); + *(uint64_t *)str = htobe64 (Int64_val (addrv)); + + CAMLreturn (rv); +} + +/* Get NUL-terminated (ASCIIZ) string at the given offset. + * + * get_asciiz : string -> int -> string + */ +value +virt_dmesg_get_asciiz (value strv, value offv) +{ + CAMLparam2 (strv, offv); + CAMLlocal1 (rv); + const char *str = String_val (strv); + size_t len = caml_string_length (strv); + int off = Int_val (offv); + size_t rlen; + + /* Work out the length of the return value. */ + for (rlen = 0; off+rlen < len; ++rlen) + if (str[off+rlen] == '\0') + break; + + rv = caml_alloc_string (rlen); + /* Previous allocation could have moved the input string, so ... */ + str = String_val (strv); + + memcpy (String_val (rv), &str[off], rlen); + + CAMLreturn (rv); +} + +/* Return true iff what is at the offset is plausibly a C programming + * language identifier. + * + * is_C_ident : string -> int -> bool + */ +value +virt_dmesg_is_C_ident (value strv, value offv) +{ + CAMLparam2 (strv, offv); + const char *str = String_val (strv); + size_t len = caml_string_length (strv); + int off = Int_val (offv); + size_t i; + int r = 1 /* true */; + + if (str[off] != '_' && !(str[off] >= 'A' && str[off] <= 'Z' || + str[off] >= 'a' && str[off] <= 'z')) { + r = 0 /* false */; + goto out; + } + + for (i = 1; off+i < len; ++i) { + if (str[off+i] == '\0') + break; + + if (str[off+i] != '_' && !(str[off+i] >= 'A' && str[off+i] <= 'Z' || + str[off+i] >= 'a' && str[off+i] <= 'z' || + str[off+i] >= '0' && str[off+i] <= '9')) { + r = 0 /* false */; + goto out; + } + } + + out: + CAMLreturn (Val_int (r)); +} + +/* external crc32_of_string : string -> int32 */ +value +virt_dmesg_crc32_of_string (value strv) +{ + CAMLparam1 (strv); + CAMLlocal1 (rv); + uLong r; + + r = crc32 (0, Z_NULL, 0); + r = crc32 (r, String_val (strv), caml_string_length (strv)); + + rv = caml_copy_int32 (r); + CAMLreturn (rv); +}