diff options
author | Randall Spangler <rspangler@chromium.org> | 2011-07-07 10:30:25 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2011-07-08 09:17:07 -0700 |
commit | bebe53c9193dbe875d793c7cb124ed66e610e1bd (patch) | |
tree | 8933d26b404b4a477d99ef97d2507431e8c1210b | |
parent | 93cf15e9a1c29962d6f08be6102d2ea7876d969f (diff) | |
download | vboot-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/Makefile | 1 | ||||
-rw-r--r-- | firmware/include/utility.h | 18 | ||||
-rw-r--r-- | firmware/lib/utility_string.c | 71 | ||||
-rw-r--r-- | tests/Makefile | 2 | ||||
-rw-r--r-- | tests/utility_string_tests.c | 121 |
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; +} |