2 * (C) Copyright 2008-2011 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* This contains functions written in C. We can drop into C wherever
20 * we need to do something that would be much faster than OCaml or
21 * where it's just awkward to do something in OCaml or much easier in
36 #include <caml/alloc.h>
37 #include <caml/fail.h>
38 #include <caml/memory.h>
39 #include <caml/mlvalues.h>
41 /* This vital function returns the offset of the virtual address
42 * relative to the base address. If the virtual address is outside
43 * the kernel, then it returns -1.
45 * Note that the function is declared "noalloc" for speed. It must
46 * not allocate anything on the OCaml heap.
48 * str_mapping : int64 -> int64 -> int -> int
51 virt_dmesg_str_mapping (value base_addrv, value addrv, value str_lenv)
53 uint64_t base_addr = Int64_val (base_addrv);
54 uint64_t addr = Int64_val (addrv);
55 int str_len = Int_val (str_lenv);
58 off = addr - base_addr;
65 /* NOTE: Declared as a "noalloc" function for speed. */
67 virt_dmesg_addr_compare (value a1v, value a2v)
69 uint64_t a1 = Int64_val (a1v);
70 uint64_t a2 = Int64_val (a2v);
73 return (Val_int (-1));
80 /* Find 'needle' in 'haystack', but start searching haystack from 'off'.
82 * strstr_from : string -> string -> int -> int
85 virt_dmesg_strstr_from (value haystackv, value needlev, value offv)
87 CAMLparam3 (haystackv, needlev, offv);
88 const char *haystack = String_val (haystackv);
89 int off = Int_val (offv);
93 /* Because OCaml strings can contain '\0' characters, use memmem
96 r = memmem (haystack + off, caml_string_length (haystackv) - off,
97 String_val (needlev), caml_string_length (needlev));
99 caml_raise_not_found ();
102 CAMLreturn (Val_int (i));
105 /* This is like 'strstr_from' but it only tests for aligned 'needle',
106 * eg. if 'needle' was 4 bytes long then it would only look every 4
110 virt_dmesg_strstr_from_aligned (value haystackv, value needlev, value offv)
112 CAMLparam3 (haystackv, needlev, offv);
113 const char *haystack = String_val (haystackv);
114 size_t haystack_len = caml_string_length (haystackv);
115 const char *needle = String_val (needlev);
116 size_t needle_len = caml_string_length (needlev);
117 int off = Int_val (offv);
120 for (r = off; r < haystack_len; r += needle_len) {
121 if (memcmp (haystack + r, needle, needle_len) == 0)
124 caml_raise_not_found ();
127 CAMLreturn (Val_int (r));
130 /* Extract endian 32 and 64 bit integers (or pointers) from strings. */
132 virt_dmesg_str_get_le32 (value strv, value offv)
134 CAMLparam2 (strv, offv);
136 const char *str = String_val (strv);
137 int off = Int_val (offv);
140 r = le32toh (*(const uint32_t *)(str + off));
141 rv = caml_copy_int64 (r);
147 virt_dmesg_str_get_be32 (value strv, value offv)
149 CAMLparam2 (strv, offv);
151 const char *str = String_val (strv);
152 int off = Int_val (offv);
155 r = be32toh (*(const uint32_t *)(str + off));
156 rv = caml_copy_int64 (r);
162 virt_dmesg_str_get_le64 (value strv, value offv)
164 CAMLparam2 (strv, offv);
166 const char *str = String_val (strv);
167 int off = Int_val (offv);
170 r = le64toh (*(const uint64_t *)(str + off));
171 rv = caml_copy_int64 (r);
177 virt_dmesg_str_get_be64 (value strv, value offv)
179 CAMLparam2 (strv, offv);
181 const char *str = String_val (strv);
182 int off = Int_val (offv);
185 r = be64toh (*(const uint64_t *)(str + off));
186 rv = caml_copy_int64 (r);
191 /* Convert integers of various endianness/word size to strings of bytes.
193 * str_of_*32 returns a 4 byte string
194 * str_of_*64 returns an 8 byte string
197 virt_dmesg_str_of_le32 (value addrv)
203 rv = caml_alloc_string (4);
204 str = String_val (rv);
205 *(uint32_t *)str = htole32 (Int64_val (addrv));
211 virt_dmesg_str_of_be32 (value addrv)
217 rv = caml_alloc_string (4);
218 str = String_val (rv);
219 *(uint32_t *)str = htobe32 (Int64_val (addrv));
225 virt_dmesg_str_of_le64 (value addrv)
231 rv = caml_alloc_string (8);
232 str = String_val (rv);
233 *(uint64_t *)str = htole64 (Int64_val (addrv));
239 virt_dmesg_str_of_be64 (value addrv)
245 rv = caml_alloc_string (8);
246 str = String_val (rv);
247 *(uint64_t *)str = htobe64 (Int64_val (addrv));
252 /* Get NUL-terminated (ASCIIZ) string at the given offset.
254 * get_asciiz : string -> int -> string
257 virt_dmesg_get_asciiz (value strv, value offv)
259 CAMLparam2 (strv, offv);
261 const char *str = String_val (strv);
262 size_t len = caml_string_length (strv);
263 int off = Int_val (offv);
266 /* Work out the length of the return value. */
267 for (rlen = 0; off+rlen < len; ++rlen)
268 if (str[off+rlen] == '\0')
271 rv = caml_alloc_string (rlen);
272 /* Previous allocation could have moved the input string, so ... */
273 str = String_val (strv);
275 memcpy (String_val (rv), &str[off], rlen);
280 /* Return true iff what is at the offset is plausibly a C programming
281 * language identifier.
283 * is_C_ident : string -> int -> bool
286 virt_dmesg_is_C_ident (value strv, value offv)
288 CAMLparam2 (strv, offv);
289 const char *str = String_val (strv);
290 size_t len = caml_string_length (strv);
291 int off = Int_val (offv);
293 int r = 1 /* true */;
295 if (str[off] != '_' && !(str[off] >= 'A' && str[off] <= 'Z' ||
296 str[off] >= 'a' && str[off] <= 'z')) {
301 for (i = 1; off+i < len; ++i) {
302 if (str[off+i] == '\0')
305 if (str[off+i] != '_' && !(str[off+i] >= 'A' && str[off+i] <= 'Z' ||
306 str[off+i] >= 'a' && str[off+i] <= 'z' ||
307 str[off+i] >= '0' && str[off+i] <= '9')) {
314 CAMLreturn (Val_int (r));
317 /* external crc32_of_string : string -> int32 */
319 virt_dmesg_crc32_of_string (value strv)
325 r = crc32 (0, Z_NULL, 0);
326 r = crc32 (r, String_val (strv), caml_string_length (strv));
328 rv = caml_copy_int32 (r);