summaryrefslogtreecommitdiff
path: root/firmware/stub/vboot_api_stub_sf.c
blob: 76d45ee8ec487ec37363a17d083f031733f6bc36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* Copyright (c) 2013 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.
 *
 * Stub implementations of firmware-provided API functions.
 */

/* Musl doesn't have execinfo.h.
   TODO(dje): Add a replacement (libunwind) if/when fnl needs it.  */
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif

#include <stdint.h>

#define _STUB_IMPLEMENTATION_

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>

#include "vboot_api.h"

#define MAX_STACK_LEVELS 10


/* Keep track of nodes that are currently allocated */
struct alloc_node {
	struct alloc_node *next;
	void *ptr;
	size_t size;
#ifdef HAVE_EXECINFO_H
	void *bt_buffer[MAX_STACK_LEVELS];
	int bt_levels;
#endif
};

static struct alloc_node *alloc_head;

#ifdef HAVE_EXECINFO_H
static void print_stacktrace(void)
{
	void *buffer[MAX_STACK_LEVELS];
	int levels = backtrace(buffer, MAX_STACK_LEVELS);

	// print to stderr (fd = 2), and remove this function from the trace
	backtrace_symbols_fd(buffer + 1, levels - 1, 2);
}
#endif

void *VbExMalloc(size_t size)
{
	struct alloc_node *node;
	void *p = malloc(size);

	if (!p) {
		/* Fatal Error. We must abort. */
		abort();
	}

	node = malloc(sizeof(*node));
	if (!node)
		abort();
	node->next = alloc_head;
	node->ptr = p;
	node->size = size;
#ifdef HAVE_EXECINFO_H
	node->bt_levels = backtrace(node->bt_buffer, MAX_STACK_LEVELS);
#endif
	alloc_head = node;

	return p;
}

static struct alloc_node **find_node(void *ptr)
{
	struct alloc_node **nodep;

	for (nodep = &alloc_head; *nodep; nodep = &(*nodep)->next)
		if ((*nodep)->ptr == ptr)
			return nodep;

	return NULL;
}

void VbExFree(void *ptr)
{
	struct alloc_node **nodep, *next;

	nodep = find_node(ptr);
	if (nodep) {
		next = (*nodep)->next;
		free(*nodep);
		*nodep = next;
	} else {
		fprintf(stderr, "\n>>>>>> Invalid VbExFree() %p\n", ptr);
		fflush(stderr);
#ifdef HAVE_EXECINFO_H
		print_stacktrace();
#endif
		/*
		 * Fall through and do the free() so we get normal error
		 * handling.
		 */
	}

	free(ptr);
}

VbError_t VbExHashFirmwareBody(VbCommonParams *cparams,
                               uint32_t firmware_index)
{
	return VBERROR_SUCCESS;
}

int vboot_api_stub_check_memory(void)
{
	struct alloc_node *node, *next;

	if (!alloc_head)
		return 0;

	/*
	 * Make sure we free all our memory so that valgrind doesn't complain
	 * about leaked memory.
	 */
	fprintf(stderr, "\nWarning, some allocations not freed:");
	for (node = alloc_head; node; node = next) {
		next = node->next;
		fprintf(stderr, "\nptr=%p, size=%zd\n", node->ptr, node->size);
		fflush(stderr);
#ifdef HAVE_EXECINFO_H
		backtrace_symbols_fd(node->bt_buffer + 1, node->bt_levels - 1,
				     2);
#endif
		free(node);
	}

	return -1;
}