xref: /haiku/src/kits/debug/DebugEventStream.cpp (revision 25a7b01d15612846f332751841da3579db313082)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <DebugEventStream.h>
7 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <DataIO.h>
12 
13 #include <system_profiler_defs.h>
14 
15 
16 #define INPUT_BUFFER_SIZE	(128 * 1024)
17 
18 
BDebugEventInputStream()19 BDebugEventInputStream::BDebugEventInputStream()
20 	:
21 	fStream(NULL),
22 	fFlags(0),
23 	fEventMask(0),
24 	fBuffer(NULL),
25 	fBufferCapacity(0),
26 	fBufferSize(0),
27 	fBufferPosition(0),
28 	fStreamPosition(0),
29 	fOwnsBuffer(false)
30 {
31 }
32 
33 
~BDebugEventInputStream()34 BDebugEventInputStream::~BDebugEventInputStream()
35 {
36 	Unset();
37 
38 	if (fOwnsBuffer)
39 		free(fBuffer);
40 }
41 
42 
43 status_t
SetTo(BDataIO * stream)44 BDebugEventInputStream::SetTo(BDataIO* stream)
45 {
46 	Unset();
47 
48 	// set the new values
49 	if (stream == NULL)
50 		return B_BAD_VALUE;
51 
52 	fStream = stream;
53 
54 	// allocate a buffer
55 	if (fBuffer == NULL) {
56 		fBuffer = (uint8*)malloc(INPUT_BUFFER_SIZE);
57 		if (fBuffer == NULL) {
58 			Unset();
59 			return B_NO_MEMORY;
60 		}
61 
62 		fOwnsBuffer = true;
63 		fBufferCapacity = INPUT_BUFFER_SIZE;
64 		fBufferSize = 0;
65 	}
66 
67 	return _Init();
68 }
69 
70 
71 status_t
SetTo(const void * data,size_t size,bool takeOverOwnership)72 BDebugEventInputStream::SetTo(const void* data, size_t size,
73 	bool takeOverOwnership)
74 {
75 	Unset();
76 
77 	if (data == NULL || size == 0)
78 		return B_BAD_VALUE;
79 
80 	if (fBuffer != NULL) {
81 		if (fOwnsBuffer)
82 			free(fBuffer);
83 		fBuffer = NULL;
84 		fBufferCapacity = 0;
85 		fBufferSize = 0;
86 	}
87 
88 	fBuffer = (uint8*)data;
89 	fBufferCapacity = fBufferSize = size;
90 	fOwnsBuffer = takeOverOwnership;
91 
92 	return _Init();
93 }
94 
95 
96 void
Unset()97 BDebugEventInputStream::Unset()
98 {
99 	fStream = NULL;
100 	fFlags = 0;
101 	fEventMask = 0;
102 
103 	// If we have a buffer that we own and has the right size, we keep it.
104 	if (fOwnsBuffer) {
105 		if (fBuffer != NULL && fBufferSize != INPUT_BUFFER_SIZE) {
106 			free(fBuffer);
107 			fBuffer = NULL;
108 			fBufferCapacity = 0;
109 			fBufferSize = 0;
110 		}
111 	} else {
112 		fBuffer = NULL;
113 		fBufferCapacity = 0;
114 		fBufferSize = 0;
115 	}
116 }
117 
118 
119 status_t
Seek(off_t streamOffset)120 BDebugEventInputStream::Seek(off_t streamOffset)
121 {
122 	// TODO: Support for streams, at least for BPositionIOs.
123 	if (fStream != NULL)
124 		return B_UNSUPPORTED;
125 
126 	if (streamOffset < 0 || streamOffset > (off_t)fBufferCapacity)
127 		return B_BUFFER_OVERFLOW;
128 
129 	fStreamPosition = 0;
130 	fBufferPosition = streamOffset;
131 	fBufferSize = fBufferCapacity - streamOffset;
132 
133 	return B_OK;
134 }
135 
136 
137 /*!	\brief Returns the next event in the stream.
138 
139 	At the end of the stream \c 0 is returned and \c *_buffer is set to \c NULL.
140 	For events that don't have data associated with them, \c *_buffer will still
141 	be non-NULL, even if dereferencing that address is not allowed.
142 
143 	\param _event Pointer to a pre-allocated location where the event ID shall
144 		be stored.
145 	\param _cpu Pointer to a pre-allocated location where the CPU index shall
146 		be stored.
147 	\param _buffer Pointer to a pre-allocated location where the pointer to the
148 		event data shall be stored.
149 	\param _streamOffset Pointer to a pre-allocated location where the event
150 		header's offset relative to the beginning of the stream shall be stored.
151 		May be \c NULL.
152 	\return A negative error code in case an error occurred while trying to read
153 		the info, the size of the data associated with the event otherwise.
154 */
155 ssize_t
ReadNextEvent(uint32 * _event,uint32 * _cpu,const void ** _buffer,off_t * _streamOffset)156 BDebugEventInputStream::ReadNextEvent(uint32* _event, uint32* _cpu,
157 	const void** _buffer, off_t* _streamOffset)
158 {
159 	// get the next header
160 	status_t error = _GetData(sizeof(system_profiler_event_header));
161 	if (error != B_OK) {
162 		if (error == B_BAD_DATA && fBufferSize == 0) {
163 			*_buffer = NULL;
164 			return 0;
165 		}
166 		return error;
167 	}
168 
169 	system_profiler_event_header header
170 		= *(system_profiler_event_header*)(fBuffer + fBufferPosition);
171 
172 	off_t streamOffset = fStreamPosition + fBufferPosition;
173 
174 	// skip the header in the buffer
175 	fBufferSize -= sizeof(system_profiler_event_header);
176 	fBufferPosition += sizeof(system_profiler_event_header);
177 
178 	// get the data
179 	if (header.size > 0) {
180 		error = _GetData(header.size);
181 		if (error != B_OK)
182 			return error;
183 	}
184 
185 	*_event = header.event;
186 	*_cpu = header.cpu;
187 	*_buffer = fBuffer + fBufferPosition;
188 	if (_streamOffset)
189 		*_streamOffset = streamOffset;
190 
191 	// skip the event in the buffer
192 	fBufferSize -= header.size;
193 	fBufferPosition += header.size;
194 
195 	return header.size;
196 }
197 
198 
199 status_t
_Init()200 BDebugEventInputStream::_Init()
201 {
202 	fStreamPosition = 0;
203 	fBufferPosition = 0;
204 
205 	// get the header
206 	status_t error = _GetData(sizeof(debug_event_stream_header));
207 	if (error != B_OK) {
208 		Unset();
209 		return error;
210 	}
211 	const debug_event_stream_header& header
212 		= *(const debug_event_stream_header*)(fBuffer + fBufferPosition);
213 
214 	fBufferPosition += sizeof(debug_event_stream_header);
215 	fBufferSize -= sizeof(debug_event_stream_header);
216 
217 	// check the header
218 	if (strncmp(header.signature, B_DEBUG_EVENT_STREAM_SIGNATURE,
219 			sizeof(header.signature)) != 0
220 		|| header.version != B_DEBUG_EVENT_STREAM_VERSION
221 		|| (header.flags & B_DEBUG_EVENT_STREAM_FLAG_HOST_ENDIAN) == 0) {
222 		// TODO: Support non-host endianess!
223 		Unset();
224 		return B_BAD_DATA;
225 	}
226 
227 	fFlags = header.flags;
228 	fEventMask = header.event_mask;
229 
230 	return B_OK;
231 }
232 
233 
234 ssize_t
_Read(void * _buffer,size_t size)235 BDebugEventInputStream::_Read(void* _buffer, size_t size)
236 {
237 	uint8* buffer = (uint8*)_buffer;
238 	size_t totalBytesRead = 0;
239 	ssize_t bytesRead = 0;
240 
241 	while (size > 0 && (bytesRead = fStream->Read(buffer, size)) > 0) {
242 		totalBytesRead += bytesRead;
243 		buffer += bytesRead;
244 		size -= bytesRead;
245 	}
246 
247 	if (bytesRead < 0)
248 		return bytesRead;
249 
250 	return totalBytesRead;
251 }
252 
253 
254 status_t
_GetData(size_t size)255 BDebugEventInputStream::_GetData(size_t size)
256 {
257 	if (fBufferSize >= size)
258 		return B_OK;
259 
260 	if (size > fBufferCapacity)
261 		return B_BUFFER_OVERFLOW;
262 
263 	// move remaining data to the start of the buffer
264 	if (fBufferSize > 0 && fBufferPosition > 0)
265 		memmove(fBuffer, fBuffer + fBufferPosition, fBufferSize);
266 	fStreamPosition += fBufferPosition;
267 	fBufferPosition = 0;
268 
269 	// read more data
270 	if (fStream != NULL) {
271 		ssize_t bytesRead = _Read(fBuffer + fBufferSize,
272 			fBufferCapacity - fBufferSize);
273 		if (bytesRead < 0)
274 			return bytesRead;
275 
276 		fBufferSize += bytesRead;
277 	}
278 
279 	return fBufferSize >= size ? B_OK : B_BAD_DATA;
280 }
281 
282 
283 // #pragma mark - BDebugEventOutputStream
284 
285 
BDebugEventOutputStream()286 BDebugEventOutputStream::BDebugEventOutputStream()
287 	:
288 	fStream(NULL),
289 	fFlags(0)
290 {
291 }
292 
293 
~BDebugEventOutputStream()294 BDebugEventOutputStream::~BDebugEventOutputStream()
295 {
296 	Unset();
297 }
298 
299 
300 status_t
SetTo(BDataIO * stream,uint32 flags,uint32 eventMask)301 BDebugEventOutputStream::SetTo(BDataIO* stream, uint32 flags, uint32 eventMask)
302 {
303 	Unset();
304 
305 	// set the new values
306 	if (stream == NULL)
307 		return B_BAD_VALUE;
308 
309 	fStream = stream;
310 	fFlags = /*(flags & B_DEBUG_EVENT_STREAM_FLAG_ZIPPED)
311 		|*/ B_DEBUG_EVENT_STREAM_FLAG_HOST_ENDIAN;
312 		// TODO: Support zipped data!
313 
314 	// init and write the header
315 	debug_event_stream_header header;
316 	memset(header.signature, 0, sizeof(header.signature));
317 	strlcpy(header.signature, B_DEBUG_EVENT_STREAM_SIGNATURE,
318 		sizeof(header.signature));
319 	header.version = B_DEBUG_EVENT_STREAM_VERSION;
320 	header.flags = fFlags;
321 	header.event_mask = eventMask;
322 
323 	ssize_t written = fStream->Write(&header, sizeof(header));
324 	if (written < 0) {
325 		Unset();
326 		return written;
327 	}
328 	if ((size_t)written != sizeof(header)) {
329 		Unset();
330 		return B_FILE_ERROR;
331 	}
332 
333 	return B_OK;
334 }
335 
336 
337 void
Unset()338 BDebugEventOutputStream::Unset()
339 {
340 	Flush();
341 	fStream = NULL;
342 	fFlags = 0;
343 }
344 
345 
346 status_t
Write(const void * buffer,size_t size)347 BDebugEventOutputStream::Write(const void* buffer, size_t size)
348 {
349 	if (size == 0)
350 		return B_OK;
351 	if (buffer == NULL)
352 		return B_BAD_VALUE;
353 
354 	ssize_t written = fStream->Write(buffer, size);
355 	if (written < 0)
356 		return written;
357 	if ((size_t)written != size)
358 		return B_FILE_ERROR;
359 
360 	return B_OK;
361 }
362 
363 
364 status_t
Flush()365 BDebugEventOutputStream::Flush()
366 {
367 	return B_OK;
368 }
369