1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Stub implementations of firmware-provided API functions.
6 */
7
8#include <execinfo.h>
9#include <stdint.h>
10
11#define _STUB_IMPLEMENTATION_
12
13#include <stdarg.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/time.h>
18
19#include "vboot_api.h"
20
21#define MAX_STACK_LEVELS 10
22
23
24/* Keep track of nodes that are currently allocated */
25struct alloc_node {
26	struct alloc_node *next;
27	void *ptr;
28	size_t size;
29	void *bt_buffer[MAX_STACK_LEVELS];
30	int bt_levels;
31};
32
33static struct alloc_node *alloc_head;
34
35static void print_stacktrace(void)
36{
37	void *buffer[MAX_STACK_LEVELS];
38	int levels = backtrace(buffer, MAX_STACK_LEVELS);
39
40	// print to stderr (fd = 2), and remove this function from the trace
41	backtrace_symbols_fd(buffer + 1, levels - 1, 2);
42}
43
44void *VbExMalloc(size_t size)
45{
46	struct alloc_node *node;
47	void *p = malloc(size);
48
49	if (!p) {
50		/* Fatal Error. We must abort. */
51		abort();
52	}
53
54	node = malloc(sizeof(*node));
55	if (!node)
56		abort();
57	node->next = alloc_head;
58	node->ptr = p;
59	node->size = size;
60	node->bt_levels = backtrace(node->bt_buffer, MAX_STACK_LEVELS);
61	alloc_head = node;
62
63	return p;
64}
65
66static struct alloc_node **find_node(void *ptr)
67{
68	struct alloc_node **nodep;
69
70	for (nodep = &alloc_head; *nodep; nodep = &(*nodep)->next)
71		if ((*nodep)->ptr == ptr)
72			return nodep;
73
74	return NULL;
75}
76
77void VbExFree(void *ptr)
78{
79	struct alloc_node **nodep, *next;
80
81	nodep = find_node(ptr);
82	if (nodep) {
83		next = (*nodep)->next;
84		free(*nodep);
85		*nodep = next;
86	} else {
87		fprintf(stderr, "\n>>>>>> Invalid VbExFree() %p\n", ptr);
88		fflush(stderr);
89		print_stacktrace();
90		/*
91		 * Fall through and do the free() so we get normal error
92		 * handling.
93		 */
94	}
95
96	free(ptr);
97}
98
99VbError_t VbExHashFirmwareBody(VbCommonParams *cparams,
100                               uint32_t firmware_index)
101{
102	return VBERROR_SUCCESS;
103}
104
105int vboot_api_stub_check_memory(void)
106{
107	struct alloc_node *node, *next;
108
109	if (!alloc_head)
110		return 0;
111
112	/*
113	 * Make sure we free all our memory so that valgrind doesn't complain
114	 * about leaked memory.
115	 */
116	fprintf(stderr, "\nWarning, some allocations not freed:");
117	for (node = alloc_head; node; node = next) {
118		next = node->next;
119		fprintf(stderr, "\nptr=%p, size=%zd\n", node->ptr, node->size);
120		fflush(stderr);
121		backtrace_symbols_fd(node->bt_buffer + 1, node->bt_levels - 1,
122				     2);
123		free(node);
124	}
125
126	return -1;
127}
128