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 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 34 BDebugEventInputStream::~BDebugEventInputStream() 35 { 36 Unset(); 37 38 if (fOwnsBuffer) 39 free(fBuffer); 40 } 41 42 43 status_t 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 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 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 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 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 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 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 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 286 BDebugEventOutputStream::BDebugEventOutputStream() 287 : 288 fStream(NULL), 289 fFlags(0) 290 { 291 } 292 293 294 BDebugEventOutputStream::~BDebugEventOutputStream() 295 { 296 Unset(); 297 } 298 299 300 status_t 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 338 BDebugEventOutputStream::Unset() 339 { 340 Flush(); 341 fStream = NULL; 342 fFlags = 0; 343 } 344 345 346 status_t 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 365 BDebugEventOutputStream::Flush() 366 { 367 return B_OK; 368 } 369