1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Copyright 2022 Collabora Ltd.
4 */
5
6 #include "retrace.h"
7
8 struct retrace_context ctx_retrace = {};
9
buffer_in_retrace_context(int fd,__u32 offset)10 bool buffer_in_retrace_context(int fd, __u32 offset)
11 {
12 bool buffer_in_retrace_context = false;
13 for (auto &b : ctx_retrace.buffers) {
14 if ((b.fd == fd) && (b.offset == offset)) {
15 buffer_in_retrace_context = true;
16 break;
17 }
18 }
19 return buffer_in_retrace_context;
20 }
21
get_buffer_fd_retrace(__u32 type,__u32 index)22 int get_buffer_fd_retrace(__u32 type, __u32 index)
23 {
24 int fd = -1;
25 for (auto &b : ctx_retrace.buffers) {
26 if ((b.type == type) && (b.index == index)) {
27 fd = b.fd;
28 break;
29 }
30 }
31 return fd;
32 }
33
add_buffer_retrace(int fd,__u32 type,__u32 index,__u32 offset)34 void add_buffer_retrace(int fd, __u32 type, __u32 index, __u32 offset)
35 {
36 struct buffer_retrace buf = {};
37 buf.fd = fd;
38 buf.type = type;
39 buf.index = index;
40 buf.offset = offset;
41 ctx_retrace.buffers.push_front(buf);
42 }
43
remove_buffer_retrace(__u32 type,__u32 index)44 void remove_buffer_retrace(__u32 type, __u32 index)
45 {
46 for (auto it = ctx_retrace.buffers.begin(); it != ctx_retrace.buffers.end(); ++it) {
47 if ((it->type == type) && (it->index == index)) {
48 ctx_retrace.buffers.erase(it);
49 break;
50 }
51 }
52 }
53
set_buffer_address_retrace(int fd,__u32 offset,long address_trace,long address_retrace)54 void set_buffer_address_retrace(int fd, __u32 offset, long address_trace, long address_retrace)
55 {
56 for (auto &b : ctx_retrace.buffers) {
57 if ((b.fd == fd) && (b.offset == offset)) {
58 b.address_trace = address_trace;
59 b.address_retrace = address_retrace;
60 break;
61 }
62 }
63 }
64
get_retrace_address_from_trace_address(long address_trace)65 long get_retrace_address_from_trace_address(long address_trace)
66 {
67 long address_retrace = 0;
68 for (auto &b : ctx_retrace.buffers) {
69 if (b.address_trace == address_trace) {
70 address_retrace = b.address_retrace;
71 break;
72 }
73 }
74 return address_retrace;
75 }
76
print_buffers_retrace(void)77 void print_buffers_retrace(void)
78 {
79 for (auto &b : ctx_retrace.buffers) {
80 fprintf(stderr, "fd: %d, offset: %d, address_trace:%ld, address_retrace:%ld\n",
81 b.fd, b.offset, b.address_trace, b.address_retrace);
82 }
83 }
84
add_fd(int fd_trace,int fd_retrace)85 void add_fd(int fd_trace, int fd_retrace)
86 {
87 std::pair<int, int> new_pair;
88 new_pair = std::make_pair(fd_trace, fd_retrace);
89 ctx_retrace.retrace_fds.insert(new_pair);
90 }
91
get_fd_retrace_from_fd_trace(int fd_trace)92 int get_fd_retrace_from_fd_trace(int fd_trace)
93 {
94 int fd_retrace = -1;
95 auto it = ctx_retrace.retrace_fds.find(fd_trace);
96 if (it != ctx_retrace.retrace_fds.end())
97 fd_retrace = it->second;
98 return fd_retrace;
99 }
100
print_fds(void)101 void print_fds(void)
102 {
103 if (ctx_retrace.retrace_fds.empty())
104 fprintf(stderr, "all devices closed\n");
105 for (auto retrace_fd : ctx_retrace.retrace_fds)
106 fprintf(stderr, "fd_trace: %d, fd_retrace: %d\n", retrace_fd.first, retrace_fd.second);
107 }
108
get_path_retrace_from_path_trace(std::string path_trace,json_object * open_obj)109 std::string get_path_retrace_from_path_trace(std::string path_trace, json_object *open_obj)
110 {
111 bool is_media = path_trace.find("media") != std::string::npos;
112 bool is_video = path_trace.find("video") != std::string::npos;
113
114 std::string path_media;
115 std::string path_video;
116
117 /* If user set the media or video path just return that path. */
118 if (is_media && (getenv("V4L2_TRACER_OPTION_SET_MEDIA_DEVICE") != nullptr)) {
119 path_media = getenv("V4L2_TRACER_OPTION_SET_MEDIA_DEVICE");
120 debug_line_info("\n\tUse path set by user: %s", path_media.c_str());
121 return path_media;
122 }
123 if (is_video && (getenv("V4L2_TRACER_OPTION_SET_VIDEO_DEVICE") != nullptr)) {
124 path_video = getenv("V4L2_TRACER_OPTION_SET_VIDEO_DEVICE");
125 debug_line_info("\n\tUse path set by user: %s", path_video.c_str());
126 return path_video;
127 }
128
129 std::string driver;
130 json_object *driver_obj;
131 if (json_object_object_get_ex(open_obj, "driver", &driver_obj))
132 if (json_object_get_string(driver_obj) != nullptr)
133 driver = json_object_get_string(driver_obj);
134 if (driver.empty())
135 return "";
136
137 path_media = get_path_media(driver);
138 if (path_media.empty()) {
139 line_info("\n\tWarning: driver: \'%s\' not found.", driver.c_str());
140 return "";
141 }
142
143 if (is_media)
144 return path_media;
145
146 if (is_video) {
147 std::list<std::string> linked_entities;
148 json_object *le_obj;
149 if (json_object_object_get_ex(open_obj, "linked_entities", &le_obj)) {
150 for (size_t i = 0; i < array_list_length(json_object_get_array(le_obj)); i++) {
151 std::string ename;
152 if (json_object_get_string(json_object_array_get_idx(le_obj, i)) != nullptr)
153 ename = json_object_get_string(json_object_array_get_idx(le_obj, i));
154 linked_entities.push_back(ename);
155 }
156 }
157 if (linked_entities.size() == 0)
158 return "";
159
160 setenv("V4L2_TRACER_PAUSE_TRACE", "true", 0);
161 int media_fd = open(path_media.c_str(), O_RDONLY);
162 unsetenv("V4L2_TRACER_PAUSE_TRACE");
163
164 std::string path_video = get_path_video(media_fd, linked_entities);
165 setenv("V4L2_TRACER_PAUSE_TRACE", "true", 0);
166 close(media_fd);
167 unsetenv("V4L2_TRACER_PAUSE_TRACE");
168 return path_video;
169 }
170
171 return "";
172 }
173
write_to_output_buffer(unsigned char * buffer_pointer,int bytesused,json_object * mem_obj)174 void write_to_output_buffer(unsigned char *buffer_pointer, int bytesused, json_object *mem_obj)
175 {
176 int byteswritten = 0;
177 const int hex_base = 16;
178 json_object *line_obj;
179 size_t number_of_lines;
180 std::string compressed_video_data;
181
182 json_object *mem_array_obj;
183 json_object_object_get_ex(mem_obj, "mem_array", &mem_array_obj);
184 number_of_lines = json_object_array_length(mem_array_obj);
185
186 for (long unsigned int i = 0; i < number_of_lines; i++) {
187 line_obj = json_object_array_get_idx(mem_array_obj, i);
188 if (json_object_get_string(line_obj) != nullptr)
189 compressed_video_data = json_object_get_string(line_obj);
190
191 for (long unsigned i = 0; i < compressed_video_data.length(); i++) {
192 if (std::isspace(compressed_video_data[i]) != 0)
193 continue;
194 try {
195 /* Two values from the string e.g. "D9" are needed to write one byte. */
196 *buffer_pointer = (char) std::stoi(compressed_video_data.substr(i,2), nullptr, hex_base);
197 buffer_pointer++;
198 i++;
199 byteswritten++;
200 } catch (std::invalid_argument& ia) {
201 line_info("\n\t\'%s\' is an invalid argument.\n",
202 compressed_video_data.substr(i,2).c_str());
203 } catch (std::out_of_range& oor) {
204 line_info("\n\t\'%s\' is out of range.\n",
205 compressed_video_data.substr(i,2).c_str());
206 }
207 }
208 }
209 debug_line_info("\n\tbytesused: %d, byteswritten: %d", bytesused, byteswritten);
210 }
211
compare_program_versions(json_object * v4l2_tracer_info_obj)212 void compare_program_versions(json_object *v4l2_tracer_info_obj)
213 {
214 json_object *package_version_obj;
215 json_object_object_get_ex(v4l2_tracer_info_obj, "package_version", &package_version_obj);
216 std::string package_version_trace;
217 if (json_object_get_string(package_version_obj) != nullptr)
218 package_version_trace = json_object_get_string(package_version_obj);
219 std::string package_version_retrace = PACKAGE_VERSION;
220 if (package_version_trace != package_version_retrace) {
221 line_info("\n\tWarning: trace package version \'%s\' does not match current: \'%s\'",
222 package_version_trace.c_str(), package_version_retrace.c_str());
223 print_v4l2_tracer_info();
224 return;
225 }
226
227 json_object *git_sha_obj;
228 json_object_object_get_ex(v4l2_tracer_info_obj, "git_sha", &git_sha_obj);
229 std::string git_sha_trace;
230 if (json_object_get_string(git_sha_obj) != nullptr)
231 git_sha_trace = json_object_get_string(git_sha_obj);
232 std::string git_sha_retrace = (STRING(GIT_SHA));
233 if (git_sha_trace != git_sha_retrace) {
234 line_info("\n\tWarning: sha in trace file \'%s\' does not match current sha: \'%s\'",
235 git_sha_trace.c_str(), git_sha_retrace.c_str());
236 print_v4l2_tracer_info();
237 return;
238 }
239 }
240
print_context(void)241 void print_context(void)
242 {
243 if (!is_debug())
244 return;
245 print_fds();
246 print_buffers_retrace();
247 fprintf(stderr, "\n");
248 }
249