Segfault when reading ELF Shdr of own executable - c++

I'm trying to read the symbol table of the program's own ELF binary as part of a symbolizer. Part of this involves finding the ELF start, then ELF shdr, etc. I must be doing something wrong, though, because despite e_shoff matching what I see by readelfing the binary manually and the start address looking reasonable, I cannot read the shdr.
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <assert.h>
#include <dlfcn.h>
#include <elf.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static int findELFStartCallback(struct dl_phdr_info *info, size_t size,
void *data) {
static_cast<void>(size);
static int address_found = 0;
if (address_found) {
return 0;
}
address_found = 1;
fprintf(stderr, "relocation: 0x%lx\n", (long)info->dlpi_addr);
for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type == PT_LOAD) {
auto result = reinterpret_cast<void *>(info->dlpi_addr +
info->dlpi_phdr[i].p_vaddr);
fprintf(stderr, "a.out loaded at %p\n", result);
*reinterpret_cast<void **>(data) = result;
break;
}
}
return 0;
}
static void *findELFStart() {
void *result = nullptr;
dl_iterate_phdr(findELFStartCallback, &result);
return result;
}
static void checkELF(ElfW(Ehdr) * ehdr) {
assert(ehdr->e_ident[EI_MAG0] == ELFMAG0 && "bad magic number");
assert(ehdr->e_ident[EI_MAG1] == ELFMAG1 && "bad magic number");
assert(ehdr->e_ident[EI_MAG2] == ELFMAG2 && "bad magic number");
assert(ehdr->e_ident[EI_MAG3] == ELFMAG3 && "bad magic number");
}
int main(int argc, char *argv[]) {
char *exe_ = nullptr;
exe_ = reinterpret_cast<char *>(findELFStart());
assert(exe_ != nullptr && "could not find ELF header");
checkELF(reinterpret_cast<ElfW(Ehdr) *>(exe_));
auto elf = reinterpret_cast<ElfW(Ehdr) *>(exe_);
fprintf(stderr, "e_shoff is %ld (0x%lx)\n", elf->e_shoff, elf->e_shoff);
auto shdr = reinterpret_cast<ElfW(Shdr) *>(exe_ + elf->e_shoff);
fprintf(stderr, "shdr is %ld (%p)\n", (size_t)shdr, (void*)shdr);
const char *str = exe_ + shdr[elf->e_shstrndx].sh_offset; // boom
}
I get a segfault. When I load it in GDB, it looks like shdr is indeed a bad pointer. What am I missing here?
Sample output:
computer% ./p/dladdr
relocation: 0x0
a.out loaded at 0x400000
e_shoff is 24528 (0x5fd0)
shdr is 4218832 (0x405fd0)
zsh: segmentation fault (core dumped) ./p/dladdr
computer%
EDIT: After seeing Reading ELF header of loaded shared object during runtime maybe the sections just aren't loaded into memory...
EDIT: I finished the symbolizer and it's available here

maybe the sections just aren't loaded into memory...
That's exactly right. Here is readelf -WS /bin/date on my system:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1
[ 2] .note.gnu.property NOTE 0000000000000338 000338 000050 00 A 0 0 8
[ 3] .note.gnu.build-id NOTE 0000000000000388 000388 000024 00 A 0 0 4
[ 4] .note.ABI-tag NOTE 00000000000003ac 0003ac 000020 00 A 0 0 4
...
[26] .bss NOBITS 000000000001a0a0 019098 000130 00 WA 0 0 32
[27] .gnu.build.attributes NOTE 000000000001c1d0 019098 000248 00 0 0 4
[28] .gnu_debuglink PROGBITS 0000000000000000 0192e0 000024 00 0 0 4
[29] .gnu_debugdata PROGBITS 0000000000000000 019304 0005a0 00 0 0 1
[30] .shstrtab STRTAB 0000000000000000 0198a4 00013e 00 0 0 1
Note that .shstrtab does not have the A (allocated) flag. The contents of this section is not used at runtime, so there is no reason to load it into memory, and so it isn't.
If you want to access .shstrtab, you need to either read it from the file on disk, or mmap the entire file (the kernel only mmaps the parts covered by PT_LOAD segments, not the entire file).

Related

Initializing plog::RollingFileAppender on Windows XP Triggers Access Violation (Null Pointer)

When using [plog][1] on Windows XP. In this case, the code is:
void LogInit(void)
{
static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("log.log");
Using Visual Studio 2019 but the project uses the platform toolset Visual Studio 2017 - Windows XP (v141_XP)
The output assembly is:
; COMDAT _LogInit
_TEXT SEGMENT
_status$1$ = -516 ; size = 4
_appender$66 = -516 ; size = 4
$T65 = -512 ; size = 256
$T64 = -512 ; size = 256
$T62 = -512 ; size = 256
$T60 = -512 ; size = 256
$T58 = -256 ; size = 256
$T57 = -256 ; size = 256
$T41 = -256 ; size = 256
_LogInit PROC ; COMDAT
; 108 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 e4 f8 and esp, -8 ; fffffff8H
; 109 : static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("log.log");
00006 64 a1 00 00 00
00 mov eax, DWORD PTR fs:__tls_array
0000c 81 ec 04 02 00
00 sub esp, 516 ; 00000204H
00012 8b 0d 00 00 00
00 mov ecx, DWORD PTR __tls_index
00018 53 push ebx
00019 56 push esi
0001a 8b 34 88 mov esi, DWORD PTR [eax+ecx*4]
The null pointer is because EAX (__tls_array) and ECX (__tls_index) area both null. Output from WinDbg:
TGLOBALFLAG: 70
APPLICATION_VERIFIER_FLAGS: 0
CONTEXT: (.ecxr)
eax=00000000 ebx=00000000 ecx=00000000 edx=7c90e4f4 esi=0012f624 edi=00000000
eip=1000366a esp=001afda4 ebp=001affb4 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216
LogTest!LogInit+0x1a:
1000366a 8b3488 mov esi,dword ptr [eax+ecx*4] ds:0023:00000000=????????
Resetting default scope
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 1000366a (LogTest!LogInit+0x0000001a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000000
Attempt to read from address 00000000
PROCESS_NAME: notepad.exe
READ_ADDRESS: 00000000
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 00000000
EXCEPTION_PARAMETER2: 00000000
FAULTING_LOCAL_VARIABLE_NAME: fileAppender
STACK_TEXT:
001affb4 7c80b713 00000000 00000000 0012f624 LogTest!LogInit+0x1a
001affec 00000000 10003650 00000000 00000000 kernel32!BaseThreadStart+0x37
STACK_COMMAND: ~1s; .ecxr ; kb
FAULTING_SOURCE_LINE: d:\test\logtest.cpp
FAULTING_SOURCE_FILE: d:\test\logtest.cpp
FAULTING_SOURCE_LINE_NUMBER: 109
FAULTING_SOURCE_CODE:
105:
106: // This is an example of an exported function.
107: LogInit_API void LogInit(void)
108: {
> 109: static plog::RollingFileAppender<plog::TxtFormatter> fileAppender(";pg.log");
110: plog::init(plog::info, &fileAppender);
111:
112:
113:
114:
SYMBOL_NAME: LogTest!LogInit+1a
MODULE_NAME: LogTest
IMAGE_NAME: LogTest.dll
FAILURE_BUCKET_ID: NULL_POINTER_READ_c0000005_LogTest.dll!LogInit
OS_VERSION: 5.1.2600.5512
BUILDLAB_STR: xpsp
OSPLATFORM_TYPE: x86
OSNAME: Windows XP
FAILURE_ID_HASH: {0218fa42-bce4-328f-5683-a7e3657927fc}
Followup: MachineOwner
---------
Code for affected class is:
namespace plog
{
template<class Formatter, class Converter = NativeEOLConverter<UTF8Converter> >
class PLOG_LINKAGE_HIDDEN RollingFileAppender : public IAppender
{
public:
RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
: m_fileSize()
, m_maxFileSize()
, m_maxFiles(maxFiles)
, m_firstWrite(true)
{
setFileName(fileName);
setMaxFileSize(maxFileSize);
}
#ifdef _WIN32
RollingFileAppender(const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
: m_fileSize()
, m_maxFileSize()
, m_maxFiles(maxFiles)
, m_firstWrite(true)
{
setFileName(fileName);
setMaxFileSize(maxFileSize);
}
#endif
virtual void write(const Record& record)
{
util::MutexLock lock(m_mutex);
if (m_firstWrite)
{
openLogFile();
m_firstWrite = false;
}
else if (m_maxFiles > 0 && m_fileSize > m_maxFileSize && static_cast<size_t>(-1) != m_fileSize)
{
rollLogFiles();
}
size_t bytesWritten = m_file.write(Converter::convert(Formatter::format(record)));
if (static_cast<size_t>(-1) != bytesWritten)
{
m_fileSize += bytesWritten;
}
}
void setFileName(const util::nchar* fileName)
{
util::MutexLock lock(m_mutex);
util::splitFileName(fileName, m_fileNameNoExt, m_fileExt);
m_file.close();
m_firstWrite = true;
}
#ifdef _WIN32
void setFileName(const char* fileName)
{
setFileName(util::toWide(fileName).c_str());
}
#endif
void setMaxFiles(int maxFiles)
{
m_maxFiles = maxFiles;
}
void setMaxFileSize(size_t maxFileSize)
{
m_maxFileSize = (std::max)(maxFileSize, static_cast<size_t>(1000)); // set a lower limit for the maxFileSize
}
void rollLogFiles()
{
m_file.close();
util::nstring lastFileName = buildFileName(m_maxFiles - 1);
util::File::unlink(lastFileName.c_str());
for (int fileNumber = m_maxFiles - 2; fileNumber >= 0; --fileNumber)
{
util::nstring currentFileName = buildFileName(fileNumber);
util::nstring nextFileName = buildFileName(fileNumber + 1);
util::File::rename(currentFileName.c_str(), nextFileName.c_str());
}
openLogFile();
m_firstWrite = false;
}
private:
void openLogFile()
{
util::nstring fileName = buildFileName();
m_fileSize = m_file.open(fileName.c_str());
if (0 == m_fileSize)
{
size_t bytesWritten = m_file.write(Converter::header(Formatter::header()));
if (static_cast<size_t>(-1) != bytesWritten)
{
m_fileSize += bytesWritten;
}
}
}
util::nstring buildFileName(int fileNumber = 0)
{
util::nostringstream ss;
ss << m_fileNameNoExt;
if (fileNumber > 0)
{
ss << '.' << fileNumber;
}
if (!m_fileExt.empty())
{
ss << '.' << m_fileExt;
}
return ss.str();
}
private:
util::Mutex m_mutex;
util::File m_file;
size_t m_fileSize;
size_t m_maxFileSize;
int m_maxFiles;
util::nstring m_fileExt;
util::nstring m_fileNameNoExt;
bool m_firstWrite;
};
}
Is there code or compiler settings that can be modified to fix/remove the references to __tls_array / __tls_index.
This occurs in both debug & release builds.
[1]: https://github.com/SergiusTheBest/plog
Setting compiler option /Zc:threadSafeInit- removes the references to __tls_array and __tls_index and stops the access violation crash.
Microsoft documentation here mentions:
In the C++11 standard, block scope variables with static or thread
storage duration must be zero-initialized before any other
initialization takes place. Initialization occurs when control first
passes through the declaration of the variable. If an exception is
thrown during initialization, the variable is considered
uninitialized, and initialization is re-attempted the next time
control passes through the declaration. If control enters the
declaration concurrently with initialization, the concurrent execution
blocks while initialization is completed. The behavior is undefined if
control re-enters the declaration recursively during initialization.
By default, Visual Studio starting in Visual Studio 2015 implements
this standard behavior. This behavior may be explicitly specified by
setting the /Zc:threadSafeInit compiler option.
The /Zc:threadSafeInit compiler option is on by default. The
/permissive- option does not affect /Zc:threadSafeInit.
Thread-safe initialization of static local variables relies on code
implemented in the Universal C run-time library (UCRT). To avoid
taking a dependency on the UCRT, or to preserve the non-thread-safe
initialization behavior of versions of Visual Studio prior to Visual
Studio 2015, use the /Zc:threadSafeInit- option. If you know that
thread-safety is not required, use this option to generate slightly
smaller, faster code around static local declarations.
Thread-safe static local variables use thread-local storage (TLS)
internally to provide efficient execution when the static has already
been initialized. The implementation of this feature relies on Windows
operating system support functions in Windows Vista and later
operating systems. Windows XP, Windows Server 2003, and older
operating systems do not have this support, so they do not get the
efficiency advantage. These operating systems also have a lower limit
on the number of TLS sections that can be loaded. Exceeding the TLS
section limit can cause a crash. If this is a problem in your code,
especially in code that must run on older operating systems, use
/Zc:threadSafeInit- to disable the thread-safe initialization code.

C++ Read file stream from terminal line by line with only one command

Short: I want to read data from the terminal into a variable and compare it with a string.
Long: I am using a TI AM3358 development board from GOEMBED which runs embedded linux. I use this kit to read data from a canbus. To read the data from the canbus into the terminal I use socketcan.
When I run the following command into the terminal I get a datastream of can messages from the bus.
candump can0
I wrote some code which execute the above command and returns the output.
string GetCmdOutput(const char * cmd)
{
char buffer[128];
string result = "";
string different;
FILE* pipe = popen(cmd,"r");
int counter=0;
if(!pipe) throw runtime_error("popen() failed!");
try {
if(fgets(buffer,128,pipe) !=NULL){
while(counter<1){
result +=buffer;
counter++;
}
}
}catch(...){
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}
In int main() I run the following code which compares the terminal output to a string:
string dump = "candump can0";
const char *senddump;
senddump = dump.c_str();
string newOutput;
int senddata = 0;
int i = 0;
int x = 0;
int amountS = 0;
int y = 0;
string datas;
while(i<1)
{
newOutput = GetCmdOutput(senddump);
cout<<newOutput + "\n";
if(newOutput==" can0 000 [2] 01 12\n")
{
canWrite(busn,baudrate, sendID, dlcn,data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
}
}
The code itself works, but I miss a lot of data from the canbus. I think the reason for this is that I always need to reinitialize the canbus (cmd --> candump can0).
Now my question is: How to change my code that I only need to run the command "candump can0" ones and that the code always compares the next messafes to the string. If this is possible, I think I will gain already a lot of perfomance.
If you have other commands or other options to improve the performancy, pleas do not hesitate to give constructive critisisme. (I'm not a professional! I try to learn)
/ EDIT 1 /
The following datastream is how it is outputted into the terminal
can0 712 [1] 05
can0 192 [6] 1C 0F 19 00 00 00
can0 70B [1] 00
can0 70B [1] 85
can0 703 [1] 00
can0 707 [1] 00
can0 709 [1] 00
Thanks in advance,
Kind regards,
TMO
If there is continual output from candump you could simply pipe the output to your program like this:
$ candump can0 | myprogram
Where myprogram.cpp looks a bit like this:
#include <iostream>
#include <string>
int main()
{
std::string message;
while(std::getline(std::cin, message))
{
// process message here ... eg. ...
if(message == "can0 000 [2] 01 12")
{
// do something specific ...
}
}
}

Given function never gets executed despite being called properly and compiler throwing no error

The following snippet from a long long bunch of C++ sources and header files (which I will be happy to share in case they are needed) shows the user-defined function(or object?) Read being called as part of a Multi-threading operation that is going on.
As part of identifying the problem, I printed flags just before and after the function is called:
std::cout<<"Before calling\n";
and
std::cout<<"After calling\n";
I have also inserted a flag to be printed just after the function is called:
std::cout<<"Entered the function";
The entire application compiles perfectly and also runs smoothly - until this function Read is called, it never gets executed.
In the output, you get the "Before calling" and "After calling" but never the "Entered function".
Operating system used is Ubuntu 16.04, with the g++ compiler.
As of now I am only sharing two snippets related to the question - (since a single file is around 1500 lines of code; I think it should suffice, let me know if otherwise)
Following is the snippet of the thread in which function is called (at line 130) and then is the other file where the function is defined.
Thread where the Function is called:
1 void* StartGenericReadThread(void *ThreadAr)
2 { //std::cout<<"flag GenericThread\n";
3 //printf("\nSuccess");
4 int PORT = ((ThreadArg*)ThreadAr)->PORT;
5 #ifdef WIN32
6 Sleep(4000);
7 #else
8 sleep(4);
9 #endif
10 DSDMux *Mux;
11 DSDConfigReader *cfg;
12 SNMPTrap Trap;
13 DSDMessageSender *DMS;
14 Mux = ((ThreadArg*)ThreadAr)->Mux;
15 cfg = ((ThreadArg*)ThreadAr)->cfg;
16 DMS = ((ThreadArg*)ThreadAr)->MSG;
17
18
19 strcpy(DMS->SNMP_DET.DSD_MAN_IP,cfg->DSDSetting.DSD_MANAGER_IP);
20 strcpy(DMS->SNMP_DET.SNMP_MAN_IP,cfg->DSDSetting.SNMP_TRAP_IP);
21 DMS->SNMP_DET.SNMP_MAN_PORT = cfg->DSDSetting.SNMP_TRAP_PORT;
22 DMS->SNMP_DET.DSD_MAN_PORT = 162;
23
24 if ( checkflag != 1) //EDITED
25 {std::cout<<"\nDSD Manager IP set to
26 "<<cfg->DSDSetting.DSD_MANAGER_IP<<"\n";
27 std::cout<<"SNMP TRAP IP set to
28 "<<cfg->DSDSetting.SNMP_TRAP_IP<<"\n";
29
30 std::cout<<"SNMP TRAP PORT set to "<<cfg->DSDSetting.SNMP_TRAP_PORT<<"\n";
31 checkflag=1;
32 }
33
34 try
35 { //std::cout<<"Entered try\n";
36 bool IPLostErrSet(false),IPGainset(false),FIFOreaderr(false);
37 //DSDCo
38 int nStatus, nLatched,inFifoLoad,MaxBuffRead,lostCount(0);
39 dr = theInput[PORT].SetRxControl(DTAPI_RXCTRL_RCV);
40
41 if ( DTAPI_OK != dr )
42 { //std::cout<<"\nSetRXControl is not OK";
43 // return NULL; EDITED
44 }
45
46 #ifdef WIN32
47 while(!_kbhit())
48 #else
49 while(1)
50 #endif
51 { //EDITED
52 //MaxBuffRead=(inFifoLoad/188)*188;
53 //int DmaSize = ( inFifoLoad > c_ReadBufferSize ) ? c_ReadBufferSize : MaxBuffRead;
54
55 theInput[PORT].GetFlags(nStatus, nLatched);
56 if ( 0 != (DTAPI_RX_FIFO_OVF & nLatched) )
57 {
58 printf("Fifo overflow for input port %d\t\t\t\t\t[Error]\n",PORT+1);
59 DMS->SendLog(FIFO_OVERFLOW,PORT+1);
60 theInput[PORT].ClearFifo();
61 dr = theInput[PORT].SetRxControl(DTAPI_RXCTRL_RCV);
62 if ( DTAPI_OK != dr )
63 {
64 printf("\nError");
65
66 }
67 else
68 DMS->SendLog(FIFO_OVERFLOW_CLR,PORT+1);
69 }
70 theInput[PORT].GetFifoLoad(inFifoLoad);
71 inFifoLoad = MINBUFFSIZE + 512;
72 if (inFifoLoad < MINBUFFSIZE+512)
73 {
74 lostCount++;
75 if(lostCount>1000&&!IPLostErrSet)
76 {
77 lostCount=0;
78 printf("\nInput lost on port %d\t\t\t\t\t\t[ERROR]",PORT+1);
79
80 DMS->SendLog(INPUT_LOST,PORT+1);
81 int pid;
82 /*for(pid=21;pid<8191;pid++)
83 {
84 if(cfg->MuxCfg.PORT[PORT].PID[pid].Mux)
85 DMS->SendLog(PID_REMUX_ERR,pid,PORT+1);
86 }*/
87 Mux->PSI.PATdata.Table[PORT].Section[0].no_of_programs = 0;
88 IPGainset = false;
89 IPLostErrSet = true;
90 }
91
92 #ifdef WIN32
93 Sleep(1);
94 #else
95 usleep(1000);
96 #endif
97 continue;
98 }
99 lostCount = 0;
100 //std::cout<<"\nWill check for IPGAINSET now\n";
101 if(!IPGainset)
102 { //std::cout<<"IPGAINSET IS FALSE\n";
103 cfg->OutputConf.Status=true;
104 printf("\nInput signal detected on port %d\t\t\t\t\t[ OK ]",PORT+1);
105
106 DMS->SendLog(INPUT_GAIN,PORT+1);
107 /*int pid;
108 for(pid=21;pid<8191;pid++)
109 {
110 if(cfg->MuxCfg.PORT[PORT].PID[pid].Mux)
111 {
112 //std::cout<<pid;
113 DMS->SendLog(PID_REMUX,pid,PORT+1);
114 }
115 };*/
116 IPLostErrSet = false;
117 IPGainset = true;
118 }
119 //std::cout<<"IPGAINSET is TRUE\n";
120 //printf("\t%d",inFifoLoad);
121 MaxBuffRead=(inFifoLoad/188)*188;
122 int DmaSize = ( inFifoLoad > c_ReadBufferSize ) ? c_ReadBufferSize : MaxBuffRead;
123
124 // fifold=(int)DmaSize;
125 // char data[65424*10];
126
127
128 std::cout<<"Before Calling\n";
129
130 dr = theInput[PORT].Read(Mux->TSPacket[PORT].data,DmaSize);
131
132 std::cout<<"After Calling\n";
133
134 if ( DTAPI_OK != dr )
135 {// std::cout<<"Error in executing Read function\n";
136 if(!FIFOreaderr)
137 DMS->SendLog(FIFO_READ_ERR,dr,PORT+1);
138
139 }
140 else
141 {
142 Mux->ParseAndMuxTS(PORT,DmaSize,cfg,fs);
143
144 }
145 }
146 return NULL;
147
148 }
149 catch(...)
150 {
151 // printf("Error in StartGenericReadThread\n");
152 DMS->SendLog(INTERNAL_ERR,0,0,0,"StartGenericReadThread");
153 return NULL;
154 }
155 }
Now following is the snippet of the function definition (which is in another file):
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "DTAPI.h"
#include "DtapiUtility.h"
#include "Dta1xxIoCtl.h"
#include "Dta1xxCodes.h"
#include "Dtu2xxIoCtl.h"
#include "Dtu2xxCodes.h"
#include <iostream>
//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ TsInpChannel implementation +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- TsInpChannel::Read -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
//
// Read data bytes from the input channel using DMA transfers.
//
DTAPI_RESULT TsInpChannel::Read(
char* pBuffer, // [in] Pointer to data to be read from Device
int NumBytesToRead) // [in] Number of bytes to be read from Device
{
std::cout<<"Entered the function\n";
// Must be attached.
//if (!m_Attached) EDITED
// return DTAPI_E_NOT_ATTACHED; EDITED
// Validity check on parameters
if (NumBytesToRead<0 || NumBytesToRead%4!=0)
return DTAPI_E_INVALID_SIZE;
if ((atoi)(pBuffer)%4 != 0)
return DTAPI_E_INVALID_BUF;
// Avoid strange effects when NumBytesToRead is zero
if (NumBytesToRead == 0)
return DTAPI_OK;
DTAPI_RESULT dr;
// Processing is dependent on device category
if (m_HwFuncDesc.m_DvcDesc.m_Category == DTAPI_CAT_PCI) {
//-.-.-.-.-.-.-.-.-.- Call the appropiate device IoCtl handler -.-.-.-.-.-.-.-.-.-
DTA1XX_IOCTL_DATA iod;
memset(&iod, 0, sizeof(DTA1XX_IOCTL_DATA));
iod.m_nChIdx = GetIndexOnDevice();
iod.m_Data.m_DataTransDesc.m_pBuffer = pBuffer;
iod.m_Data.m_DataTransDesc.m_nNumBytesToTr = NumBytesToRead;
dr = ioctl(m_fdDevice, DTA1XX_IOCTL_DMA_USERMEM_READ, &iod);
if ( dr != DTAPI_OK )
return dr;
}
else if (Category() == DTAPI_CAT_USB) {
// Read using file IO
int ret = read(m_fdDevice, pBuffer, NumBytesToRead);
if ( ret < 0 )
return DTAPI_E_DEV_DRIVER;
}
else //EDITED
{ std::cout<<"\n Beginning to read file at /home/rtpl/Desktop/ts.mp4";
char * storedfilepath = "/home/rtpl/Desktop/ts.mp4";
int *vedant = open(storedfilepath,O_RDONLY);
int ret = read(vedant, pBuffer, NumBytestoRead);
if ( ret < 0)
std::cout<<"\n File contents cannot be read";
//return DTAPI_E_INTERNAL; // Unknown device category
}
return DTAPI_OK;
}
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- TsInpChannel::ReadDirect -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
//
DTAPI_RESULT TsInpChannel::ReadDirect(
char* pBuffer, // [in] Buffer to store data
int NumBytesToRead, // [in] Number of bytes to be read
int& NumBytesRead) // [out] Number of bytes read
{
return DTAPI_E_NOT_SUPPORTED;
}
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- TsInpChannel::ReadUsingDma -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
//
// Old name of Read. Still here for backward compatibility.
//
DTAPI_RESULT TsInpChannel::ReadUsingDma(
char* pBuffer, // [in] Buffer to store data
int NumBytesToRead) // [in] Number of bytes to be written to PCI card
{
return Read(pBuffer, NumBytesToRead);
}

SDL2/SDL_Image loading objcopy files

As stated on the topic, i'm using objcopy to load SDL_Image images with MinGW over Eclipse Helios for windows.
I'm using the command: objcopy --input-target binary --output-target pei-i386 --binary-architecture i386 Lilothyn.jpg Lilothyn.o
That results in the file:
Lilothyn.o: file format pei-i386
Lilothyn.o
architecture: i386, flags 0x00000030:
HAS_SYMS, HAS_LOCALS
start address 0x00000000
Characteristics 0x305
relocations stripped
line numbers stripped
32 bit words
debugging information removed
Time/Date Thu Jan 01 00:00:00 1970
Magic 0000
MajorLinkerVersion 0
MinorLinkerVersion 0
SizeOfCode 00000000
SizeOfInitializedData 00000000
SizeOfUninitializedData 00000000
AddressOfEntryPoint 00000000
BaseOfCode 00000000
BaseOfData 00000000
ImageBase 00000000
SectionAlignment 00000000
FileAlignment 00000000
MajorOSystemVersion 0
MinorOSystemVersion 0
MajorImageVersion 0
MinorImageVersion 0
MajorSubsystemVersion 0
MinorSubsystemVersion 0
Win32Version 00000000
SizeOfImage 00000000
SizeOfHeaders 00000000
CheckSum 00000000
Subsystem 00000000 (unspecified)
DllCharacteristics 00000000
SizeOfStackReserve 00000000
SizeOfStackCommit 00000000
SizeOfHeapReserve 00000000
SizeOfHeapCommit 00000000
LoaderFlags 00000000
NumberOfRvaAndSizes 00000000
The Data Directory
Entry 0 00000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 00000000 00000000 Import Directory [parts of .idata]
Entry 2 00000000 00000000 Resource Directory [.rsrc]
Entry 3 00000000 00000000 Exception Directory [.pdata]
Entry 4 00000000 00000000 Security Directory
Entry 5 00000000 00000000 Base Relocation Directory [.reloc]
Entry 6 00000000 00000000 Debug Directory
Entry 7 00000000 00000000 Description Directory
Entry 8 00000000 00000000 Special Directory
Entry 9 00000000 00000000 Thread Storage Directory [.tls]
Entry a 00000000 00000000 Load Configuration Directory
Entry b 00000000 00000000 Bound Import Directory
Entry c 00000000 00000000 Import Address Table Directory
Entry d 00000000 00000000 Delay Import Directory
Entry e 00000000 00000000 CLR Runtime Header
Entry f 00000000 00000000 Reserved
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 000024fb 00000000 00000000 000000c0 2**0
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
[ 0](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 _binary_Lilothyn_jpg_start
[ 1](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x000024fb _binary_Lilothyn_jpg_end
[ 2](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x000024fb _binary_Lilothyn_jpg_size
... and the other:
Tommy.o: file format pei-i386
Tommy.o
architecture: i386, flags 0x00000030:
HAS_SYMS, HAS_LOCALS
start address 0x00000000
Characteristics 0x305
relocations stripped
line numbers stripped
32 bit words
debugging information removed
Time/Date Thu Jan 01 00:00:00 1970
Magic 0000
MajorLinkerVersion 0
MinorLinkerVersion 0
SizeOfCode 00000000
SizeOfInitializedData 00000000
SizeOfUninitializedData 00000000
AddressOfEntryPoint 00000000
BaseOfCode 00000000
BaseOfData 00000000
ImageBase 00000000
SectionAlignment 00000000
FileAlignment 00000000
MajorOSystemVersion 0
MinorOSystemVersion 0
MajorImageVersion 0
MinorImageVersion 0
MajorSubsystemVersion 0
MinorSubsystemVersion 0
Win32Version 00000000
SizeOfImage 00000000
SizeOfHeaders 00000000
CheckSum 00000000
Subsystem 00000000 (unspecified)
DllCharacteristics 00000000
SizeOfStackReserve 00000000
SizeOfStackCommit 00000000
SizeOfHeapReserve 00000000
SizeOfHeapCommit 00000000
LoaderFlags 00000000
NumberOfRvaAndSizes 00000000
The Data Directory
Entry 0 00000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 00000000 00000000 Import Directory [parts of .idata]
Entry 2 00000000 00000000 Resource Directory [.rsrc]
Entry 3 00000000 00000000 Exception Directory [.pdata]
Entry 4 00000000 00000000 Security Directory
Entry 5 00000000 00000000 Base Relocation Directory [.reloc]
Entry 6 00000000 00000000 Debug Directory
Entry 7 00000000 00000000 Description Directory
Entry 8 00000000 00000000 Special Directory
Entry 9 00000000 00000000 Thread Storage Directory [.tls]
Entry a 00000000 00000000 Load Configuration Directory
Entry b 00000000 00000000 Bound Import Directory
Entry c 00000000 00000000 Import Address Table Directory
Entry d 00000000 00000000 Delay Import Directory
Entry e 00000000 00000000 CLR Runtime Header
Entry f 00000000 00000000 Reserved
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 000834fe 00000000 00000000 000000c0 2**0
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
[ 0](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 _binary_Tommy_jpg_start
[ 1](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x000834fe _binary_Tommy_jpg_end
[ 2](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x000834fe _binary_Tommy_jpg_size
The problem is that this last file (Tommy.o) loads properly, while the 1st file (Lilothyn.o) doesn't. As you can see the two are seemingly similar.
My code is extensive so i'll post the relevant parts only.
Source.cpp:
int displayFillThread(SDL_Renderer *renderer, SDL_Window *window, bool *_end) throw()
{
std::cout << "Thread initializing..." << std::endl;
SDL_Texture *texture = getTextureFromStream(&binary_Lilothyn_jpg_start, binary_Lilothyn_jpg_size, window, renderer);
if (texture == NULL)
{
std::cout << "Thread: Failed to load image - " << SDL_GetError() << std::endl;
return 1;
}
std::cout << "Thread initialized!" << std::endl;
for(int i= 10; !*_end && i < 400; i+= 100)
for(int j= 10; !*_end && j < 400; j+= 100)
{
SDL_Delay(100);
AddTextureToRederer(renderer, texture, i, j, 100, 100);
SDL_RenderPresent(renderer);
}
return 0;
}
SDL_Texture *getTextureFromStream(char binary[], unsigned int binary_size, SDL_Window *window, SDL_Renderer *renderer) throw()
{
std::cout << "Starting getTextureFromJPEGStream!" << std::endl;
// char* st = loadFileObject(binary_start, binary_end);
SDL_RWops *rw = SDL_RWFromConstMem(binary, binary_size);
std::cout << "rw loaded!" << std::endl;
SDL_Surface *tmpSurf = IMG_Load_RW(rw, 0);
//SDL_Surface *tmpSurf = SDL_CreateRGBSurfaceFrom(Lilothyn_jpg, 123, 102, 24, 96, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
if (tmpSurf != NULL)
{
SDL_Surface *surf = SDL_ConvertSurfaceFormat(tmpSurf, SDL_GetWindowPixelFormat(window), 0);
if (surf != NULL)
{
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surf);
SDL_FreeSurface(surf);
std::cout << "tmpSurf loaded!" << std::endl;
return texture;
}//*/
// SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, tmpSurf);
SDL_FreeSurface(tmpSurf);
std::cout << "surf load failed!" << std::endl;
return NULL;
}
std::cout << "tmpSurf load failed!" << std::endl;
return NULL;
}
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL init Error: " << SDL_GetError() << std::endl;
exit(1);
}
SDL_Window *window = SDL_CreateWindow("SDL_Test", 0, 0, _SCREEN_WIDTH_, _SCREEN_HEIGHT_, SDL_WINDOW_OPENGL | SDL_RENDERER_ACCELERATED); // SDL_WINDOW_FULLSCREEN |
if (window == NULL)
{
std::cout << "Window init Error: " << SDL_GetError() << std::endl;
exit(1);
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer == NULL)
{
SDL_ShowSimpleMessageBox(0, "Renderer init error", SDL_GetError(), window);
}
//SDL_Texture *texture = getTextureFromJPEGStream(binary_Tommy_jpg_start, binary_Tommy_jpg_end, binary_Tommy_jpg_size, window, renderer);
SDL_Texture *texture = getTextureFromStream(&binary_Tommy_jpg_start, binary_Tommy_jpg_size, window, renderer);
//getTextureFromImage("Resources/Tommy.jpg", window, renderer);
if (texture == NULL)
{
SDL_ShowSimpleMessageBox(0, "Background Texture init error", SDL_GetError(), window);
return 1;
}
SDL_RenderCopy(renderer, texture, NULL, NULL);
//AddTextureToRederer(renderer, FTex, 10, 10, 100, 100);
SDL_RenderPresent(renderer);
SDL_Event event;
bool _end = false;
std::cout << "Starting Thread!" << std::endl;
std::thread thread1;
try
{
thread1 = std::thread(displayFillThread, renderer, window, &_end);
std::cout << "Thread loaded!" << std::endl;
}
catch(std::exception& e)
{
std::cout << "Thread load failed: " << e.what() << std::endl;
return 1;
}
std::cout << "main while starting!" << std::endl;
while(!_end)
{
//...
Source.h:
#ifndef SOURCE_H_
#define SOURCE_H_
static int _SCREEN_WIDTH_ = 1024;
static int _SCREEN_HEIGHT_ = 800;
extern char binary_Tommy_jpg_start;
extern unsigned int binary_Tommy_jpg_size;
extern char binary_Lilothyn_jpg_start;
extern unsigned int binary_Lilothyn_jpg_size;
int displayFillThread(SDL_Renderer *renderer, SDL_Window *window, bool *_end) throw();
SDL_Texture *getTextureFromStream(char binary[], unsigned int binary_size, SDL_Window *window, SDL_Renderer *renderer) throw();
//...
And the output:
Starting getTextureFromJPEGStream!
rw loaded!
tmpSurf loaded!
Starting Thread!
Thread loaded!
Thread initializing...
main while starting!
Note that it didn't write the second "getTextureFromJPEGStream!" neither did it appear to have thrown an exception.
It compiles with no problems whatsoever so, is it possible that the Lilothyn.o file is being created corrupted? (I have rebuilt it more than once) And/or maybe the linker isn't linking correctly?
While executing, the program simple stops responding after loading the 1st image, while trying to load the 2nd.
Thank you for the replies.
I've solved this now, the problem was the types used on the .o file.
New code is as follows.
Source.h:
extern uint8_t binary_Lilothyn_jpg_start[];
extern uint8_t binary_Lilothyn_jpg_size[];
Source.cpp
SDL_Texture *getTextureFromStream(uint8_t binary[], uint8_t binary_size[], SDL_Window *window, SDL_Renderer *renderer) throw()
{
size_t converted_size = (size_t)((void *)binary_size);
SDL_Surface *tmpSurf = IMG_Load_RW(SDL_RWFromConstMem(binary, converted_size), 0);
if (tmpSurf != NULL)
{
//...
Thanks to all the viewers, I hope this helps!

Examining mmaped addresses using GDB

I'm using the driver I posted at Direct Memory Access in Linux to mmap some physical ram into a userspace address. However, I can't use GDB to look at any of the address; i.e., x 0x12345678 (where 0x12345678 is the return value of mmap) fails with an error "Cannot access memory at address 0x12345678".
Is there any way to tell GDB that this memory can be viewed? Alternatively, is there something different I can do in the mmap (either the call or the implementation of foo_mmap there) that will allow it to access this memory?
Note that I'm not asking about /dev/mem (as in the first snippet there) but about a mmap to memory acquired via ioremap(), virt_to_phys() and remap_pfn_range()
I believe Linux does not make I/O memory accessible via ptrace(). You could write a function that simply reads the mmap'ed address and have gdb invoke it. Here's a slightly modified version of your foo-user.c program along with the output from a gdb session.
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
char *mptr;
char peek(int offset)
{
return mptr[offset];
}
int main(void)
{
int fd;
fd = open("/dev/foo", O_RDWR | O_SYNC);
if (fd == -1) {
printf("open error...\n");
return 1;
}
mptr = mmap(0, 1 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 4096);
printf("On start, mptr points to 0x%lX.\n", (unsigned long) mptr);
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
mptr[0] = 'a';
mptr[1] = 'b';
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
close(fd);
return 0;
}
$ make foo-user CFLAGS=-g
$ gdb -q foo-user
(gdb) break 27
Breakpoint 1 at 0x804855f: file foo-user.c, line 27.
(gdb) run
Starting program: /home/me/foo/foo-user
On start, mptr points to 0xB7E1E000.
mptr points to 0xB7E1E000. *mptr = 0x61
Breakpoint 1, main () at foo-user.c:27
27 mptr[0] = 'a';
(gdb) n
28 mptr[1] = 'b';
(gdb) print peek(0)
$1 = 97 'a'
(gdb) print peek(1)
$2 = 98 'b'
I have the answer to your conundrum :) I've searched everywhere online without much help and finally debugged it myself.
This post was a good starting point for me. I wanted to achieve something in similar lines, I had implemented a char driver with MMAP to map my custom managed memory to a userspace process. When using GDB, ptrace PEEK calls access_process_vm() to access any memory in your VMA. This causes a EIO error since the generic access cannot get the PA of your memory. It turns out, you have to implement an access function for this memory by implementing .access of your VMA's vm_operations_struct. Below is an example:
//Below code needs to be implemented by your driver:
static struct vm_operations_struct custom_vm_ops = {
.access = custom_vma_access,
};
static inline int custom_vma_access(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
return custom_generic_access_phys(vma, addr, buf, len, write);
}
static int custom_generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
void __iomem *maddr;
//int offset = (addr & (PAGE_SIZE-1)) - vma->vm_start;
int offset = (addr) - vma->vm_start;
maddr = phys_to_virt(__pa(custom_mem_VA));
if (write)
memcpy_toio(maddr + offset, buf, len);
else
memcpy_fromio(buf, maddr + offset, len);
return len;
}
To access the mmapped memory, GDB will call ptrace, which will then call __access_remote_vm() to access the mmapped memory. If the memory is mapped with flags such as VMIO | VM_PFNMAP (for example, remap_pfn_range() sets them), GDB will access the memory though vm's access method defined by users.
Instead of writing our own implementation for access(), kernel already provides a generic version called generic_access_phys(), and this method could be easily linked via vm_operations_struct as the /dev/mem device did:
static const struct vm_operations_struct mmap_mem_ops = {
.access = generic_access_phys };
int mmap_mem()
{
.... ....
vma->vm_ops = &mmap_mem_ops;
.... ....
}
It is my understanding that GDB will be using ptrace to poke around in your process's memory. Perhaps you should write a simple program that just attaches to your process and uses ptrace to read from that memory. This might help narrow down what the underlying problem is. If that has no issues, then you know either I'm wrong :), or something else fishy is happening with GDB.
you go "info files"
(gdb) help info files
Names of targets and files being debugged.
Shows the entire stack of targets currently in use (including the exec-file,
core-file, and process, if any), as well as the symbol file name.
(gdb) info files
Symbols from "/bin/ls".
Unix child process:
Using the running image of child Thread 4160418656 (LWP 10729).
While running this, GDB does not access memory from...
Local exec file:
`/bin/ls', file type elf32-powerpc.
Entry point: 0x10002a10
0x10000134 - 0x10000141 is .interp
0x10000144 - 0x10000164 is .note.ABI-tag
0x10000164 - 0x100008f8 is .gnu.hash
0x100008f8 - 0x10001728 is .dynsym
0x10001728 - 0x100021f3 is .dynstr
0x100021f4 - 0x100023ba is .gnu.version
...
0x0ffa8300 - 0x0ffad8c0 is .text in /lib/libacl.so.1
0x0ffad8c0 - 0x0ffad8f8 is .fini in /lib/libacl.so.1
0x0ffad8f8 - 0x0ffadbac is .rodata in /lib/libacl.so.1
0x0ffadbac - 0x0ffadd58 is .eh_frame_hdr in /lib/libacl.so.1
0x0ffadd58 - 0x0ffae4d8 is .eh_frame in /lib/libacl.so.1
0x0ffbe4d8 - 0x0ffbe4e0 is .ctors in /lib/libacl.so.1
0x0ffbe4e0 - 0x0ffbe4e8 is .dtors in /lib/libacl.so.1
...
(gdb) info sh
From To Syms Read Shared Object Library
0xf7fcf960 0xf7fe81a0 Yes /lib/ld.so.1
0x0ffd0820 0x0ffd5d10 Yes /lib/librt.so.1
0x0ffa8300 0x0ffad8c0 Yes /lib/libacl.so.1
0x0ff6a840 0x0ff7f4f0 Yes /lib/libselinux.so.1
0x0fdfe920 0x0ff1ae70 Yes /lib/libc.so.6
0x0fda23d0 0x0fdb0db0 Yes /lib/libpthread.so.0
Failing this, you can use "mem" to configure memory ranges.
(gdb) mem 1 1414
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 y 0x00000001 0x00000586 rw nocache
(gdb) disable mem 1
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 n 0x00000001 0x00000586 rw nocache
I think that if that memory is not accessible by GDB then it is not mapped into your process address space and so you get "Cannot access memory at addresss 0x12345678". If that application were run normally you would get a segmentation fault. Also, maybe your driver is screwed and you should check you actually can access the memory from within the kernel. Try with example here:
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
int fd = open("/dev/zero", O_RDONLY);
void* addr = mmap(NULL, 1024, PROT_READ, MAP_PRIVATE, fd, 0);
for (int x = 0; x < 10; x++) {
printf("%X\n", ((char*)addr)[x]);
}
close(fd);
return 0;
}
If you open an AF_PACKET socket and mmap it, gdb can't access this memory. So there isn't a problem with your driver. It's either a problem with ptrace or with gdb.