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