• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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