Add helper functions and files for gpt tests.

Review URL: http://codereview.chromium.org/1729006
diff --git a/cgptlib/Makefile b/cgptlib/Makefile
new file mode 100644
index 0000000..418163c
--- /dev/null
+++ b/cgptlib/Makefile
@@ -0,0 +1,24 @@
+# Copyright (c) 2010 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.
+
+CFLAGS ?= -Wall -Werror -ansi
+INCLUDES += tests
+SUBDIRS = tests
+
+all: cgpt.a
+	for i in $(SUBDIRS); do \
+	( cd $$i ; $(MAKE)) ; \
+	done
+
+.c.o:
+	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+cgpt.a: cgpt.o
+	$(AR) rs cgpt.a $<
+
+clean:
+	for i in $(SUBDIRS); do \
+	( $(MAKE) -C $$i clean ) ; \
+	done
+	rm -f cgpt cgpt-host *.o *~ *.a
diff --git a/cgptlib/cgpt.c b/cgptlib/cgpt.c
index 4504a61..4865473 100644
--- a/cgptlib/cgpt.c
+++ b/cgptlib/cgpt.c
@@ -4,24 +4,42 @@
  */
 
 #include "cgpt.h"
+#include <string.h>
+#include "gpt.h"
+#include "utility.h"
 
 /* stub code */
 static int start[] = { 34, 10034 };
 
-int GPTInit(GPTData_t *gpt) {
+int GptInit(GptData_t *gpt) {
+  int valid_headers[2] = {1, 1};
+
+  /* check header signature */
+  if (Memcmp(gpt->primary_header, GPT_HEADER_SIGNATURE,
+                                  GPT_HEADER_SIGNATURE_SIZE))
+    valid_headers[0] = 0;
+  if (Memcmp(gpt->secondary_header, GPT_HEADER_SIGNATURE,
+                                  GPT_HEADER_SIGNATURE_SIZE))
+    valid_headers[1] = 0;
+
+  if (!valid_headers[0] && !valid_headers[1])
+    return GPT_ERROR_INVALID_HEADERS;
+
   gpt->current_kernel = 1;
-  return 0;
+  return GPT_SUCCESS;
 }
 
-int GPTNextKernelEntry(GPTData_t *gpt, uint64_t *start_sector, uint64_t *size) {
+int GptNextKernelEntry(GptData_t *gpt, uint64_t *start_sector, uint64_t *size) {
+  /* FIXME: the following code is not really code, just returns anything */
   gpt->current_kernel ^= 1;
   if (start_sector) *start_sector = start[gpt->current_kernel];
   if (size) *size = 10000;
-  return 0;
+  return GPT_SUCCESS;
 }
 
-int GPTUpdateKernelEntry(GPTData_t *gpt, uint32_t update_type) {
+int GptUpdateKernelEntry(GptData_t *gpt, uint32_t update_type) {
+  /* FIXME: the following code is not really code, just return anything */
   gpt->modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) <<
                    gpt->current_kernel;
-  return 0;
+  return GPT_SUCCESS;
 }
diff --git a/cgptlib/cgpt.h b/cgptlib/cgpt.h
index c9cd04d..ba32bb0 100644
--- a/cgptlib/cgpt.h
+++ b/cgptlib/cgpt.h
@@ -9,7 +9,8 @@
 #include <stdint.h>
 
 enum {
-  GPT_ERROR_NO_VALID_KERNEL = 1,
+  GPT_SUCCESS = 0,
+  GPT_ERROR_NO_VALID_KERNEL,
   GPT_ERROR_INVALID_HEADERS,
   GPT_ERROR_INVALID_ENTRIES,
   GPT_ERROR_INVALID_SECTOR_SIZE,
@@ -28,32 +29,32 @@
   /* The currently selected kernel partition failed validation.  Mark entry as
    * invalid. */
 
-struct GPTData {
-  /* Fill in the following fields before calling GPTInit() */
-  uint8_t *header1;       /* GPT primary header, from sector 1 of disk
-                           *   (size: 512 bytes) */
-  uint8_t *header2;       /* GPT secondary header, from last sector of
-                           *   disk (size: 512 bytes) */
-  uint8_t *entries1;      /* primary GPT table, follows primary header
-                           *   (size: 16 KB) */
-  uint8_t *entries2;      /* secondary GPT table, precedes secondary
-                           *   header (size: 16 KB) */
-  uint32_t sector_bytes;  /* Size of a LBA sector, in bytes */
-  uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */
+struct GptData {
+  /* Fill in the following fields before calling GptInit() */
+  uint8_t *primary_header;       /* GPT primary header, from sector 1 of disk
+                                  *   (size: 512 bytes) */
+  uint8_t *secondary_header;     /* GPT secondary header, from last sector of
+                                  *   disk (size: 512 bytes) */
+  uint8_t *primary_entries;      /* primary GPT table, follows primary header
+                                  *   (size: 16 KB) */
+  uint8_t *secondary_entries;    /* secondary GPT table, precedes secondary
+                                  *   header (size: 16 KB) */
+  uint32_t sector_bytes;         /* Size of a LBA sector, in bytes */
+  uint64_t drive_sectors;        /* Size of drive in LBA sectors, in sectors */
 
   /* Outputs */
-  uint8_t modified;       /* Which inputs have been modified?
-                           * 0x01 = header1
-                           * 0x02 = header2
-                           * 0x04 = table1
-                           * 0x08 = table2  */
+  uint8_t modified;              /* Which inputs have been modified?
+                                  * 0x01 = header1
+                                  * 0x02 = header2
+                                  * 0x04 = table1
+                                  * 0x08 = table2  */
 
   /* Internal state */
-  uint8_t current_kernel; // the current kernel index
+  uint8_t current_kernel; /* the current kernel index */
 };
-typedef struct GPTData GPTData_t;
+typedef struct GptData GptData_t;
 
-int GPTInit(GPTData_t *gpt);
+int GptInit(GptData_t *gpt);
 /* Initializes the GPT data structure's internal state.  The header1, header2,
  * table1, table2, and drive_size fields should be filled in first.
  *
@@ -69,7 +70,7 @@
  *   GPT_ERROR_INVALID_SECTOR_NUMBER, number of sectors in drive is invalid (too
  *                                    small) */
 
-int GPTNextKernelEntry(GPTData_t *gpt, uint64_t *start_sector, uint64_t *size);
+int GptNextKernelEntry(GptData_t *gpt, uint64_t *start_sector, uint64_t *size);
 /* Provides the location of the next kernel partition, in order of decreasing
  * priority.  On return the start_sector parameter contains the LBA sector
  * for the start of the kernel partition, and the size parameter contains the
@@ -78,7 +79,7 @@
  * Returns 0 if successful, else
  *   GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */
 
-int GPTUpdateKernelEntry(GPTData_t *gpt, uint32_t update_type);
+int GptUpdateKernelEntry(GptData_t *gpt, uint32_t update_type);
 /* Updates the kernel entry with the specified index, using the specified type
  * of update (GPT_UPDATE_ENTRY_*).
  *
diff --git a/cgptlib/gpt.h b/cgptlib/gpt.h
new file mode 100644
index 0000000..95f0efb
--- /dev/null
+++ b/cgptlib/gpt.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2010 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.
+ *
+ * Defines EFI related structure. See more details in EFI 2.3 spec.
+ *
+ * To download EFI standard, please visit UEFI homepage:
+ *    http://www.uefi.org/
+ */
+#ifndef VBOOT_REFERENCE_CGPTLIB_GPT_H_
+#define VBOOT_REFERENCE_CGPTLIB_GPT_H_
+
+#include <stdint.h>
+
+#define GPT_HEADER_SIGNATURE "EFI PART"
+#define GPT_HEADER_SIGNATURE_SIZE sizeof(GPT_HEADER_SIGNATURE)
+#define GPT_HEADER_REVISION 0x00010000
+
+#define GPT_ENT_TYPE_EFI \
+  {{Uuid: {0xc12a7328,0xf81f,0x11d2,0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}}}
+#define GPT_ENT_TYPE_UNUSED \
+  {{Uuid: {0x00000000,0x0000,0x0000,0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}}}
+#define GPT_ENT_TYPE_CHROMEOS_KERNEL \
+  {{Uuid: {0xfe3a2a5d,0x4f32,0x41a7,0xb7,0x25,{0xac,0xcc,0x32,0x85,0xa3,0x09}}}}
+#define GPT_ENT_TYPE_CHROMEOS_ROOTFS \
+  {{Uuid: {0x3cb8e202,0x3b7e,0x47dd,0x8a,0x3c,{0x7f,0xf2,0xa1,0x3c,0xfc,0xec}}}}
+#define GPT_ENT_TYPE_CHROMEOS_RESERVED \
+  {{Uuid: {0x2e0a753d,0x9e48,0x43b0,0x83,0x37,{0xb1,0x51,0x92,0xcb,0x1b,0x5e}}}}
+
+#define UUID_NODE_LEN 6
+#define GUID_SIZE 16
+
+/*  GUID definition.
+ *  Defined in appendix A of EFI standard.
+ */
+typedef struct {
+  union {
+    struct {
+      uint32_t time_low;
+      uint16_t time_mid;
+      uint16_t time_high_and_version;
+      uint8_t clock_seq_high_and_reserved;
+      uint8_t clock_seq_low;
+      uint8_t node[UUID_NODE_LEN];
+    } Uuid;
+    uint8_t raw[GUID_SIZE];
+  };
+} __attribute__((packed)) Guid;
+
+/* GPT header defines how many partitions exist on a drive and sectors managed.
+ * For every drive device, there are 2 headers, primary and secondary.
+ * Most of fields are duplicated except my_lba and entries_lba.
+ *
+ * You may find more details in chapter 5 of EFI standard.
+ */
+typedef struct {
+  char signature[8];
+  uint32_t revision;
+  uint32_t size;
+  uint32_t header_crc32;
+  uint32_t reserved;
+  uint64_t my_lba;
+  uint64_t alternate_lba;
+  uint64_t first_usable_lba;
+  uint64_t last_usable_lba;
+  Guid disk_uuid;
+
+  uint64_t entries_lba;
+  uint32_t number_of_entries;
+  uint32_t size_of_entry;
+  uint32_t entries_crc32;
+  uint32_t padding;  /* since header size must be a multiple of 8, pad here. */
+} GptHeader;
+
+/* GPT partition entry defines the starting and ending LBAs of a partition.
+ * It also contains the unique GUID, type, and attribute bits.
+ *
+ * You may find more details in chapter 5 of EFI standard.
+ */
+typedef struct {
+  Guid type;
+  Guid unique;
+  uint64_t starting_lba;
+  uint64_t ending_lba;
+  uint64_t attributes;
+  uint16_t name[36];  /* UTF-16 encoded partition name */
+} GptEntry;
+
+#endif  /* VBOOT_REFERENCE_CGPTLIB_GPT_H_ */
diff --git a/cgptlib/tests/Makefile b/cgptlib/tests/Makefile
new file mode 100644
index 0000000..60871fa
--- /dev/null
+++ b/cgptlib/tests/Makefile
@@ -0,0 +1,20 @@
+# Copyright (c) 2010 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.
+
+CC ?= cc
+CFLAGS ?= -Wall -DNDEBUG -Werror -ansi
+LIBS = ../cgpt.a ../../common/libcommon.a
+OBJS = cgpt_test.o
+OUT = cgpt_test
+
+all: $(OUT)
+
+$(OUT): $(OBJS) $(LIBS)
+	$(CC) -o $@ $^
+
+.c.o:
+	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+clean:
+	rm -rf $(OUT) $(OBJS)
diff --git a/cgptlib/tests/cgpt_test.c b/cgptlib/tests/cgpt_test.c
index b5b26e7..a451838 100644
--- a/cgptlib/tests/cgpt_test.c
+++ b/cgptlib/tests/cgpt_test.c
@@ -3,12 +3,219 @@
  * found in the LICENSE file.
  */
 
-#include "cgpt.h"
 #include "cgpt_test.h"
+#include <string.h>
+#include "cgpt.h"
+#include "gpt.h"
+#include "utility.h"
+
+/* Testing partition layout (sector_bytes=512)
+ *
+ *     LBA   Size  Usage
+ *       0      1  PMBR
+ *       1      1  primary partition header
+ *       2     32  primary partition entries (128B * 128)
+ *      34    100  kernel A
+ *     134    100  kernel B
+ *     234    100  root A
+ *     334    100  root B
+ *     434     32  secondary partition entries
+ *     466      1  secondary partition header
+ *     467
+ */
+#define DEFAULT_SECTOR_SIZE 512
+#define MAX_SECTOR_SIZE 4096
+#define DEFAULT_DRIVE_SECTORS 467
+#define PARTITION_ENTRIES_SIZE (16*1024)
 
 #define TEST_CASE(func) #func, func
 typedef int (*test_func)(void);
 
+/* NOT A REAL CRC32, it is fake before I call real one . FIXME */
+uint32_t CalculateCrc32(const uint8_t *start, size_t len) {
+  uint32_t buf = 0;
+  int i;
+  for (i = 0; i < len; i += 4, len -= 4) {
+    buf ^= *(uint32_t*)&start[i];
+  }
+  if (len >= 3) buf ^= start[i-2] << 16;
+  if (len >= 2) buf ^= start[i-3] << 8;
+  if (len >= 1) buf ^= start[i-4];
+  return buf;
+}
+
+/* Given a GptData pointer, first re-calculate entries CRC32 value,
+ * then reset header CRC32 value to 0, and calculate header CRC32 value.
+ * Both primary and secondary are updated. */
+void RefreshCrc32(struct GptData *gpt) {
+  GptHeader *header, *header2;
+  GptEntry *entries, *entries2;
+
+  header = (GptHeader*)gpt->primary_header;
+  entries = (GptEntry*)gpt->primary_entries;
+  header2 = (GptHeader*)gpt->secondary_header;
+  entries2 = (GptEntry*)gpt->secondary_entries;
+
+  header->entries_crc32 = CalculateCrc32((uint8_t*)entries,
+                                         sizeof(GptEntry));
+  header->header_crc32 = 0;
+  header->header_crc32 = CalculateCrc32((uint8_t*)header,
+                                        header->size);
+  header2->entries_crc32 = CalculateCrc32((uint8_t*)entries2,
+                                          sizeof(GptEntry));
+  header2->header_crc32 = 0;
+  header2->header_crc32 = CalculateCrc32((uint8_t*)header2,
+                                         header2->size);
+}
+
+/* Returns a pointer to a static GptData instance (no free is required).
+ * All fields are zero except 4 pointers linking to header and entries.
+ * All content of headers and entries are zero. */
+struct GptData* GetAClearGptData() {
+  static GptData_t gpt;
+  static uint8_t primary_header[MAX_SECTOR_SIZE];
+  static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
+  static uint8_t secondary_header[MAX_SECTOR_SIZE];
+  static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
+
+  Memset(&gpt, 0, sizeof(gpt));
+  Memset(&primary_header, 0, sizeof(primary_header));
+  Memset(&primary_entries, 0, sizeof(primary_entries));
+  Memset(&secondary_header, 0, sizeof(secondary_header));
+  Memset(&secondary_entries, 0, sizeof(secondary_entries));
+
+  gpt.primary_header = primary_header;
+  gpt.primary_entries = primary_entries;
+  gpt.secondary_header = secondary_header;
+  gpt.secondary_entries = secondary_entries;
+
+  return &gpt;
+}
+
+/* Fills in most of fields and creates the layout described in the top of this
+ * file. */
+struct GptData*
+BuildTestGptData(uint32_t sector_bytes) {
+  GptData_t *gpt;
+  GptHeader *header, *header2;
+  GptEntry *entries, *entries2;
+  Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
+
+  gpt = GetAClearGptData();
+  gpt->sector_bytes = sector_bytes;
+  gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
+
+  /* build primary */
+  header = (GptHeader*)gpt->primary_header;
+  entries = (GptEntry*)gpt->primary_entries;
+  Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
+  header->revision = GPT_HEADER_REVISION;
+  header->size = sizeof(GptHeader) - sizeof(header->padding);
+  header->my_lba = 1;
+  header->first_usable_lba = 34;
+  header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1;  /* 433 */
+  header->entries_lba = 2;
+  header->number_of_entries = 128;  /* 512B / 128B * 32sectors = 128 entries */
+  header->size_of_entry = 128;  /* bytes */
+  Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
+  entries[0].starting_lba = 34;
+  entries[0].ending_lba = 133;
+  Memcpy(&entries[1].type, &chromeos_kernel, sizeof(chromeos_kernel));
+  entries[1].starting_lba = 134;
+  entries[1].ending_lba = 233;
+  Memcpy(&entries[2].type, &chromeos_kernel, sizeof(chromeos_kernel));
+  entries[2].starting_lba = 234;
+  entries[2].ending_lba = 333;
+  Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
+  entries[3].starting_lba = 334;
+  entries[3].ending_lba = 433;
+
+  /* build secondary */
+  header2 = (GptHeader*)gpt->secondary_header;
+  entries2 = (GptEntry*)gpt->secondary_entries;
+  Memcpy(header2, header, sizeof(header));
+  Memcpy(entries2, entries, sizeof(entries));
+  header2->my_lba = DEFAULT_DRIVE_SECTORS - 1;  /* 466 */
+  header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32;  /* 434 */
+
+  RefreshCrc32(gpt);
+  return gpt;
+}
+
+/* Dumps memory starting from [vp] with [len] bytes.
+ * Prints [memo] if not NULL. Example output:
+ *
+ *  00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
+ *  10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
+ *  ...
+ */
+static void dump(void *vp, int len, char* memo) {
+  uint8_t *start = vp;
+  int i;
+  if (memo) printf("--[%s]----------\n", memo);
+  for (i = 0; i < len; ++i) {
+    printf("%02x%s", start[i],
+                     (!(~i & 15) ? "\n" :
+                      !(~i & 7) ? " - ": " "));
+  }
+  if (i&15) printf("\n");
+}
+
+/* More formatted dump with GptData. */
+void DumpGptData(struct GptData *gpt) {
+  printf("DumpGptData(%p)...\n", gpt);
+  dump(gpt, sizeof(gpt), NULL);
+  dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
+  dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
+  dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
+  dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
+       "Secondary entries");
+}
+
+/* Tests if signature ("EFI PART") is checked. */
+int SignatureTest() {
+  int i;
+  GptData_t *gpt;
+  GptHeader *primary_header, *secondary_header;
+
+  gpt = BuildTestGptData(DEFAULT_SECTOR_SIZE);
+  primary_header = (GptHeader*)gpt->primary_header;
+  secondary_header = (GptHeader*)gpt->secondary_header;
+
+  EXPECT(GPT_SUCCESS == GptInit(gpt));
+
+  /* change every char in signature of primary. Secondary is still valid. */
+  for (i = 0; i < 8; ++i) {
+    gpt->primary_header[i] ^= 0xff;
+    RefreshCrc32(gpt);
+    EXPECT(GPT_SUCCESS == GptInit(gpt));
+    gpt->primary_header[i] ^= 0xff;
+    RefreshCrc32(gpt);
+  }
+
+  /* change every char in signature of secondary. Primary is still valid. */
+  for (i = 0; i < 8; ++i) {
+    gpt->secondary_header[i] ^= 0xff;
+    RefreshCrc32(gpt);
+    EXPECT(GPT_SUCCESS == GptInit(gpt));
+    gpt->secondary_header[i] ^= 0xff;
+    RefreshCrc32(gpt);
+  }
+
+  /* change every char in signature of primary and secondary. Expect fail. */
+  for (i = 0; i < 8; ++i) {
+    gpt->primary_header[i] ^= 0xff;
+    gpt->secondary_header[i] ^= 0xff;
+    RefreshCrc32(gpt);
+    EXPECT(GPT_ERROR_INVALID_HEADERS == GptInit(gpt));
+    gpt->primary_header[i] ^= 0xff;
+    gpt->secondary_header[i] ^= 0xff;
+    RefreshCrc32(gpt);
+  }
+
+  return TEST_OK;
+}
+
 /* Tests if header CRC in two copies are calculated. */
 int HeaderCrcTest() {
   return TEST_FAIL;
@@ -45,7 +252,7 @@
   return TEST_FAIL;
 }
 
-/* Tests if GPTInit() handles non-identical partition entries well.
+/* Tests if GptInit() handles non-identical partition entries well.
  * Two copies of partition table entries must be identical. If not, we trust the
  * primary table entries, and mark secondary as modified (see Caller's write-
  * back order below). */
@@ -53,7 +260,7 @@
   return TEST_FAIL;
 }
 
-/* Tests if GPTInit() handles non-identical headers well.
+/* Tests if GptInit() handles non-identical headers well.
  * Two partition headers must be identical. If not, we trust the primary
  * partition header, and mark secondary as modified (see Caller's write-back
  * order below). */
@@ -84,7 +291,7 @@
   return TEST_FAIL;
 }
 
-/* Tests if GPTNextKernelEntry() can survive in different corrupt header/entries
+/* Tests if GptNextKernelEntry() can survive in different corrupt header/entries
  * combinations, like:
  *   primary GPT header         - valid
  *   primary partition table    - invalid
@@ -102,6 +309,8 @@
     test_func fp;
     int retval;
   } test_cases[] = {
+    { TEST_CASE(SignatureTest), },
+#if 0
     { TEST_CASE(HeaderCrcTest), },
     { TEST_CASE(MyLbaTest), },
     { TEST_CASE(SizeOfPartitionEntryTest), },
@@ -114,6 +323,7 @@
     { TEST_CASE(ValidEntryTest), },
     { TEST_CASE(NoOverlappedPartitionTest), },
     { TEST_CASE(CorruptCombinationTest), },
+#endif
   };
 
   for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
diff --git a/cgptlib/tests/cgpt_test.h b/cgptlib/tests/cgpt_test.h
index 0dcb637..4a8b115 100644
--- a/cgptlib/tests/cgpt_test.h
+++ b/cgptlib/tests/cgpt_test.h
@@ -7,7 +7,10 @@
 
 #include <stdio.h>
 
-#define TEST_FAIL -1
+enum {
+  TEST_FAIL = -1,
+  TEST_OK = 0,
+};
 
 /* ANSI Color coding sequences. */
 #define COL_GREEN "\e[1;32m"
diff --git a/common/include/utility.h b/common/include/utility.h
index 8619cd2..a5df8fa 100644
--- a/common/include/utility.h
+++ b/common/include/utility.h
@@ -40,6 +40,12 @@
 /* Free memory pointed by [ptr] previously allocated by Malloc(). */
 void Free(void* ptr);
 
+/* Compare [n] bytes in [src1] and [src2]
+ * Returns an integer less than, equal to, or greater than zero if the first [n]
+ * bytes of [src1] is found, respectively, to be less than, to match, or be
+ * greater than the first n bytes of [src2]. */
+int Memcmp(const void* src1, const void* src2, size_t n);
+
 /* Copy [n] bytes from [src] to [dest]. */
 void* Memcpy(void* dest, const void* src, size_t n);
 
diff --git a/common/utility_stub.c b/common/utility_stub.c
index d2244c7..6613270 100644
--- a/common/utility_stub.c
+++ b/common/utility_stub.c
@@ -42,6 +42,10 @@
   free(ptr);
 }
 
+int Memcmp(const void* src1, const void* src2, size_t n) {
+  return memcmp(src1, src2, n);
+}
+
 void* Memcpy(void* dest, const void* src, size_t n) {
   return memcpy(dest, src, n);
 }