int ReadVideoCoreStringBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, const char *symbol, char *buf, size_t bufSize ) { VC_MEM_ADDR_T vcMemAddr; size_t vcMemSize; if ( !LookupVideoCoreSymbol( vcHandle, symbol, &vcMemAddr, &vcMemSize )) { ERR( "Symbol not found: '%s'", symbol ); return 0; } if ( vcMemSize > bufSize ) { vcMemSize = bufSize; } if ( !ReadVideoCoreMemory( vcHandle, buf, vcMemAddr, vcMemSize )) { ERR( "Unable to read %zu bytes @ 0x%08x", vcMemSize, vcMemAddr ); return 0; } // Make sure that the result is null-terminated buf[vcMemSize-1] = '\0'; return 1; }
static int do_components(int argc, const char **argv) { VC_MEM_ACCESS_HANDLE_T vc; VC_MEM_ADDR_T addr, statsaddr; size_t size; MMAL_VC_STATS_T stats; int rc; if (argc > 2 && (strcasecmp(argv[2], "update") == 0)) { MMAL_STATUS_T status; do_connect(); status = mmal_vc_get_stats(&stats, 0); if (status != MMAL_SUCCESS) { fprintf(stderr, "Failed to update MMAL stats. error %s", mmal_status_to_string(status)); return -1; } } else { if ((rc = OpenVideoCoreMemory(&vc)) < 0) { fprintf(stderr,"Unable to open videocore memory: %d\n", rc); return -1; } if (!LookupVideoCoreSymbol(vc, "mmal_vc_stats", &addr, &size)) { fprintf(stderr,"Could not get MMAL stats address\n"); goto fail; } if (!ReadVideoCoreUInt32(vc, &statsaddr, addr)) { fprintf(stderr,"Could not read MMAL stats pointer at address 0x%x\n", addr); goto fail; } if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats))) { fprintf(stderr,"Could not read MMAL stats at address 0x%x\n", addr); goto fail; } CloseVideoCoreMemory(vc); } rc = print_component_stats(&stats); return rc; fail: CloseVideoCoreMemory(vc); return -1; }
int ReadVideoCoreMemoryBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, const char *symbol, void *buf, size_t bufSize ) { VC_MEM_ADDR_T vcMemAddr; size_t vcMemSize; if ( !LookupVideoCoreSymbol( vcHandle, symbol, &vcMemAddr, &vcMemSize )) { ERR( "Symbol not found: '%s'", symbol ); return 0; } if ( vcMemSize > bufSize ) { vcMemSize = bufSize; } if ( !ReadVideoCoreMemory( vcHandle, buf, vcMemAddr, vcMemSize )) { ERR( "Unable to read %zu bytes @ 0x%08x", vcMemSize, vcMemAddr ); return 0; } return 1; }
static int do_imageconv_stats(int argc, const char **argv) { VC_MEM_ACCESS_HANDLE_T vc; VC_MEM_ADDR_T addr, statsaddr; size_t size; IMAGECONV_STATS_T stats; long convert_time; double frame_rate; int rc; int reset_stats = 0; if (argc > 2) reset_stats = strcasecmp(argv[2], "reset") == 0; if ((rc = OpenVideoCoreMemory(&vc)) < 0) { fprintf(stderr,"Unable to open videocore memory: %d\n", rc); return -1; } if (!LookupVideoCoreSymbol(vc, "imageconv_stats", &addr, &size)) { fprintf(stderr,"Could not get imageconv stats address\n"); goto fail; } if (!ReadVideoCoreUInt32(vc, &statsaddr, addr)) { fprintf(stderr, "Could not read imageconv stats address\n"); goto fail; } if (reset_stats) { memset(&stats, 0, sizeof(stats)); stats.magic = IMAGECONV_STATS_MAGIC; if (!WriteVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats))) { fprintf(stderr, "Could not write stats at 0x%x\n", statsaddr); goto fail; } } if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats))) { fprintf(stderr, "Could not read stats at 0x%x\n", statsaddr); goto fail; } if (stats.magic != IMAGECONV_STATS_MAGIC) { fprintf(stderr, "Bad magic 0x%x\n", stats.magic); goto fail; } if (stats.conversions) convert_time = stats.time_spent / stats.conversions; else convert_time = 0; if (stats.conversions) frame_rate = 1000000.0 * stats.conversions / (stats.last_image_ts - stats.first_image_ts); else frame_rate = 0; printf("%-25s:\t%d\n", "conversions", stats.conversions); printf("%-25s:\t%d\n", "size requests", stats.size_requests); printf("%-25s:\t%d\n", "max vrf delay", stats.max_vrf_delay); printf("%-25s:\t%d\n", "vrf wait time", stats.vrf_wait_time); printf("%-25s:\t%d\n", "duplicate conversions", stats.duplicate_conversions); printf("%-25s:\t%d\n", "failures", stats.failures); printf("%-25s:\t%ld\n", "convert time / image (us)", convert_time); printf("%-25s:\t%.1f\n", "client frame_rate", frame_rate); printf("%-25s:\t%d us\n", "max delay to consume", stats.max_delay); CloseVideoCoreMemory(vc); return 0; fail: CloseVideoCoreMemory(vc); return -1; }
static int do_eventlog(int argc, const char **argv) { VC_MEM_ACCESS_HANDLE_T vc; VC_MEM_ADDR_T addr; /** The address of the pointer to the log */ size_t size; VC_MEM_ADDR_T logaddr; /** The address of the log itself */ MMAL_DBG_LOG_T log; (void)argc; (void)argv; int rc; if ((rc = OpenVideoCoreMemory(&vc)) < 0) { fprintf(stderr,"Unable to open videocore memory: %d\n", rc); return -1; } if (!LookupVideoCoreSymbol(vc, "mmal_dbg_log", &addr, &size)) { fprintf(stderr,"Could not get MMAL log address\n"); goto fail; } if (!ReadVideoCoreUInt32(vc, &logaddr, addr)) { fprintf(stderr,"Could not read MMAL log pointer at address 0x%x\n", addr); goto fail; } if (!ReadVideoCoreMemory(vc, &log, logaddr, sizeof(log))) { fprintf(stderr,"Could not read MMAL log at address 0x%x\n", logaddr); goto fail; } if (log.magic != MMAL_MAGIC) { fprintf(stderr,"Bad magic 0x%08x in log at 0x%x\n", log.magic, logaddr); goto fail; } if (log.size != sizeof(log)) { fprintf(stderr,"MMAL Log size mismatch (got %d, expected %d)\n", log.size, sizeof(log)); goto fail; } if (log.elemsize != sizeof(MMAL_DBG_ENTRY_T)) { fprintf(stderr,"MMAL log element size mismatch (got %d, expected %d)\n", log.elemsize, sizeof(MMAL_DBG_ENTRY_T)); goto fail; } printf("reading MMAL log at 0x%x version %d magic %x\n", logaddr, log.version, log.magic); printf("%d events, %d entries each size %d\n", log.index, log.num_entries, log.elemsize); print_mmal_event_log(vc, &log); CloseVideoCoreMemory(vc); return 0; fail: CloseVideoCoreMemory(vc); return -1; }
int OpenVideoCoreMemoryFileWithOffset( const char *filename, VC_MEM_ACCESS_HANDLE_T *vcHandlePtr, size_t loadOffset ) { int rc = 0; VC_MEM_ACCESS_HANDLE_T newHandle; VC_DEBUG_SYMBOL_T debug_sym; VC_MEM_ADDR_T symAddr; size_t symTableSize; unsigned symIdx; struct { VC_DEBUG_HEADER_T header; VC_DEBUG_PARAMS_T params; } vc_dbg; vcos_log_register( "debug_sym", &debug_sym_log_category ); if (( newHandle = calloc( 1, sizeof( *newHandle ))) == NULL ) { return -ENOMEM; } if ( filename == NULL ) { newHandle->use_vc_mem = 1; filename = "/dev/vc-mem"; } else { newHandle->use_vc_mem = 0; } if (( newHandle->memFd = open( filename, ( newHandle->use_vc_mem ? O_RDWR : O_RDONLY ) | O_SYNC )) < 0 ) { ERR( "Unable to open '%s': %s(%d)\n", filename, strerror( errno ), errno ); free(newHandle); return -errno; } DBG( "Opened %s memFd = %d", filename, newHandle->memFd ); if ( newHandle->use_vc_mem ) { newHandle->memFdBase = 0; #if defined(WIN32) || defined(__CYGWIN__) #define VC_MEM_SIZE (128 * 1024 * 1024) newHandle->vcMemSize = VC_MEM_SIZE; newHandle->vcMemBase = 0; newHandle->vcMemLoad = 0; newHandle->vcMemPhys = 0; #else if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_SIZE, &newHandle->vcMemSize ) != 0 ) { ERR( "Failed to get memory size via ioctl: %s(%d)\n", strerror( errno ), errno ); free(newHandle); return -errno; } if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_BASE, &newHandle->vcMemBase ) != 0 ) { ERR( "Failed to get memory base via ioctl: %s(%d)\n", strerror( errno ), errno ); free(newHandle); return -errno; } if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_LOAD, &newHandle->vcMemLoad ) != 0 ) { ERR( "Failed to get memory load via ioctl: %s(%d)\n", strerror( errno ), errno ); /* Backward compatibility. */ newHandle->vcMemLoad = newHandle->vcMemBase; } if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_PHYS_ADDR, &newHandle->vcMemPhys ) != 0 ) { ERR( "Failed to get memory physical address via ioctl: %s(%d)\n", strerror( errno ), errno ); free(newHandle); return -errno; } #endif } else { off_t len = lseek( newHandle->memFd, 0, SEEK_END ); if ( len < 0 ) { ERR( "Failed to seek to end of file: %s(%d)\n", strerror( errno ), errno ); free(newHandle); return -errno; } newHandle->vcMemPhys = 0; newHandle->vcMemSize = len; newHandle->vcMemBase = 0; newHandle->vcMemLoad = loadOffset; newHandle->memFdBase = 0; } DBG( "vcMemSize = %08x", newHandle->vcMemSize ); DBG( "vcMemBase = %08x", newHandle->vcMemBase ); DBG( "vcMemLoad = %08x", newHandle->vcMemLoad ); DBG( "vcMemPhys = %08x", newHandle->vcMemPhys ); newHandle->vcMemEnd = newHandle->vcMemBase + newHandle->vcMemSize - 1; // See if we can detect the symbol table if ( !ReadVideoCoreMemory( newHandle, &newHandle->vcSymbolTableOffset, newHandle->vcMemLoad + VC_SYMBOL_BASE_OFFSET, sizeof( newHandle->vcSymbolTableOffset ))) { ERR( "ReadVideoCoreMemory @VC_SYMBOL_BASE_OFFSET (0x%08x) failed\n", VC_SYMBOL_BASE_OFFSET ); rc = -EIO; goto err_exit; } // When reading from a file, the VC binary is read into a buffer and the effective base is 0. // But that may not be the actual base address the binary is intended to be loaded to. The // following reads the debug header to find out what the actual base address is. if( !newHandle->use_vc_mem ) { // Read the complete debug header if ( !ReadVideoCoreMemory( newHandle, &vc_dbg, newHandle->vcMemLoad + VC_SYMBOL_BASE_OFFSET, sizeof( vc_dbg ))) { ERR( "ReadVideoCoreMemory @VC_SYMBOL_BASE_OFFSET (0x%08x) failed\n", VC_SYMBOL_BASE_OFFSET ); rc = -EIO; goto err_exit; } // The vc_dbg header gives the "base" address of the VC binary, // which debug_sym calls the "load" address, so we need to adjust // it by loadOffset to find the base of the whole memory dump file newHandle->memFdBase = vc_dbg.params.vcMemBase - loadOffset; newHandle->vcMemBase = vc_dbg.params.vcMemBase - loadOffset; newHandle->vcMemLoad = vc_dbg.params.vcMemBase; newHandle->vcMemEnd = newHandle->memFdBase + newHandle->vcMemSize - 1; DBG( "Updated from debug header:" ); DBG( "vcMemSize = %08x", newHandle->vcMemSize ); DBG( "vcMemBase = %08x", newHandle->vcMemBase ); DBG( "vcMemLoad = %08x", newHandle->vcMemLoad ); DBG( "vcMemPhys = %08x", newHandle->vcMemPhys ); } DBG( "vcSymbolTableOffset = 0x%08x", newHandle->vcSymbolTableOffset ); // Make sure that the pointer points into the first few megabytes of // the memory space. if ( (newHandle->vcSymbolTableOffset - newHandle->vcMemLoad) > ( MAX_VC_SIZE * 1024 * 1024 )) { ERR( "newHandle->vcSymbolTableOffset (0x%x - 0x%x) > %dMB\n", newHandle->vcSymbolTableOffset, newHandle->vcMemLoad, MAX_VC_SIZE ); rc = -EIO; goto err_exit; } // Make a pass to count how many symbols there are. symAddr = newHandle->vcSymbolTableOffset; newHandle->numSymbols = 0; do { if ( !ReadVideoCoreMemory( newHandle, &debug_sym, symAddr, sizeof( debug_sym ))) { ERR( "ReadVideoCoreMemory @ symAddr(0x%08x) failed\n", symAddr ); rc = -EIO; goto err_exit; } newHandle->numSymbols++; DBG( "Symbol %d: label: 0x%p addr: 0x%08x size: %zu", newHandle->numSymbols, debug_sym.label, debug_sym.addr, debug_sym.size ); if ( newHandle->numSymbols > 1024 ) { // Something isn't sane. ERR( "numSymbols (%d) > 1024 - looks wrong\n", newHandle->numSymbols ); rc = -EIO; goto err_exit; } symAddr += sizeof( debug_sym ); } while ( debug_sym.label != 0 ); newHandle->numSymbols--; DBG( "Detected %d symbols", newHandle->numSymbols ); // Allocate some memory to hold the symbols, and read them in. symTableSize = newHandle->numSymbols * sizeof( debug_sym ); if (( newHandle->symbol = malloc( symTableSize )) == NULL ) { rc = -ENOMEM; goto err_exit; } if ( !ReadVideoCoreMemory( newHandle, newHandle->symbol, newHandle->vcSymbolTableOffset, symTableSize )) { ERR( "ReadVideoCoreMemory @ newHandle->vcSymbolTableOffset(0x%08x) failed\n", newHandle->vcSymbolTableOffset ); rc = -EIO; goto err_exit; } // The names of the symbols are pointers in videocore space. We want // to have them available locally, so we make copies and fixup // the pointer. for ( symIdx = 0; symIdx < newHandle->numSymbols; symIdx++ ) { VC_DEBUG_SYMBOL_T *sym; char symName[ 256 ]; sym = &newHandle->symbol[ symIdx ]; DBG( "Symbol %d: label: 0x%p addr: 0x%08x size: %zu", symIdx, sym->label, sym->addr, sym->size ); if ( !ReadVideoCoreMemory( newHandle, symName, TO_VC_MEM_ADDR(sym->label), sizeof( symName ))) { ERR( "ReadVideoCoreMemory @ sym->label(0x%08x) failed\n", TO_VC_MEM_ADDR(sym->label) ); rc = -EIO; goto err_exit; } symName[ sizeof( symName ) - 1 ] = '\0'; sym->label = vcos_strdup( symName ); DBG( "Symbol %d (@0x%p): label: '%s' addr: 0x%08x size: %zu", symIdx, sym, sym->label, sym->addr, sym->size ); } *vcHandlePtr = newHandle; return 0; err_exit: close( newHandle->memFd ); free( newHandle ); return rc; }