1 /*
2 * Copyright (c) 2015-2019, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "pt_section.h"
30 #include "pt_section_file.h"
31
32 #include "intel-pt.h"
33
34 #include <stdlib.h>
35 #include <stdio.h>
36
37
38 /* This is a variation of ptunit-section.c.
39 *
40 * We provide pt_section_map() et.al. that are normally provided by mmap-based
41 * section implementations. Our implementation falls back to file-based
42 * sections so we're able to test them.
43 *
44 * The actual test is in ptunit-section.c.
45 */
46
47 /* The file status used for detecting changes to a file between unmap and map.
48 *
49 * In our case, the changes always affect the size of the file.
50 */
51 struct pt_file_status {
52 /* The size in bytes. */
53 long size;
54 };
55
pt_section_mk_status(void ** pstatus,uint64_t * psize,const char * filename)56 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
57 {
58 struct pt_file_status *status;
59 FILE *file;
60 long size;
61 int errcode;
62
63 if (!pstatus || !psize)
64 return -pte_internal;
65
66 file = fopen(filename, "rb");
67 if (!file)
68 return -pte_bad_image;
69
70 errcode = fseek(file, 0, SEEK_END);
71 if (errcode) {
72 errcode = -pte_bad_image;
73 goto out_file;
74 }
75
76 size = ftell(file);
77 if (size < 0) {
78 errcode = -pte_bad_image;
79 goto out_file;
80 }
81
82 status = malloc(sizeof(*status));
83 if (!status) {
84 errcode = -pte_nomem;
85 goto out_file;
86 }
87
88 status->size = size;
89
90 *pstatus = status;
91 *psize = (uint64_t) size;
92
93 errcode = 0;
94
95 out_file:
96 fclose(file);
97 return errcode;
98 }
99
pt_section_map_success(struct pt_section * section)100 static int pt_section_map_success(struct pt_section *section)
101 {
102 uint16_t mcount;
103 int errcode, status;
104
105 if (!section)
106 return -pte_internal;
107
108 mcount = section->mcount + 1;
109 if (!mcount) {
110 (void) pt_section_unlock(section);
111 return -pte_overflow;
112 }
113
114 section->mcount = mcount;
115
116 errcode = pt_section_unlock(section);
117 if (errcode < 0)
118 return errcode;
119
120 status = pt_section_on_map(section);
121 if (status < 0) {
122 (void) pt_section_unmap(section);
123 return status;
124 }
125
126 return 0;
127 }
128
pt_section_map(struct pt_section * section)129 int pt_section_map(struct pt_section *section)
130 {
131 struct pt_file_status *status;
132 const char *filename;
133 uint16_t mcount;
134 FILE *file;
135 long size;
136 int errcode;
137
138 if (!section)
139 return -pte_internal;
140
141 errcode = pt_section_lock(section);
142 if (errcode < 0)
143 return errcode;
144
145 mcount = section->mcount;
146 if (mcount)
147 return pt_section_map_success(section);
148
149 if (section->mapping)
150 goto out_unlock;
151
152 filename = section->filename;
153 if (!filename)
154 goto out_unlock;
155
156 status = section->status;
157 if (!status)
158 goto out_unlock;
159
160 errcode = -pte_bad_image;
161 file = fopen(filename, "rb");
162 if (!file)
163 goto out_unlock;
164
165 errcode = fseek(file, 0, SEEK_END);
166 if (errcode) {
167 errcode = -pte_bad_image;
168 goto out_file;
169 }
170
171 errcode = -pte_bad_image;
172 size = ftell(file);
173 if (size < 0)
174 goto out_file;
175
176 if (size != status->size)
177 goto out_file;
178
179 /* We need to keep the file open on success. It will be closed when
180 * the section is unmapped.
181 */
182 errcode = pt_sec_file_map(section, file);
183 if (!errcode)
184 return pt_section_map_success(section);
185
186 out_file:
187 fclose(file);
188
189 out_unlock:
190 (void) pt_section_unlock(section);
191 return errcode;
192 }
193