190792Sgshapiro/*
2261363Sgshapiro * Copyright (c) 2013-2019, Intel Corporation
390792Sgshapiro *
490792Sgshapiro * Redistribution and use in source and binary forms, with or without
590792Sgshapiro * modification, are permitted provided that the following conditions are met:
690792Sgshapiro *
790792Sgshapiro *  * Redistributions of source code must retain the above copyright notice,
890792Sgshapiro *    this list of conditions and the following disclaimer.
990792Sgshapiro *  * Redistributions in binary form must reproduce the above copyright notice,
1090792Sgshapiro *    this list of conditions and the following disclaimer in the documentation
11266692Sgshapiro *    and/or other materials provided with the distribution.
1290792Sgshapiro *  * Neither the name of Intel Corporation nor the names of its contributors
1390792Sgshapiro *    may be used to endorse or promote products derived from this software
1490792Sgshapiro *    without specific prior written permission.
1590792Sgshapiro *
1690792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1790792Sgshapiro * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1890792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1990792Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2090792Sgshapiro * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2190792Sgshapiro * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2290792Sgshapiro * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2390792Sgshapiro * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2490792Sgshapiro * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2590792Sgshapiro * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2690792Sgshapiro * POSSIBILITY OF SUCH DAMAGE.
2790792Sgshapiro */
2890792Sgshapiro
2990792Sgshapiro#include "pt_section.h"
3090792Sgshapiro#include "pt_section_file.h"
3190792Sgshapiro
3290792Sgshapiro#include "intel-pt.h"
3390792Sgshapiro
3490792Sgshapiro#include <stdlib.h>
3590792Sgshapiro#include <string.h>
3690792Sgshapiro
3790792Sgshapiro
3890792Sgshapirostatic int fmap_init(struct pt_sec_file_mapping *mapping)
3990792Sgshapiro{
4090792Sgshapiro	if (!mapping)
4190792Sgshapiro		return -pte_internal;
4290792Sgshapiro
4390792Sgshapiro	memset(mapping, 0, sizeof(*mapping));
4490792Sgshapiro
4590792Sgshapiro#if defined(FEATURE_THREADS)
4690792Sgshapiro	{
4790792Sgshapiro		int errcode;
4890792Sgshapiro
4990792Sgshapiro		errcode = mtx_init(&mapping->lock, mtx_plain);
5090792Sgshapiro		if (errcode != thrd_success)
5190792Sgshapiro			return -pte_bad_lock;
5290792Sgshapiro	}
5390792Sgshapiro#endif /* defined(FEATURE_THREADS) */
5490792Sgshapiro
5590792Sgshapiro	return 0;
5690792Sgshapiro}
5790792Sgshapiro
5890792Sgshapirostatic void fmap_fini(struct pt_sec_file_mapping *mapping)
5990792Sgshapiro{
6090792Sgshapiro	if (!mapping)
6190792Sgshapiro		return;
6290792Sgshapiro
6390792Sgshapiro	fclose(mapping->file);
6490792Sgshapiro
6590792Sgshapiro#if defined(FEATURE_THREADS)
6690792Sgshapiro
6790792Sgshapiro	mtx_destroy(&mapping->lock);
6890792Sgshapiro
6990792Sgshapiro#endif /* defined(FEATURE_THREADS) */
7090792Sgshapiro}
7190792Sgshapiro
7290792Sgshapirostatic int fmap_lock(struct pt_sec_file_mapping *mapping)
7390792Sgshapiro{
7490792Sgshapiro	if (!mapping)
7590792Sgshapiro		return -pte_internal;
7690792Sgshapiro
7790792Sgshapiro#if defined(FEATURE_THREADS)
7890792Sgshapiro	{
7990792Sgshapiro		int errcode;
8090792Sgshapiro
8190792Sgshapiro		errcode = mtx_lock(&mapping->lock);
8290792Sgshapiro		if (errcode != thrd_success)
8390792Sgshapiro			return -pte_bad_lock;
8490792Sgshapiro	}
8590792Sgshapiro#endif /* defined(FEATURE_THREADS) */
8690792Sgshapiro
8790792Sgshapiro	return 0;
8890792Sgshapiro}
8990792Sgshapiro
9090792Sgshapirostatic int fmap_unlock(struct pt_sec_file_mapping *mapping)
9190792Sgshapiro{
9290792Sgshapiro	if (!mapping)
9390792Sgshapiro		return -pte_internal;
9490792Sgshapiro
9590792Sgshapiro#if defined(FEATURE_THREADS)
9690792Sgshapiro	{
9790792Sgshapiro		int errcode;
9890792Sgshapiro
9990792Sgshapiro		errcode = mtx_unlock(&mapping->lock);
10090792Sgshapiro		if (errcode != thrd_success)
10190792Sgshapiro			return -pte_bad_lock;
10290792Sgshapiro	}
10390792Sgshapiro#endif /* defined(FEATURE_THREADS) */
10490792Sgshapiro
10590792Sgshapiro	return 0;
10690792Sgshapiro}
10790792Sgshapiro
10890792Sgshapiroint pt_sec_file_map(struct pt_section *section, FILE *file)
10990792Sgshapiro{
110	struct pt_sec_file_mapping *mapping;
111	uint64_t offset, size;
112	long begin, end, fsize;
113	int errcode;
114
115	if (!section)
116		return -pte_internal;
117
118	mapping = section->mapping;
119	if (mapping)
120		return -pte_internal;
121
122	offset = section->offset;
123	size = section->size;
124
125	begin = (long) offset;
126	end = begin + (long) size;
127
128	/* Check for overflows. */
129	if ((uint64_t) begin != offset)
130		return -pte_bad_image;
131
132	if ((uint64_t) end != (offset + size))
133		return -pte_bad_image;
134
135	if (end < begin)
136		return -pte_bad_image;
137
138	/* Validate that the section lies within the file. */
139	errcode = fseek(file, 0, SEEK_END);
140	if (errcode)
141		return -pte_bad_image;
142
143	fsize = ftell(file);
144	if (fsize < 0)
145		return -pte_bad_image;
146
147	if (fsize < end)
148		return -pte_bad_image;
149
150	mapping = malloc(sizeof(*mapping));
151	if (!mapping)
152		return -pte_nomem;
153
154	errcode = fmap_init(mapping);
155	if (errcode < 0)
156		goto out_mem;
157
158	mapping->file = file;
159	mapping->begin = begin;
160	mapping->end = end;
161
162	section->mapping = mapping;
163	section->unmap = pt_sec_file_unmap;
164	section->read = pt_sec_file_read;
165	section->memsize = pt_sec_file_memsize;
166
167	return 0;
168
169out_mem:
170	free(mapping);
171	return errcode;
172}
173
174int pt_sec_file_unmap(struct pt_section *section)
175{
176	struct pt_sec_file_mapping *mapping;
177
178	if (!section)
179		return -pte_internal;
180
181	mapping = section->mapping;
182
183	if (!mapping || !section->unmap || !section->read || !section->memsize)
184		return -pte_internal;
185
186	section->mapping = NULL;
187	section->unmap = NULL;
188	section->read = NULL;
189	section->memsize = NULL;
190
191	fmap_fini(mapping);
192	free(mapping);
193
194	return 0;
195}
196
197int pt_sec_file_read(const struct pt_section *section, uint8_t *buffer,
198		     uint16_t size, uint64_t offset)
199{
200	struct pt_sec_file_mapping *mapping;
201	FILE *file;
202	long begin;
203	size_t read;
204	int errcode;
205
206	if (!buffer || !section)
207		return -pte_internal;
208
209	mapping = section->mapping;
210	if (!mapping)
211		return -pte_internal;
212
213	file = mapping->file;
214
215	/* We already checked in pt_section_read() that the requested memory
216	 * lies within the section's boundaries.
217	 *
218	 * And we checked that the file covers the entire section in
219	 * pt_sec_file_map().  There's no need to check for overflows, again.
220	 */
221	begin = mapping->begin + (long) offset;
222
223	errcode = fmap_lock(mapping);
224	if (errcode < 0)
225		return errcode;
226
227	errcode = fseek(file, begin, SEEK_SET);
228	if (errcode)
229		goto out_unlock;
230
231	read = fread(buffer, 1, size, file);
232
233	errcode = fmap_unlock(mapping);
234	if (errcode < 0)
235		return errcode;
236
237	return (int) read;
238
239out_unlock:
240	(void) fmap_unlock(mapping);
241	return -pte_nomap;
242}
243
244int pt_sec_file_memsize(const struct pt_section *section, uint64_t *size)
245{
246	if (!section || !size)
247		return -pte_internal;
248
249	if (!section->mapping)
250		return -pte_internal;
251
252	*size = 0ull;
253
254	return 0;
255}
256