summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-07-07 10:30:25 -0700
committerRandall Spangler <rspangler@chromium.org>2011-07-08 09:17:07 -0700
commitbebe53c9193dbe875d793c7cb124ed66e610e1bd (patch)
tree8933d26b404b4a477d99ef97d2507431e8c1210b
parent93cf15e9a1c29962d6f08be6102d2ea7876d969f (diff)
downloadvboot-bebe53c9193dbe875d793c7cb124ed66e610e1bd.tar.gz
Add string utility functions.
These are used by the coming-soon vboot wrapper (vboot_api_kernel) to display debug information when Tab is pressed at a BIOS screen. BUG=chromium-os:17035 TEST=make && make runtests (runs new test!) Change-Id: I4893f31e9333f4e9d458a6e347213eef22f770cd Reviewed-on: http://gerrit.chromium.org/gerrit/3759 Reviewed-by: Bill Richardson <wfrichar@chromium.org> Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--firmware/Makefile1
-rw-r--r--firmware/include/utility.h18
-rw-r--r--firmware/lib/utility_string.c71
-rw-r--r--tests/Makefile2
-rw-r--r--tests/utility_string_tests.c121
5 files changed, 213 insertions, 0 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
index bdc4ca02..72e813e3 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -59,6 +59,7 @@ LIB_SRCS = \
./lib/cryptolib/sha_utility.c \
./lib/stateful_util.c \
./lib/utility.c \
+ ./lib/utility_string.c \
./lib/vboot_common.c \
./lib/vboot_firmware.c \
./lib/vboot_kernel.c \
diff --git a/firmware/include/utility.h b/firmware/include/utility.h
index 3de8bb8a..b1472673 100644
--- a/firmware/include/utility.h
+++ b/firmware/include/utility.h
@@ -87,6 +87,24 @@ void* Memset(void *dest, const uint8_t c, uint64_t n);
*/
int SafeMemcmp(const void* s1, const void* s2, size_t n);
+/* Buffer size required to hold the longest possible output of
+ * Uint64ToString() - that is, Uint64ToString(~0, 2). */
+#define UINT64_TO_STRING_MAX 65
+
+/* Convert a value to a string in the specified radix (2=binary, 10=decimal,
+ * 16=hex) and store it in <buf>, which is <bufsize> chars long. If
+ * <zero_pad_width>, left-pads the string to at least that width with '0'.
+ * Returns the length of the stored string, not counting the terminating
+ * null. */
+uint32_t Uint64ToString(char *buf, uint32_t bufsize, uint64_t value,
+ uint32_t radix, uint32_t zero_pad_width);
+
+/* Concatenate <src> onto <dest>, which has space for <destlen> characters
+ * including the terminating null. Note that <dest> will always be
+ * null-terminated if <destlen> > 0. Returns the number of characters
+ * used in <dest>, not counting the terminating null. */
+uint32_t Strncat(char *dest, const char *src, uint32_t destlen);
+
/* Ensure that only our stub implementations are used, not standard C */
#ifndef _STUB_IMPLEMENTATION_
#define malloc _do_not_use_standard_malloc
diff --git a/firmware/lib/utility_string.c b/firmware/lib/utility_string.c
new file mode 100644
index 00000000..424c3e33
--- /dev/null
+++ b/firmware/lib/utility_string.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * String utility functions that need to be built as part of the firmware.
+ */
+
+#include "sysincludes.h"
+#include "utility.h"
+
+
+uint32_t Uint64ToString(char *buf, uint32_t bufsize, uint64_t value,
+ uint32_t radix, uint32_t zero_pad_width) {
+ char ibuf[UINT64_TO_STRING_MAX];
+ char *s;
+ uint32_t usedsize = 1;
+
+ if (!buf)
+ return 0;
+
+ /* Clear output buffer in case of error */
+ *buf = '\0';
+
+ /* Sanity-check input args */
+ if (radix < 2 || radix > 36 || zero_pad_width >= UINT64_TO_STRING_MAX)
+ return 0;
+
+ /* Start at end of string and work backwards */
+ s = ibuf + UINT64_TO_STRING_MAX - 1;
+ *(s) = '\0';
+ do {
+ int v = value % radix;
+ value /= radix;
+
+ *(--s) = (char)(v < 10 ? v + '0' : v + 'a' - 10);
+ if (++usedsize > bufsize)
+ return 0; /* Result won't fit in buffer */
+ } while (value);
+
+ /* Zero-pad if necessary */
+ while (usedsize <= zero_pad_width) {
+ *(--s) = '0';
+ if (++usedsize > bufsize)
+ return 0; /* Result won't fit in buffer */
+ }
+
+ /* Now copy the string back to the input buffer. */
+ Memcpy(buf, s, usedsize);
+
+ /* Don't count the terminating null in the bytes used */
+ return usedsize - 1;
+}
+
+
+uint32_t Strncat(char *dest, const char *src, uint32_t destlen) {
+ uint32_t used = 0;
+
+ if (!dest || !src)
+ return 0;
+
+ /* Skip past existing string in destination.*/
+ while (dest[used] && used < destlen - 1)
+ used++;
+ /* Now copy source */
+ while (*src && used < destlen - 1)
+ dest[used++] = *src++;
+
+ /* Terminate destination and return count of non-null characters */
+ dest[used] = 0;
+ return used;
+}
diff --git a/tests/Makefile b/tests/Makefile
index e97bbe11..e2a4af53 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -15,6 +15,7 @@ TEST_NAMES = cgptlib_test \
rsa_verify_benchmark \
sha_benchmark \
sha_tests \
+ utility_string_tests \
vboot_common_tests \
vboot_common2_tests \
vboot_common3_tests \
@@ -90,6 +91,7 @@ runcryptotests:
# Run other misc tests
runmisctests:
./run_vbutil_tests.sh
+ ${BUILD_ROOT}/utility_string_tests
#This will exercise vbutil_kernel and vbutil_firmware
runfuzztests:
diff --git a/tests/utility_string_tests.c b/tests/utility_string_tests.c
new file mode 100644
index 00000000..91f57146
--- /dev/null
+++ b/tests/utility_string_tests.c
@@ -0,0 +1,121 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for string utility functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_common.h"
+#include "utility.h"
+#include "vboot_common.h"
+
+
+/* Test string concatenation */
+static void StrncatTest(void) {
+ char dest[128];
+
+ /* Null inputs */
+ TEST_EQ(0, Strncat(dest, NULL, sizeof(dest)), "Strncat('', null)");
+ TEST_EQ(0, Strncat(NULL, "Hey!", sizeof(dest)), "Strncat(null, '')");
+
+ /* Empty <-- empty */
+ *dest = 0;
+ TEST_EQ(0, Strncat(dest, "", sizeof(dest)), "Strncat('', '')");
+ TEST_EQ(0, strcmp(dest, ""), "Strncat('', '') result");
+
+ /* Nonempty <-- empty */
+ strcpy(dest, "Bob");
+ TEST_EQ(3, Strncat(dest, "", sizeof(dest)), "Strncat(B, '')");
+ TEST_EQ(0, strcmp(dest, "Bob"), "Strncat(B, '') result");
+
+ /* Empty <-- nonempty */
+ *dest = 0;
+ TEST_EQ(5, Strncat(dest, "Alice", sizeof(dest)), "Strncat('', A)");
+ TEST_EQ(0, strcmp(dest, "Alice"), "Strncat('', A) result");
+
+ /* Nonempty <-- nonempty */
+ strcpy(dest, "Tigre");
+ TEST_EQ(10, Strncat(dest, "Bunny", sizeof(dest)), "Strncat(T, B)");
+ TEST_EQ(0, strcmp(dest, "TigreBunny"), "Strncat(T, B) result");
+
+ /* Test clipping */
+ strcpy(dest, "YesI");
+ TEST_EQ(7, Strncat(dest, "Can't", 8), "Strncat(Y, over)");
+ TEST_EQ(0, strcmp(dest, "YesICan"), "Strncat(Y, over) result");
+
+ /* Test clipping if dest already overflows its claimed length */
+ strcpy(dest, "BudgetDeficit");
+ TEST_EQ(6, Strncat(dest, "Spending", 7), "Strncat(over, over)");
+ TEST_EQ(0, strcmp(dest, "Budget"), "Strncat(over, over) result");
+}
+
+
+static void TestU64ToS(uint64_t value, uint32_t radix, uint32_t zero_pad_width,
+ const char *expect) {
+ char dest[UINT64_TO_STRING_MAX];
+
+ TEST_EQ(strlen(expect),
+ Uint64ToString(dest, sizeof(dest), value, radix, zero_pad_width),
+ "Uint64ToString");
+ printf("Uint64ToString expect %s got %s\n", expect, dest);
+ TEST_EQ(0, strcmp(dest, expect), "Uint64ToString result");
+}
+
+
+/* Test uint64 to string conversion */
+static void Uint64ToStringTest(void) {
+ char dest[UINT64_TO_STRING_MAX];
+
+ /* Test invalid inputs */
+ TEST_EQ(0, Uint64ToString(NULL, 8, 123, 10, 8), "Uint64ToString null dest");
+ TestU64ToS(0, 1, 0, "");
+ TestU64ToS(0, 37, 0, "");
+
+ /* Binary */
+ TestU64ToS(0, 2, 0, "0");
+ TestU64ToS(0x9A, 2, 0, "10011010");
+ TestU64ToS(0x71, 2, 12, "000001110001");
+ TestU64ToS(
+ ~UINT64_C(0), 2, 0,
+ "1111111111111111111111111111111111111111111111111111111111111111");
+
+ /* Decimal */
+ TestU64ToS(0, 10, 0, "0");
+ TestU64ToS(12345, 10, 0, "12345");
+ TestU64ToS(67890, 10, 8, "00067890");
+ TestU64ToS(~UINT64_C(0), 10, 0, "18446744073709551615");
+
+ /* Hex */
+ TestU64ToS(0, 16, 0, "0");
+ TestU64ToS(0x12345678, 16, 0, "12345678");
+ TestU64ToS(0x9ABCDEF, 16, 8, "09abcdef");
+ TestU64ToS(~UINT64_C(0), 16, 0, "ffffffffffffffff");
+
+ /* Zero pad corner cases */
+ /* Don't pad if over length */
+ TestU64ToS(0x1234567890, 16, 8, "1234567890");
+ /* Fail if padding won't fit in buffer */
+ TEST_EQ(0, Uint64ToString(dest, 8, 123, 10, 8), "Uint64ToString bad pad");
+ TEST_EQ(0, strcmp(dest, ""), "Uint64ToString bad pad result");
+
+}
+
+
+/* disable MSVC warnings on unused arguments */
+__pragma(warning (disable: 4100))
+
+int main(int argc, char* argv[]) {
+ int error_code = 0;
+
+ StrncatTest();
+ Uint64ToStringTest();
+
+ if (!gTestSuccess)
+ error_code = 255;
+
+ return error_code;
+}