Any porting available of backtrace for uclibc? - linux

We are running the uclibc linux on ARM 9. The problem is uclibc doesn't support backtrace. When a core dump happens, I cannot grab the call stack.
Does anyone have a good solution for that?
For example, an existing porting of backtrace for uclibc, or any good method to grab the call stack when a core dump happens (uclibc+ARM+Linux)?

Update:
It seems that a patch was created to support backtrace() on uclibc for x86 and ARM (XScale) and it makes use of the __libc_stack_end symbol.
Original Answer:
I worked on a project where the version of glibc we were using did not provide a functional backtrace() for our ARM processor, so we developed our own outside of glibc using the __libc_stack_end symbol. Below is the resulting code. Perhaps you can use it to write a uclibc backtrace() function.
extern void * __libc_stack_end;
struct backtrace_frame_t
{
void * fp;
void * sp;
void * lr;
void * pc;
};
int backtrace(void ** array, int size)
{
void * top_frame_p;
void * current_frame_p;
struct backtrace_frame_t * frame_p;
int frame_count;
top_frame_p = __builtin_frame_address(0);
current_frame_p = top_frame_p;
frame_p = (struct backtrace_frame_t*)((void**)(current_frame_p)-3);
frame_count = 0;
if (__builtin_return_address(0) != frame_p->lr)
{
fprintf(stderr, "backtrace error: __builtin_return_address(0) != frame_p->lr\n");
return frame_count;
}
if (current_frame_p != NULL
&& current_frame_p > (void*)&frame_count
&& current_frame_p < __libc_stack_end)
{
while (frame_count < size
&& current_frame_p != NULL
&& current_frame_p > (void*)&frame_count
&& current_frame_p < __libc_stack_end)
{
frame_p = (struct backtrace_frame_t*)((void**)(current_frame_p)-3);
array[frame_count] = frame_p->lr;
frame_count++;
current_frame_p = frame_p->fp;
}
}
return frame_count;
}
Note: The __libc_stack_end symbol is no longer exported in more recent versions of glibc and I'm not sure of the existence of it or a similar symbol in uclibc.

Have a look at the same question asked here:
http://lists.uclibc.org/pipermail/uclibc/2010-June/044115.html
which mentions a patch from here:
http://git.stlinux.com/?p=stm/uclibc.git;a=commit;h=d6a3d9ece5922a337800a8e2ed4db7e226f9ccb3

Related

Calling aarch64 shared library from amd64 executable, maybe using binary translation/QEMU

I have an aarch64 library for Linux and I want to use it from within an amd64 Linux install. Currently, I know one method of getting this to work, which is to use the qemu-arm-static binary emulator with an aarch64 executable I compile myself, that calls dlopen on the aarch64 library and uses it.
The annoyance is that integrating the aarch64 executable with my amd64 environment is annoying (eg. let's say, for example, this arm64 library is from an IoT device and decodes a special video file in real time—how am I supposed to use the native libraries on my computer to play it?). I end up using UNIX pipes, but I really dislike this solution.
Is there a way I can use the qemu-arm-static stuff only with the library, so I can have an amd64 executable that directly calls the library? If not, what's the best way to interface between the two architectures? Is it pipes?
The solution that I implemented for this is to use shared memory IPC. This solution is particularly nice since it integrates pretty well with fixed-length C structs, allowing you to simply just use a struct on one end and the other end.
Let's say you have a function with a signature uint32_t so_lib_function_a(uint32_t c[2])
You can write a wrapper function in an amd64 library: uint32_t wrapped_so_lib_function_a(uint32_t c[2]).
Then, you create a shared memory structure:
typedef struct {
uint32_t c[2];
uint32_t ret;
int turn; // turn = 0 means amd64 library, turn = 1 means arm library
} ipc_call_struct;
Initialise a struct like this, and then run shmget(SOME_SHM_KEY, sizeof(ipc_call_struct), IPC_CREAT | 0777);, get the return value from that, and then get a pointer to the shared memory. Then copy the initialised struct into shared memory.
You then run shmget(3) and shmat(3) on the ARM binary side, getting a pointer to the shared memory as well. The ARM binary runs an infinite loop, waiting for its "turn." When turn is set to 1, the amd64 binary will block in a forever loop until the turn is 0. The ARM binary will execute the function, using the shared struct details as parameters and updating the shared memory struct with the return value. Then the ARM library will set the turn to 0 and block until turn is 1 again, which will allow the amd64 binary to do its thing until it's ready to call the ARM function again.
Here is an example (it might not compile yet, but it gives you a general idea):
Our "unknown" library : shared.h
#include <stdint.h>
#define MAGIC_NUMBER 0x44E
uint32_t so_lib_function_a(uint32_t c[2]) {
// Add args and multiplies by MAGIC_NUMBER
uint32_t ret;
for (int i = 0; i < 2; i++) {
ret += c[i];
}
ret *= MAGIC_NUMBER;
return ret;
}
Hooking into the "unknown" library: shared_executor.c
#include <dlfcn.h>
#include <sys/shm.h>
#include <stdint.h>
#define SHM_KEY 22828 // Some random SHM ID
uint32_t (*so_lib_function_a)(uint32_t c[2]);
typedef struct {
uint32_t c[2];
uint32_t ret;
int turn; // turn = 0 means amd64 library, turn = 1 means arm library
} ipc_call_struct;
int main() {
ipc_call_struct *handle;
void *lib_dlopen = dlopen("./shared.so", RTLD_LAZY);
so_lib_function_a = dlsym(lib_dlopen, "so_lib_function_a");
// setup shm
int shm_id = shmget(SHM_KEY, sizeof(ipc_call_struct), IPC_CREAT | 0777);
handle = shmat(shm_id, NULL, 0);
// We expect the handle to already be initialised by the time we get here, so we don't have to do anything
while (true) {
if (handle->turn == 1) { // our turn
handle->ret = so_lib_function_a(handle->c);
handle->turn = 0; // hand off for later
}
}
}
On the amd64 side: shm_shared.h
#include <stdint.h>
#include <sys/shm.h>
typedef struct {
uint32_t c[2];
uint32_t ret;
int turn; // turn = 0 means amd64 library, turn = 1 means arm library
} ipc_call_struct;
#define SHM_KEY 22828 // Some random SHM ID
static ipc_call_struct* handle;
void wrapper_init() {
// setup shm here
int shm_id = shmget(SHM_KEY, sizeof(ipc_call_struct), IPC_CREAT | 0777);
handle = shmat(shm_id, NULL, 0);
// Initialise the handle
// Currently, we don't want to call the ARM library, so the turn is still zero
ipc_call_struct temp_handle = { .c={0}, .ret=0, .turn=0 };
*handle = temp_handle;
// you should be able to fork the ARM binary using "qemu-arm-static" here
// (and add code for that if you'd like)
}
uint32_t wrapped_so_lib_function_a(uint32_t c[2]) {
handle->c = c;
handle->turn = 1; // hand off execution to the ARM librar
while (handle->turn != 0) {} // wait
return handle->ret;
}
Again, there's no guarantee this code even compiles (yet), but just a general idea.

packet.c:98:2: error: 'writebuf' undeclared (first use in this function)

I'm trying to compile dropbear for windows before I compiled it but now that I try to recompile it and format my previous pc, install cygwin and what is necessary but when I execute the make command, it throws me that error. but I do not understand why it says that it is not declared if it is clearly seen there, I would appreciate your help.
ERROR: "packet.c: In function 'write_packet':
packet.c:98:2: error: 'writebuf' undeclared (first use in this function)
writebuf = (buffer*)examine(&ses.writequeue);"
CODE:
#ifdef HAVE_WRITEV
/* 50 is somewhat arbitrary */
unsigned int iov_count = 50;
struct iovec iov[50];
#else
int len;
buffer* writebuf;
int packet_type;
#endif
TRACE2(("enter write_packet"))
dropbear_assert(!isempty(&ses.writequeue));
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
/* This may return EAGAIN. The main loop sometimes
calls write_packet() without bothering to test with select() since
it's likely to be necessary */
written = writev(ses.sock_out, iov, iov_count);
if (written < 0) {
if (errno == EINTR || errno == EAGAIN) {
TRACE2(("leave write_packet: EINTR"))
return;
} else {
dropbear_exit("Error writing: %s", strerror(errno));
}
}
packet_queue_consume(&ses.writequeue, written);
ses.writequeue_len -= written;
if (written == 0) {
ses.remoteclosed();
}
#else /* No writev () */
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
/* The last byte of the buffer is not to be transmitted, but is
* a cleartext packet_type indicator */
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
TRACE2(("write_packet type %d len %d/%d", packet_type,
len, writebuf->len-1))
dropbear_assert(len > 0);
The problem seems due that the definition protected by a single check
#ifdef HAVE_WRITEV
while the usage is behind a multiple check
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
HAVE_WRITEV is defined in config.h on cygwin, so the definition is skipped but the check for usage fails and writebuf is used.
It seems a upstream bug.

C++ no acceptable conversion for operator+ with class

I have some 15-year-old C++ code that I am trying to bring up to more modern times. At this stage, I'm trying to get code that compiled with Visual C++ 6.0 to now compile with VS 2003 (Microsoft Visual C++ .NET 69462-335-0000007-18915). If we can get this to compile cleanly & run properly, then we can take another step to get it into a more recent version of VS. But I'm having a number of problems...
Here is a snippet of the (simplified) code:
class toS
{
public:
toS() { buff[0] ='\0'; }
operator LPCTSTR() { return buff; }
protected:
void Append (TCHAR c)
{
LPTSTR p = buff + _tcslen(buff);
*p++ = c;
*p = '\0';
}
TCHAR buff[40];
};
class LtoS : public toS
{
public:
LtoS(LONG n, TCHAR c = '\0')
{
_ltot(n, buff, 10);
Append(c);
}
};
void WriteBool(const CString& Section, const CString& Key, bool Value);
CString Section;
int nLine = 0;
std::vector<bool> *BoolVect;
std::vector<bool>::iterator vi;
...
for (vi = BoolVect->begin(); vi != BoolVect->end(); vi++)
WriteBool(Section, "LineVis " + LtoS(nLine++), *vi);
...
From this I get the following error message:
error C2677: binary '+' : no global operator found which takes type 'LtoS' (or there is no acceptable conversion)
Any idea how this code ever worked? If I can find out what it did in the past, I can begin to define the overloaded operator+ to match the functionality.
Compiler error goes away when I make class tos inherit from CString with:
class tos : public CString { ... }
Hopefully this will not only compile, but will execute correctly...
Deriving from several of the comments, try adding a public conversion operator to class toS as follows:
operator LPCTSTR() const { return &buff[0]; }
You may need to explicitly construct the string in the for loop as well, e.g.:
WriteBool(Section, CString("LineVis ") + static_cast<LPCTSTR>(LtoS(nLine++)), *vi);
(Side note: As you probably know since you just extracted code for an example, there's a problem here:
std::vector<bool> BoolVect;
...
for (vi = BoolVect->begin(); vi != BoolVect->end(); vi++)
The notation you're using to access the BoolVect implies that it is a pointer, but it's not being declared as such in your example.)

Finding addresses of called functions C

I want to find addresses of functions on stack without using builtin macros or some library functions.(I know that all functions are called with call rel32) So what I want to do is: get address of local variable, iterate through stack looking for 0xe8 byte (opcode of call) and if I find it function's address should be 5 bytes further. This is what I have know:
extern void *__libc_stack_end;
void stack_show() {
int x;
for (uint8_t* i = &x; i < __libc_stack_end; i++) {
if(i == 0xe8) {
int64_t *a = i + 5;
printf("%p\n", a);
}
}
}
But it doesn't work. I'm not sure if types of my variables are OK.I'm using Linux and x86 architecture.
Any help appreciated.
Thanks.

Unzipping archive on Windows 8

I have previously used MiniZip (zlib wrapper) to unzip archives. MiniZip cannot be used for Metro applications as it uses deprecated APIs in "iowin32.c" -- CreateFile() and SetFilePointer().
I thought that would be an easy fix and created "iowinrt.c" with CreateFile() and SetFilePointer() replaced with CreateFile2() and SetFilePointerEx(). While this way I obtained a version of MiniZip that uses only approved Win8 APIs, it still turned out to be useless -- I forgot about sandboxing. If I pick a file using FileOpenPicker() and pass its path to my modified MiniZip I still cannot open it -- CreateFile2() will fail with "Access is denied." message.
So it appears that old C API for file access if now mostly useless; it is my understanding that in order to fix this I would need to reimplement my "iowinrt" in C++/CX using the new async file access. Are there any other options? I think I saw somewhere that WinRT does have compress/uncompress functionality but that it only works on individual files, not archives.
Additional requirements it that I need this to work in memory.
For a moment I thought I had a solution via .NET Framework 4.5:
I found this piece of info about how to create .NET classes that can be used from C++/CX:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/3ff383d0-0c9f-4a30-8987-ff2b23957f01
.NET Framework 4.5 contains ZipArchive and ZipArchiveEntry classes in System.IO.Compression:
http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive%28v=vs.110%29.aspx#Y0
http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchiveentry%28v=vs.110%29.aspx#Y0
I thought I could create C# Metro Class Library with WinMD Output type exposing ZipArchive and ZipArchiveEntry then use that in my C++/CX project. However, even if it worked it would not work in-memory; it appears that ZipArchive and ZipArchiveEntry work only with files.
Got reading from archive working. Explanation and code below but really just a hack at this point, to see if it's possible at all. I just kept modifying things until I got something working; this is just an example of what works and by no means a production quality code (it's not re-entrant for start). There are undoubtedly many things that are bad/unnecessary/wtf so feel free to use comments to help with clean up.
As mentioned previously, it is no longer enough to pass path to the library -- unless file is in one of KnownFolders (documents, home, media, music, pictures, removable or videos) you end up with "access is denied" message. Instead, library must be able to accept StorageFile^, as returned from FileOpenPicker. At least I haven't found any other way to do it, maybe someone knows better?
MiniZip provides Windows filesystem access layer for zlib via iowin32.h/.c. This still works in desktop mode for old-style apps, but does not work for Metro apps as it uses deprecated APIs and relies on paths. To get MiniZip going on Windows 8, a complete rewrite of iowin32 is required.
To get things working again, first thing was to find a way to pass StorageFile^ all the way down to iowinrt (Windows 8 replacement for iowin32). Fortunately, that was not a problem as MiniZip provides two styles of open file functions -- ones that accept pointer to char, and the others accepting pointer to void. Since ^ is still just a pointer, casting StorageFile^ to void* and than back to StorageFile^ works fine.
Now that I was able to pass StorageFile^ to my new iowinrt, the next problem was how to make new async C++ file access API work with Zlib. In order to support very old C compilers, Zlib is written with old K&R style C. VisualStudio compiler will refuse to compile this as C++, it has to be compiled as C, and new iowinrt must be compiled as C++ of course -- keep that in mind when creating your project. Other things to note about VS project is that I did it as Visual C++ Windows Metro style Static Library although DLL should also work but then you must also define macro to export MiniZip API (I haven't tried this, don't know which macro you have to use). I think I also had to set "Consume Windows Runtime Extension" (/ZW), set "Not Using Precompiled Headers" and add _CRT_SECURE_NO_WARNINGS and _CRT_NONSTDC_NO_WARNINGS to Preprocessor Definitions.
As for iowinrt itself, I've split it in two files. One holds two sealed ref classes -- reader and writer objects; they accept StorageFile^. Reader implements Read, Tell, SeekFromBeginning, SeekFromCurrent and SeekFromEnd (the reason for 3 Seek methods is because ref sealed classes have to stick with RT types and that apparently excludes enums so I just took the easy route). Writer implements just Write at the moment, haven't used it yet.
This is FileReader code:
#include "pch.h"
#include "FileAccess.h" // FileReader and FileWriter
using namespace Concurrency;
using namespace Windows::Security::Cryptography;
using namespace CFileAccess;
FileReader::FileReader(StorageFile^ archive)
{
if (nullptr != archive)
{
create_task(archive->OpenReadAsync()).then([this](IRandomAccessStreamWithContentType^ archiveStream)
{
if (nullptr != archiveStream)
{
_readStream = archiveStream;
}
}).wait();
}
} // end of constructor
int32 FileReader::Read(WriteOnlyArray<byte>^ fileData)
{
int32 bytesRead = 0;
if ((nullptr != _readStream) && (fileData->Length > 0))
{
try
{
auto inputStreamReader = ref new DataReader(_readStream);
create_task(inputStreamReader->LoadAsync(fileData->Length)).then([&](task<unsigned int> dataRead)
{
try
{
bytesRead = dataRead.get();
if (bytesRead)
{
inputStreamReader->ReadBytes(fileData);
}
}
catch (Exception^ e)
{
bytesRead = -1;
}
inputStreamReader->DetachStream();
}).wait();
}
catch (Exception^ e)
{
bytesRead = -1;
}
}
return (bytesRead);
} // end of method Read()
int64 FileReader::Tell(void)
{
int64 ret = -1;
if (nullptr != _readStream)
{
ret = _readStream->Position;
}
return (ret);
} // end of method Tell()
int64 FileReader::SeekFromBeginning(uint64 offset)
{
int64 ret = -1;
if ((nullptr != _readStream) && (offset < _readStream->Size))
{
_readStream->Seek(offset);
ret = 0;
}
return (ret);
} // end of method SeekFromBeginning()
int64 FileReader::SeekFromCurrent(uint64 offset)
{
int64 ret = -1;
if ((nullptr != _readStream) && ((_readStream->Position + offset) < _readStream->Size))
{
_readStream->Seek(_readStream->Position + offset);
ret = 0;
}
return (ret);
} // end of method SeekFromCurrent()
int64 FileReader::SeekFromEnd(uint64 offset)
{
int64 ret = -1;
if ((nullptr != _readStream) && ((_readStream->Size - offset) >= 0))
{
_readStream->Seek(_readStream->Size - offset);
ret = 0;
}
return (ret);
} // end of method SeekFromEnd()
iowinrt sits between MiniZip and FileReader (and FileWriter). It's too long to give everything here but this should be sufficient to reconstruct the rest since it's mostly just more of the same with different function names, plus a bunch of fill_winRT_filefuncxxx() which are obvious:
#include "zlib.h"
#include "ioapi.h"
#include "iowinrt.h"
#include "FileAccess.h"
using namespace Windows::Security::Cryptography;
using namespace Platform;
using namespace CFileAccess;
static FileReader^ g_fileReader = nullptr;
static FileWriter^ g_fileWriter = nullptr;
static StorageFile^ g_storageFile = nullptr;
[...]
static voidpf winRT_translate_open_mode(int mode)
{
if (nullptr != g_storageFile)
{
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
{
g_fileWriter = nullptr;
g_fileReader = ref new FileReader(g_storageFile);
}
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
{
g_fileReader = nullptr;
g_fileWriter = ref new FileWriter(g_storageFile);
}
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
{
g_fileReader = nullptr;
g_fileWriter = ref new FileWriter(g_storageFile);
}
}
return (nullptr != g_fileReader ? reinterpret_cast<voidpf>(g_fileReader) : reinterpret_cast<voidpf>(g_fileWriter));
}
voidpf ZCALLBACK winRT_open64_file_func (voidpf opaque,const void* storageFile,int mode)
{
g_storageFile = reinterpret_cast<StorageFile^>(const_cast<void*>(storageFile));
return (winRT_translate_open_mode(mode));
}
[...]
Long ZCALLBACK winRT_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size)
{
uLong bytesRead = 0;
if (nullptr != g_fileReader)
{
auto fileData = ref new Platform::Array<byte>(size);
bytesRead = g_fileReader->Read(fileData);
memcpy(buf, fileData->Data, fileData->Length);
}
return (bytesRead);
}
uLong ZCALLBACK winRT_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size)
{
uLong bytesWritten = 0;
if (nullptr != g_fileWriter)
{
auto bytes = ref new Array<uint8>(reinterpret_cast<uint8*>(const_cast<void*>(buf)), size);
IBuffer ^writeBuffer = CryptographicBuffer::CreateFromByteArray(bytes);
bytesWritten = g_fileWriter->Write(writeBuffer);
}
return (bytesWritten);
}
long ZCALLBACK winRT_tell_file_func (voidpf opaque,voidpf stream)
{
long long ret = 0;
if (nullptr != g_fileReader)
{
ret = g_fileReader->Tell();
}
return (static_cast<long>(ret));
}
ZPOS64_T ZCALLBACK winRT_tell64_file_func (voidpf opaque, voidpf stream)
{
ZPOS64_T ret = 0;
if (nullptr != g_fileReader)
{
ret = g_fileReader->Tell();
}
return (ret);
}
[...]
long ZCALLBACK winRT_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin)
{
long long ret = -1;
if (nullptr != g_fileReader)
{
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
ret = g_fileReader->SeekFromCurrent(offset);
break;
case ZLIB_FILEFUNC_SEEK_END :
ret = g_fileReader->SeekFromEnd(offset);
break;
case ZLIB_FILEFUNC_SEEK_SET :
ret = g_fileReader->SeekFromBeginning(offset);
break;
default:
// should never happen!
ret = -1;
break;
}
}
return (static_cast<long>(ret));
}
int ZCALLBACK winRT_close_file_func (voidpf opaque, voidpf stream)
{
g_fileWriter = nullptr;
g_fileReader = nullptr;
return (0);
}
int ZCALLBACK winRT_error_file_func (voidpf opaque,voidpf stream)
{
/// #todo Get errors from FileAccess
return (0);
}
This is enough to get MiniZip going (at least for reading) but you have to take care how you call MiniZip functions -- since Metro is all about async and blocking UI thread will end up with exception, you must wrap access in tasks:
FileOpenPicker^ openPicker = ref new FileOpenPicker();
openPicker->ViewMode = PickerViewMode::List;
openPicker->SuggestedStartLocation = PickerLocationId::ComputerFolder;
openPicker->FileTypeFilter->Append(".zip");
task<IVectorView<StorageFile^>^>(openPicker->PickMultipleFilesAsync()).then([this](IVectorView<StorageFile^>^ files)
{
if (files->Size > 0)
{
std::for_each(begin(files), end(files), [this](StorageFile ^file)
{ // open selected zip archives
create_task([this, file]()
{
OpenArchive(file);
[...]
});
});
}
else
{
rootPage->NotifyUserBackgroundThread("No files were returned.", NotifyType::ErrorMessage);
}
});
[...]
bool OpenArchive(StorageFile^ archive)
{
bool isArchiveOpened = false;
if (nullptr != archive)
{ // open ZIP archive
zlib_filefunc64_def ffunc;
fill_winRT_filefunc64(&ffunc);
unzFile archiveObject = NULL;
create_task([this, &ffunc, archive]()
{
archiveObject = unzOpen2_64(reinterpret_cast<const void*>(archive), &ffunc);
}).wait();
if (NULL != archiveObject)
{
[...]

Resources