Switch tab-indented files to 4-space indent

This commit is contained in:
Wolfgang Thaller
2019-08-18 13:21:00 +02:00
parent 9cb90cb3b0
commit e5185d23c3
133 changed files with 7879 additions and 7866 deletions
+13
View File
@@ -6,6 +6,9 @@ indent_style = space
tab_width = 4
charset = utf-8
[InterfacesAndLibraries/**/*]
indent_style = tab
[gcc/**/*]
indent_style = tab
tab_width = 8
@@ -16,5 +19,15 @@ indent_style = tab
tab_width = 8
indent_width = 2
[libelf/**/*]
indent_style = tab
tab_width = 8
indent_width = 2
[hfsutils/**/*]
indent_style = tab
tab_width = 8
indent_width = 2
[**/Makefile]
indent_style=tab
+20 -20
View File
@@ -1,20 +1,20 @@
find_program(LAUNCH_APPL LaunchAPPL PATH "${CMAKE_INSTALL_PREFIX}/../bin/")
execute_process(COMMAND ${LAUNCH_APPL} --list-emulators
OUTPUT_VARIABLE EMULATOR_LIST)
OUTPUT_VARIABLE EMULATOR_LIST)
string(REPLACE "\n" ";" EMULATOR_LIST "${EMULATOR_LIST}")
if(CMAKE_SYSTEM_NAME MATCHES "RetroCarbon")
if("carbon" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD carbon CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
if("carbon" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD carbon CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
else()
if("classic" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD classic CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
if("classic" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD classic CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "RetroCarbon")
@@ -33,17 +33,17 @@ set(LAUNCH_METHOD_FLAG)
if(RETRO68_LAUNCH_METHOD MATCHES "NONE")
else()
set(LAUNCH_METHOD_FLAG "-e${RETRO68_LAUNCH_METHOD}")
endif() # RETRO68_LAUNCH_METHOD
endif() # RETRO68_LAUNCH_METHOD
enable_testing()
function(test FILE)
get_filename_component(NAME ${FILE} NAME_WE)
get_filename_component(NAME ${FILE} NAME_WE)
add_application(${NAME} ${FILE} Test.h Test.c)
target_include_directories(${NAME} PRIVATE .)
add_test(NAME ${TESTCASE_PREFIX}${NAME} COMMAND ${LAUNCH_APPL}
add_test(NAME ${TESTCASE_PREFIX}${NAME} COMMAND ${LAUNCH_APPL}
${LAUNCH_METHOD_FLAG} ${RETRO68_TEST_CONFIG} ${NAME}.bin)
if(ARGN)
set_tests_properties(${TESTCASE_PREFIX}${NAME} ${ARGN})
@@ -51,8 +51,8 @@ function(test FILE)
endfunction()
if(CMAKE_SYSTEM_NAME MATCHES "Retro68")
test(ReallyEmpty.c)
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
test(ReallyEmpty.c)
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
endif()
test(Empty.c)
@@ -70,10 +70,10 @@ test(Init.cc PROPERTIES PASS_REGULAR_EXPRESSION "constructor\nmain\ndestructor")
test(StdIO.c PROPERTIES PASS_REGULAR_EXPRESSION "OK")
if(CMAKE_SYSTEM_NAME MATCHES Retro68)
add_application(Segments Segment1.c Segment2.c Segments.segmap Test.h Test.c)
set_target_properties(Segments PROPERTIES
LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-segments -Wl,${CMAKE_CURRENT_SOURCE_DIR}/Segments.segmap")
add_test(NAME ${TESTCASE_PREFIX}Segments COMMAND ${LAUNCH_APPL}
add_application(Segments Segment1.c Segment2.c Segments.segmap Test.h Test.c)
set_target_properties(Segments PROPERTIES
LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-segments -Wl,${CMAKE_CURRENT_SOURCE_DIR}/Segments.segmap")
add_test(NAME ${TESTCASE_PREFIX}Segments COMMAND ${LAUNCH_APPL}
${LAUNCH_METHOD_FLAG} ${RETRO68_TEST_CONFIG} Segments.bin)
endif()
+2 -2
View File
@@ -1,5 +1,5 @@
int main()
{
// Test: do things work well enough for us to get to main()?
return 0;
// Test: do things work well enough for us to get to main()?
return 0;
}
+1 -1
View File
@@ -2,5 +2,5 @@
int main()
{
TEST_LOG_OK();
TEST_LOG_OK();
}
+10 -10
View File
@@ -3,20 +3,20 @@
class Constructed
{
public:
Constructed()
{
TestLog("constructor");
}
~Constructed()
{
TestLog("destructor");
}
Constructed()
{
TestLog("constructor");
}
~Constructed()
{
TestLog("destructor");
}
};
Constructed thing;
int main()
{
TestLog("main");
return 0;
TestLog("main");
return 0;
}
+6 -6
View File
@@ -4,10 +4,10 @@ char readWriteData[6] = "Three";
int main()
{
// constant initialized data
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
// read-write initialized data
TEST_LOG_SIZED(readWriteData,5);
return 0;
// constant initialized data
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
// read-write initialized data
TEST_LOG_SIZED(readWriteData,5);
return 0;
}
+2 -2
View File
@@ -1,6 +1,6 @@
void _start()
{
// Test: do things work well enough for us to get to a startup function?
// Note: this won't work for multisegment 68K apps, as the startup function will be in the wrong segment.
// Test: do things work well enough for us to get to a startup function?
// Note: this won't work for multisegment 68K apps, as the startup function will be in the wrong segment.
}
+64 -64
View File
@@ -10,87 +10,87 @@ void Bar();
Boolean Test(Boolean unloadFoo, Boolean unloadBar, Boolean compact)
{
variable = 6;
Foo();
if(variable != 54)
{
TestLog("Expected 54 after Foo().");
return false;
}
variable = 6;
Foo();
if(variable != 54)
{
TestLog("Expected 54 after Foo().");
return false;
}
if(unloadFoo)
UnloadSeg(&Foo);
if(unloadBar)
UnloadSeg(&Bar);
if(unloadFoo)
UnloadSeg(&Foo);
if(unloadBar)
UnloadSeg(&Bar);
Size grow;
if(compact)
MaxMem(&grow);
Size grow;
if(compact)
MaxMem(&grow);
Bar();
if(variable != 42)
{
TestLog("Expected 42 after Bar().");
return false;
}
return true;
Bar();
if(variable != 42)
{
TestLog("Expected 42 after Bar().");
return false;
}
return true;
}
int main()
{
Size grow, maxblock, maxblock2, freemem, freemem2;
Size grow, maxblock, maxblock2, freemem, freemem2;
MaxApplZone(); // just to keep things simple and predictable
MoreMasters();
MaxApplZone(); // just to keep things simple and predictable
MoreMasters();
maxblock = MaxMem(&grow);
freemem = FreeMem();
maxblock = MaxMem(&grow);
freemem = FreeMem();
TestLog("1. No unloading");
if(!Test(false, false, false))
return 1;
TestLog("1. No unloading");
if(!Test(false, false, false))
return 1;
maxblock2 = MaxMem(&grow);
maxblock2 = MaxMem(&grow);
TestLog("2. UnloadSeg(&Foo)");
if(!Test(true, false, false))
return 1;
TestLog("3. UnloadSeg(&Bar)");
if(!Test(false, true, false))
return 1;
TestLog("4. UnloadSeg(&Foo); UnloadSeg(&Bar)");
if(!Test(true, true, false))
return 1;
TestLog("2. UnloadSeg(&Foo)");
if(!Test(true, false, false))
return 1;
TestLog("3. UnloadSeg(&Bar)");
if(!Test(false, true, false))
return 1;
TestLog("4. UnloadSeg(&Foo); UnloadSeg(&Bar)");
if(!Test(true, true, false))
return 1;
TestLog("5. UnloadSeg(&Foo); MaxMem()");
if(!Test(true, false, true))
return 1;
TestLog("6. UnloadSeg(&Bar); MaxMem()");
if(!Test(false, true, true))
return 1;
TestLog("7. UnloadSeg(&Foo); UnloadSeg(&Bar); MaxMem()");
if(!Test(true, true, true))
return 1;
TestLog("5. UnloadSeg(&Foo); MaxMem()");
if(!Test(true, false, true))
return 1;
TestLog("6. UnloadSeg(&Bar); MaxMem()");
if(!Test(false, true, true))
return 1;
TestLog("7. UnloadSeg(&Foo); UnloadSeg(&Bar); MaxMem()");
if(!Test(true, true, true))
return 1;
UnloadSeg(&Foo);
UnloadSeg(&Foo);
maxblock2 = MaxMem(&grow);
freemem2 = FreeMem();
maxblock2 = MaxMem(&grow);
freemem2 = FreeMem();
if(maxblock2 < maxblock || freemem2 < freemem)
{
TestLog("Leak");
char s[256];
sprintf(s, "maxblock: %d (delta %d), freemem: %d (delta %d)",
maxblock2, maxblock2-maxblock, freemem2, freemem2-freemem);
TestLog(s);
return 1;
}
else if(maxblock2 > maxblock || freemem2 > freemem)
TestLog("Magic Memory");
if(maxblock2 < maxblock || freemem2 < freemem)
{
TestLog("Leak");
char s[256];
sprintf(s, "maxblock: %d (delta %d), freemem: %d (delta %d)",
maxblock2, maxblock2-maxblock, freemem2, freemem2-freemem);
TestLog(s);
return 1;
}
else if(maxblock2 > maxblock || freemem2 > freemem)
TestLog("Magic Memory");
TestLog("OK");
TestLog("OK");
return 0;
return 0;
}
+3 -3
View File
@@ -2,11 +2,11 @@ extern int variable;
#include <SegLoad.h>
void Foo()
{
variable *= 9;
variable *= 9;
}
void Bar()
{
variable /= 9;
variable *= 7;
variable /= 9;
variable *= 7;
}
+3 -3
View File
@@ -2,7 +2,7 @@
int main()
{
FILE *f = fopen("out", "w");
fprintf(f, "OK\n");
fclose(f);
FILE *f = fopen("out", "w");
fprintf(f, "OK\n");
fclose(f);
}
+1 -1
View File
@@ -2,5 +2,5 @@
void TestLog(const char *str)
{
TEST_LOG_SIZED(str, strlen(str));
TEST_LOG_SIZED(str, strlen(str));
}
+62 -62
View File
@@ -22,52 +22,52 @@ void TestLog(const char *str);
/* The same thing as a macro. String length has to be given explicitly,
* to avoid a call to strlen(). */
#define TEST_LOG_SIZED(str, size) \
do { \
HParamBlockRec _hpb; \
\
unsigned char _fileName[4]; \
short _ref;\
_fileName[0] = 3; \
_fileName[1] = 'o'; \
_fileName[2] = 'u'; \
_fileName[3] = 't'; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = (StringPtr)_fileName; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.fileParam.ioDirID = 0; \
_hpb.ioParam.ioPermssn = fsRdWrPerm; \
_hpb.ioParam.ioMisc = NULL; \
PBHOpenSync(&_hpb); \
_ref = _hpb.ioParam.ioRefNum; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = (Ptr)str; \
_hpb.ioParam.ioReqCount = size; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
char _newline = '\n'; \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = &_newline; \
_hpb.ioParam.ioReqCount = 1; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBCloseSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = NULL; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.ioParam.ioMisc = NULL; \
PBFlushVolSync((ParmBlkPtr)&_hpb); \
} while(0);
do { \
HParamBlockRec _hpb; \
\
unsigned char _fileName[4]; \
short _ref;\
_fileName[0] = 3; \
_fileName[1] = 'o'; \
_fileName[2] = 'u'; \
_fileName[3] = 't'; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = (StringPtr)_fileName; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.fileParam.ioDirID = 0; \
_hpb.ioParam.ioPermssn = fsRdWrPerm; \
_hpb.ioParam.ioMisc = NULL; \
PBHOpenSync(&_hpb); \
_ref = _hpb.ioParam.ioRefNum; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = (Ptr)str; \
_hpb.ioParam.ioReqCount = size; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
char _newline = '\n'; \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = &_newline; \
_hpb.ioParam.ioReqCount = 1; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBCloseSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = NULL; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.ioParam.ioMisc = NULL; \
PBFlushVolSync((ParmBlkPtr)&_hpb); \
} while(0);
/*
* Output either "OK" or "NO".
@@ -75,23 +75,23 @@ void TestLog(const char *str);
* we might not want to test them yet.
*/
#define TEST_LOG_OK() \
do { \
char ok[3]; \
ok[0] = 'O'; \
ok[1] = 'K'; \
ok[2] = '\0'; \
TEST_LOG_SIZED(ok, 2); \
} while(0)
#define TEST_LOG_OK() \
do { \
char ok[3]; \
ok[0] = 'O'; \
ok[1] = 'K'; \
ok[2] = '\0'; \
TEST_LOG_SIZED(ok, 2); \
} while(0)
#define TEST_LOG_NO() \
do { \
char no[3]; \
no[0] = 'O'; \
no[1] = 'K'; \
no[2] = '\0'; \
TEST_LOG_SIZED(no, 2); \
} while(0)
#define TEST_LOG_NO() \
do { \
char no[3]; \
no[0] = 'O'; \
no[1] = 'K'; \
no[2] = '\0'; \
TEST_LOG_SIZED(no, 2); \
} while(0)
#endif // TEST_H
+6 -6
View File
@@ -2,10 +2,10 @@
int main()
{
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
for(;;)
;
TEST_LOG_SIZED("Three",5);
return 0;
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
for(;;)
;
TEST_LOG_SIZED("Three",5);
return 0;
}
+35 -35
View File
@@ -10,45 +10,45 @@ EventRecord e;
int main()
{
int i;
if(commonSymbol)
{
TEST_LOG_NO();
return 1;
}
if(zeroInited)
{
TEST_LOG_NO();
return 1;
}
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i])
{
TEST_LOG_NO();
return 1;
}
zeroInitedArray[i] = 42;
}
int i;
if(commonSymbol)
{
TEST_LOG_NO();
return 1;
}
if(zeroInited)
{
TEST_LOG_NO();
return 1;
}
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i])
{
TEST_LOG_NO();
return 1;
}
zeroInitedArray[i] = 42;
}
// Initialize some of the Macintosh Toolbox
// and maybe trigger a context switch, so we can be sure
// our global variables were put in the right placce.
#if !TARGET_API_MAC_CARBON
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
#endif
GetNextEvent(everyEvent, &e);
GetNextEvent(everyEvent, &e);
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i] != 42)
{
TEST_LOG_NO();
return 1;
}
}
TEST_LOG_OK();
return 0;
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i] != 42)
{
TEST_LOG_NO();
return 1;
}
}
TEST_LOG_OK();
return 0;
}
+10 -10
View File
@@ -16,15 +16,15 @@
# along with Retro68. If not, see <http://www.gnu.org/licenses/>.
add_library(RetroConsole
retro/Console.cc
retro/Console.h
retro/ConsoleWindow.cc
retro/ConsoleWindow.h
retro/MacUtils.h
retro/InitConsole.cc
)
retro/Console.cc
retro/Console.h
retro/ConsoleWindow.cc
retro/ConsoleWindow.h
retro/MacUtils.h
retro/InitConsole.cc
)
set_target_properties(retrocrt
PROPERTIES
PROPERTIES
COMPILE_OPTIONS -ffunction-sections)
# different library name for Carbon
@@ -37,6 +37,6 @@ target_include_directories(RetroConsole PUBLIC .)
install(TARGETS RetroConsole DESTINATION lib)
add_application(ConsoleTest
ConsoleTest.cc
)
ConsoleTest.cc
)
target_link_libraries(ConsoleTest RetroConsole)
+13 -13
View File
@@ -3,21 +3,21 @@
namespace retro
{
void InitConsole();
void InitConsole();
}
int main()
{
retro::InitConsole();
std::string out = "Hello, world.\nEnter \"exit\" to quit.\n";
retro::Console::currentInstance->write(out.data(), out.size());
std::string in;
do
{
in = retro::Console::currentInstance->ReadLine();
out = "You Entered: " + in;
retro::Console::currentInstance->write(out.data(), out.size());
} while(in != "exit\n");
return 0;
retro::InitConsole();
std::string out = "Hello, world.\nEnter \"exit\" to quit.\n";
retro::Console::currentInstance->write(out.data(), out.size());
std::string in;
do
{
in = retro::Console::currentInstance->ReadLine();
out = "You Entered: " + in;
retro::Console::currentInstance->write(out.data(), out.size());
} while(in != "exit\n");
return 0;
}
+1 -1
View File
@@ -293,7 +293,7 @@ std::string Console::ReadLine()
char c;
do
{
{
c = WaitNextChar();
if(!c)
{
+44 -44
View File
@@ -25,66 +25,66 @@
namespace retro
{
class Console
{
public:
Console();
Console(GrafPtr port, Rect r);
~Console();
class Console
{
public:
Console();
Console(GrafPtr port, Rect r);
~Console();
void Reshape(Rect newBounds);
void Reshape(Rect newBounds);
void Draw(Rect r);
void Draw() { Draw(bounds); }
void putch(char c);
void Draw(Rect r);
void Draw() { Draw(bounds); }
void putch(char c);
void write(const char *s, int n);
std::string ReadLine();
void write(const char *s, int n);
std::string ReadLine();
static Console *currentInstance;
static Console *currentInstance;
short GetRows() const { return rows; }
short GetCols() const { return cols; }
void Idle();
short GetRows() const { return rows; }
short GetCols() const { return cols; }
void Idle();
bool IsEOF() const { return eof; }
private:
GrafPtr consolePort = nullptr;
Rect bounds;
private:
GrafPtr consolePort = nullptr;
Rect bounds;
std::vector<char> chars, onscreen;
std::vector<char> chars, onscreen;
short cellSizeX;
short cellSizeY;
short cellSizeX;
short cellSizeY;
short rows = 0, cols = 0;
short rows = 0, cols = 0;
short cursorX, cursorY;
short cursorX, cursorY;
Rect dirtyRect = {};
long blinkTicks = 0;
bool cursorDrawn = false;
bool cursorVisible = true;
Rect dirtyRect = {};
long blinkTicks = 0;
bool cursorDrawn = false;
bool cursorVisible = true;
bool eof = false;
void PutCharNoUpdate(char c);
void Update();
void PutCharNoUpdate(char c);
void Update();
Rect CellRect(short x, short y);
void DrawCell(short x, short y, bool erase = true);
void DrawCells(short x1, short x2, short y, bool erase = true);
void ScrollUp(short n = 1);
void InvalidateCursor();
Rect CellRect(short x, short y);
void DrawCell(short x, short y, bool erase = true);
void DrawCells(short x1, short x2, short y, bool erase = true);
void ScrollUp(short n = 1);
void InvalidateCursor();
virtual char WaitNextChar();
protected:
void Init(GrafPtr port, Rect r);
};
virtual char WaitNextChar();
protected:
void Init(GrafPtr port, Rect r);
};
}
+73 -73
View File
@@ -25,103 +25,103 @@ using namespace retro;
namespace
{
std::unordered_map<WindowPtr, ConsoleWindow*> *windows = NULL;
std::unordered_map<WindowPtr, ConsoleWindow*> *windows = NULL;
}
ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title)
{
GrafPtr port;
GrafPtr port;
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0);
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0);
#if !TARGET_API_MAC_CARBON
port = win;
Rect portRect = port->portRect;
port = win;
Rect portRect = port->portRect;
#else
port = GetWindowPort(win);
Rect portRect;
GetPortBounds(port, &portRect);
port = GetWindowPort(win);
Rect portRect;
GetPortBounds(port, &portRect);
#endif
SetPort(port);
EraseRect(&portRect);
SetPort(port);
EraseRect(&portRect);
if(!windows)
windows = new std::unordered_map<WindowPtr, ConsoleWindow*>();
(*windows)[win] = this;
if(!windows)
windows = new std::unordered_map<WindowPtr, ConsoleWindow*>();
(*windows)[win] = this;
Init(port, portRect);
Init(port, portRect);
}
ConsoleWindow::~ConsoleWindow()
{
windows->erase(win);
DisposeWindow(win);
windows->erase(win);
DisposeWindow(win);
}
char ConsoleWindow::WaitNextChar()
{
EventRecord event;
WindowPtr eventWin;
ConsoleWindow *realConsole;
EventRecord event;
WindowPtr eventWin;
ConsoleWindow *realConsole;
#if TARGET_API_MAC_CARBON
Rect *boundsPtr = NULL;
Rect *boundsPtr = NULL;
#else
Rect *boundsPtr = &qd.screenBits.bounds;
Rect *boundsPtr = &qd.screenBits.bounds;
#endif
do
{
#if TARGET_API_MAC_CARBON
#define SystemTask()
#endif
SystemTask();
Idle();
while(!GetNextEvent(everyEvent, &event))
{
SystemTask();
Idle();
}
switch(event.what)
{
case updateEvt:
eventWin = (WindowPtr)event.message;
realConsole = (*windows)[(WindowPtr)event.message];
if(realConsole)
{
Rect updateRect;
BeginUpdate(eventWin);
do
{
#if TARGET_API_MAC_CARBON
#define SystemTask()
#endif
SystemTask();
Idle();
while(!GetNextEvent(everyEvent, &event))
{
SystemTask();
Idle();
}
switch(event.what)
{
case updateEvt:
eventWin = (WindowPtr)event.message;
realConsole = (*windows)[(WindowPtr)event.message];
if(realConsole)
{
Rect updateRect;
BeginUpdate(eventWin);
#if TARGET_API_MAC_CARBON
RgnHandle rgn = NewRgn();
GetPortVisibleRegion(GetWindowPort(eventWin), rgn);
GetRegionBounds(rgn, &updateRect);
DisposeRgn(rgn);
RgnHandle rgn = NewRgn();
GetPortVisibleRegion(GetWindowPort(eventWin), rgn);
GetRegionBounds(rgn, &updateRect);
DisposeRgn(rgn);
#else
updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then.
updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then.
#endif
realConsole->Draw(updateRect);
EndUpdate(eventWin);
}
break;
case mouseDown:
switch(FindWindow(event.where, &eventWin))
{
case inDrag:
DragWindow(eventWin, event.where, boundsPtr);
break;
case inGrow:
{
long growResult = GrowWindow(eventWin, event.where, boundsPtr);
SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false);
Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) });
}
break;
}
break;
}
} while(event.what != keyDown && event.what != autoKey);
return event.message & charCodeMask;
realConsole->Draw(updateRect);
EndUpdate(eventWin);
}
break;
case mouseDown:
switch(FindWindow(event.where, &eventWin))
{
case inDrag:
DragWindow(eventWin, event.where, boundsPtr);
break;
case inGrow:
{
long growResult = GrowWindow(eventWin, event.where, boundsPtr);
SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false);
Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) });
}
break;
}
break;
}
} while(event.what != keyDown && event.what != autoKey);
return event.message & charCodeMask;
}
+9 -9
View File
@@ -25,14 +25,14 @@
namespace retro
{
class ConsoleWindow : public Console
{
public:
ConsoleWindow(Rect r, ConstStr255Param title);
~ConsoleWindow();
private:
WindowPtr win;
class ConsoleWindow : public Console
{
public:
ConsoleWindow(Rect r, ConstStr255Param title);
~ConsoleWindow();
private:
WindowPtr win;
virtual char WaitNextChar();
};
virtual char WaitNextChar();
};
}
+46 -46
View File
@@ -1,20 +1,20 @@
/*
Copyright 2014 Wolfgang Thaller.
Copyright 2014 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
@@ -34,26 +34,26 @@
namespace retro
{
void InitConsole();
void InitConsole();
}
using namespace retro;
void retro::InitConsole()
{
if(Console::currentInstance)
return;
if(Console::currentInstance)
return;
Console::currentInstance = (Console*) -1;
#if !TARGET_API_MAC_CARBON
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
Rect r = qd.screenBits.bounds;
Rect r = qd.screenBits.bounds;
#else
Rect r = (*GetMainDevice())->gdRect;
Rect r = (*GetMainDevice())->gdRect;
#endif
{
// give MultiFinder a chance to bring the App to front
@@ -71,41 +71,41 @@ void retro::InitConsole()
EventAvail(everyEvent, &event);
}
r.top += 40;
InsetRect(&r, 5,5);
Console::currentInstance = new ConsoleWindow(r, "\pRetro68 Console");
InitCursor();
r.top += 40;
InsetRect(&r, 5,5);
Console::currentInstance = new ConsoleWindow(r, "\pRetro68 Console");
InitCursor();
}
extern "C" ssize_t _consolewrite(int fd, const void *buf, size_t count)
{
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
Console::currentInstance->write((const char*)buf, count);
return count;
Console::currentInstance->write((const char*)buf, count);
return count;
}
extern "C" ssize_t _consoleread(int fd, void *buf, size_t count)
{
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
static std::string consoleBuf;
if(consoleBuf.size() == 0)
{
consoleBuf = Console::currentInstance->ReadLine();
static std::string consoleBuf;
if(consoleBuf.size() == 0)
{
consoleBuf = Console::currentInstance->ReadLine();
if(!Console::currentInstance->IsEOF())
consoleBuf += "\n";
}
if(count > consoleBuf.size())
count = consoleBuf.size();
memcpy(buf, consoleBuf.data(), count);
consoleBuf = consoleBuf.substr(count);
return count;
}
if(count > consoleBuf.size())
count = consoleBuf.size();
memcpy(buf, consoleBuf.data(), count);
consoleBuf = consoleBuf.substr(count);
return count;
}
+340 -340
View File
@@ -25,22 +25,22 @@ bool dataSections = true;
bool dataInText = false;
using stringid = int;
unordered_map<stringid,stringid> sectionMap;
unordered_map<stringid,string> stringDictionary;
unordered_map<stringid,stringid> sectionMap;
unordered_map<stringid,string> stringDictionary;
unordered_set<stringid> localLabels;
enum RecordType {
kPad = 0,
kFirst = 1,
kLast = 2,
kPad = 0,
kFirst = 1,
kLast = 2,
kComment = 3,
kDictionary = 4,
kModule = 5,
kEntryPoint = 6,
kSize = 7,
kContent = 8,
kReference = 9,
kComputedRef = 10,
kDictionary = 4,
kModule = 5,
kEntryPoint = 6,
kSize = 7,
kContent = 8,
kReference = 9,
kComputedRef = 10,
kFilename = 11
};
@@ -49,19 +49,19 @@ enum ModuleFlags {
kExtern = 0x08 // default local
};
enum ReferenceFlags { // flags field of kReference
k16BitPatch = 0x10, // default 32Bit
kFromData = 0x01, // default fromCode
kA5Relative = 0x80, // default absolute
enum ReferenceFlags { // flags field of kReference
k16BitPatch = 0x10, // default 32Bit
kFromData = 0x01, // default fromCode
kA5Relative = 0x80, // default absolute
kUnknownReferenceFlags = 0x6E // rather a lot, isn't it?
// The following flags are known to exist from DumpOBJ,
// but their value is unkown as I haven't actually seen them yet:
// k32BitOffsets (default k16BitOffsets)
kUnknownReferenceFlags = 0x6E // rather a lot, isn't it?
// The following flags are known to exist from DumpOBJ,
// but their value is unkown as I haven't actually seen them yet:
// k32BitOffsets (default k16BitOffsets)
};
enum ComputedReferenceFlags {
kDifference = 0x80
kDifference = 0x80
};
enum ContentFlags {
@@ -73,97 +73,97 @@ enum ContentFlags {
string encodeIdentifier(stringid id)
{
const string& s = stringDictionary[id];
std::ostringstream ss;
std::ostringstream ss;
if(localLabels.find(id) != localLabels.end())
ss << "L" << id << ".";
if(s.empty() || isdigit(s[0]))
ss << "__z";
ss << "__z";
for(char c : s)
{
if(c == '_' || isalnum(c))
ss << c;
else
{
ss << "__z" << (int) c << "_";
}
}
for(char c : s)
{
if(c == '_' || isalnum(c))
ss << c;
else
{
ss << "__z" << (int) c << "_";
}
}
return ss.str();
return ss.str();
}
struct Reloc
{
int size;
stringid name1 = -1;
stringid name2 = -1;
int size;
stringid name1 = -1;
stringid name2 = -1;
int write(std::ostream& out, uint8_t *p);
int write(std::ostream& out, uint8_t *p);
};
int Reloc::write(std::ostream& out, uint8_t *p)
{
if(size == 2)
{
out << "\t.short ";
int val = (int)p[0] * 256 + p[1];
if(size == 2)
{
out << "\t.short ";
int val = (int)p[0] * 256 + p[1];
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
if(name2 == -1)
out << "-.";
out << std::endl;
return 2;
}
else if(size == 4)
{
out << "\t.long ";
int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
if(name2 == -1)
out << "-.";
out << std::endl;
return 2;
}
else if(size == 4)
{
out << "\t.long ";
int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
out << std::endl;
return 4;
}
else
{
assert(false);
return 1;
}
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
out << std::endl;
return 4;
}
else
{
assert(false);
return 1;
}
}
struct Module
{
stringid name;
stringid segment;
stringid name;
stringid segment;
bool isData;
vector<uint8_t> bytes;
unordered_map<uint32_t, vector<stringid>> labels;
unordered_map<uint32_t, Reloc> relocs;
vector<uint8_t> bytes;
unordered_map<uint32_t, vector<stringid>> labels;
unordered_map<uint32_t, Reloc> relocs;
std::vector<std::weak_ptr<Module>> nearrefs;
std::vector<std::weak_ptr<Module>> nearrefs;
void write(std::ostream& out);
void write(std::ostream& out);
};
void Module::write(std::ostream& out)
{
string encodedName = encodeIdentifier(sectionMap[name]);
string encodedName = encodeIdentifier(sectionMap[name]);
if(isData && !dataInText)
if(isData && !dataInText)
{
if(dataSections)
out << "\t.section .data." << encodedName << ",\"aw\"\n";
@@ -175,41 +175,41 @@ void Module::write(std::ostream& out)
else
{
if(functionSections)
out << "\t.section .text." << encodedName << ",\"ax\",@progbits\n";
out << "\t.section .text." << encodedName << ",\"ax\",@progbits\n";
else
out << "\t.section .text,\"ax\",@progbits\n";
out << "\t.section .text,\"ax\",@progbits\n";
out << "\t.align 2,0\n";
}
for(uint32_t offset = 0; offset < bytes.size();)
{
auto labelP = labels.find(offset);
if(labelP != labels.end())
{
for(stringid rawLabel : labelP->second)
{
string label = encodeIdentifier(rawLabel);
if(localLabels.find(rawLabel) == localLabels.end())
for(uint32_t offset = 0; offset < bytes.size();)
{
auto labelP = labels.find(offset);
if(labelP != labels.end())
{
for(stringid rawLabel : labelP->second)
{
string label = encodeIdentifier(rawLabel);
if(localLabels.find(rawLabel) == localLabels.end())
out << "\t.globl " << label << "\n";
out << label << ":\n";
}
}
out << label << ":\n";
}
}
auto relocP = relocs.find(offset);
if(relocP != relocs.end())
{
offset += relocP->second.write(out, &bytes[offset]);
}
else
{
out << "\t.byte " << (int)bytes[offset] << "\n";
offset++;
}
}
auto relocP = relocs.find(offset);
if(relocP != relocs.end())
{
offset += relocP->second.write(out, &bytes[offset]);
}
else
{
out << "\t.byte " << (int)bytes[offset] << "\n";
offset++;
}
}
if(addMacsbugNames && !isData)
{
if(functionSections)
out << "\t.section .text." << encodedName << ".macsbug,\"ax\",@progbits\n";
out << "\t.section .text." << encodedName << ".macsbug,\"ax\",@progbits\n";
if(encodedName.size() < 32)
out << "\t.byte " << (encodedName.size() | 0x80) << "\n";
else
@@ -218,38 +218,38 @@ void Module::write(std::ostream& out)
out << "\t.ascii \"" << encodedName << "\"\n";
out << "\t.align 2,0\n\t.short 0\n";
}
out << "# ######\n\n";
out << "# ######\n\n";
}
void sortModules(std::vector<std::shared_ptr<Module>>& modules)
{
std::set<stringid> unemitted;
for(auto& m : modules)
unemitted.insert(m->name);
std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;
for(auto& m : modules)
for(auto& l : m->labels)
for(auto& str : l.second)
nameMap[str] = m;
for(auto& m : modules)
for(auto& r : m->relocs)
{
if(r.second.size != 2)
continue;
if(r.second.name2 == -1)
{
if(auto p = nameMap.find(r.second.name1); p != nameMap.end())
std::set<stringid> unemitted;
for(auto& m : modules)
unemitted.insert(m->name);
std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;
for(auto& m : modules)
for(auto& l : m->labels)
for(auto& str : l.second)
nameMap[str] = m;
for(auto& m : modules)
for(auto& r : m->relocs)
{
if(r.second.size != 2)
continue;
if(r.second.name2 == -1)
{
if(auto p = nameMap.find(r.second.name1); p != nameMap.end())
{
std::shared_ptr<Module> m1 = p->second;
m1->nearrefs.push_back(m);
m->nearrefs.push_back(m1);
}
}
else
{
}
else
{
auto p1 = nameMap.find(r.second.name1);
auto p2 = nameMap.find(r.second.name2);
@@ -260,60 +260,60 @@ void sortModules(std::vector<std::shared_ptr<Module>>& modules)
m1->nearrefs.push_back(m2);
m2->nearrefs.push_back(m1);
}
}
}
}
}
std::vector<std::shared_ptr<Module>> sorted;
sorted.reserve(modules.size());
auto p = sorted.begin();
while(!unemitted.empty())
{
while(p != sorted.end())
{
for(auto& m2weak : (*p)->nearrefs)
{
if(std::shared_ptr<Module> m2 = m2weak.lock())
{
auto unemittedP = unemitted.find(m2->name);
if(unemittedP != unemitted.end())
{
sorted.push_back(m2);
unemitted.erase(unemittedP);
}
}
}
++p;
}
std::vector<std::shared_ptr<Module>> sorted;
sorted.reserve(modules.size());
auto p = sorted.begin();
while(!unemitted.empty())
{
while(p != sorted.end())
{
for(auto& m2weak : (*p)->nearrefs)
{
if(std::shared_ptr<Module> m2 = m2weak.lock())
{
auto unemittedP = unemitted.find(m2->name);
if(unemittedP != unemitted.end())
{
sorted.push_back(m2);
unemitted.erase(unemittedP);
}
}
}
++p;
}
if(!unemitted.empty())
{
sorted.push_back(nameMap[*unemitted.begin()]);
unemitted.erase(unemitted.begin());
}
}
sorted.swap(modules);
}
sorted.swap(modules);
}
int main(int argc, char* argv[])
{
if(argc != 2)
{
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::ifstream in(argv[1]);
if(!in)
{
std::cerr << "Could not read imput file \"" << argv[1] << "\"\n";
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::shared_ptr<Module> module;
std::vector<std::shared_ptr<Module>> modules;
if(argc != 2)
{
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::ifstream in(argv[1]);
if(!in)
{
std::cerr << "Could not read imput file \"" << argv[1] << "\"\n";
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::shared_ptr<Module> module;
std::vector<std::shared_ptr<Module>> modules;
{
@@ -343,30 +343,30 @@ int main(int argc, char* argv[])
std::cout << "\t.text\n\t.align 2\n";
for(bool endOfObject = false; !endOfObject;) {
if(verbose)
std::cerr << std::hex << in.tellg() << ": ";
int recordType = byte(in);
if(!in)
{
std::cerr << "Unexpected End of File\n";
return 1;
}
for(bool endOfObject = false; !endOfObject;) {
if(verbose)
std::cerr << std::hex << in.tellg() << ": ";
int recordType = byte(in);
if(!in)
{
std::cerr << "Unexpected End of File\n";
return 1;
}
if(verbose)
std::cerr << "Record: " << recordType << std::endl;
if(verbose)
std::cerr << "Record: " << recordType << std::endl;
switch(recordType)
{
case kPad:
if(verbose)
std::cerr << "Pad\n";
break;
switch(recordType)
{
case kPad:
if(verbose)
std::cerr << "Pad\n";
break;
case kComment:
{
/*int flags =*/ byte(in);
int size = word(in);
/*int flags =*/ byte(in);
int size = word(in);
size -= 4;
if(verbose)
std::cerr << "Comment: ";
@@ -380,189 +380,189 @@ int main(int argc, char* argv[])
std::cerr << std::endl;
}
break;
case kDictionary:
{
/*int flags =*/ byte(in);
if(verbose)
std::cerr << "Dictionary\n";
int sz = word(in);
int stringId = word(in);
int end = (int)(in.tellg()) - 6 + sz;
while(in.tellg() < end)
{
int n = byte(in);
string s;
for(int i = 0; i < n; i++)
s += (char) byte(in);
if(verbose)
std::cerr << s << std::endl;
stringDictionary[stringId++] = s;
}
}
break;
case kModule:
{
int flags = byte(in);
stringid name = word(in);
sectionMap[name] = name;
stringid segment = word(in);
case kDictionary:
{
/*int flags =*/ byte(in);
if(verbose)
std::cerr << "Dictionary\n";
int sz = word(in);
int stringId = word(in);
int end = (int)(in.tellg()) - 6 + sz;
while(in.tellg() < end)
{
int n = byte(in);
string s;
for(int i = 0; i < n; i++)
s += (char) byte(in);
if(verbose)
std::cerr << s << std::endl;
stringDictionary[stringId++] = s;
}
}
break;
case kModule:
{
int flags = byte(in);
stringid name = word(in);
sectionMap[name] = name;
stringid segment = word(in);
if(verbose)
std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";
if(verbose)
std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";
if((flags & kExtern) == 0)
localLabels.insert(name);
module.reset(new Module());
module->name = name;
module.reset(new Module());
module->name = name;
module->segment = segment;
module->isData = (flags & kData) != 0;
module->labels[0].push_back(name);
modules.push_back(module);
}
break;
case kContent:
{
int flags = byte(in);
int sz = word(in) - 4;
uint32_t offset = 0;
if(flags & kContentOffset)
{
offset = longword(in);
sz -= 4;
}
module->labels[0].push_back(name);
modules.push_back(module);
}
break;
case kContent:
{
int flags = byte(in);
int sz = word(in) - 4;
uint32_t offset = 0;
if(flags & kContentOffset)
{
offset = longword(in);
sz -= 4;
}
int repeat = 1;
if(flags & kContentRepeat)
{
repeat = word(in);
sz -= 2;
}
if(verbose)
std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat << ")\n";
if(verbose)
std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat << ")\n";
assert(module.get());
if(module->bytes.size() < offset + sz * repeat)
module->bytes.resize(offset + sz * repeat);
in.read((char*) &module->bytes[offset], sz);
assert(module.get());
if(module->bytes.size() < offset + sz * repeat)
module->bytes.resize(offset + sz * repeat);
in.read((char*) &module->bytes[offset], sz);
while(--repeat > 0)
{
std::copy(module->bytes.begin() + offset, module->bytes.begin() + offset + sz,
module->bytes.begin() + offset + sz);
offset += sz;
}
}
break;
case kSize:
{
/*int flags =*/ byte(in);
long size = longword(in);
if(verbose)
std::cerr << "Size " << size << "\n";
assert(module.get());
module->bytes.resize(size);
}
break;
case kReference:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name = word(in);
}
break;
case kSize:
{
/*int flags =*/ byte(in);
long size = longword(in);
if(verbose)
std::cerr << "Size " << size << "\n";
assert(module.get());
module->bytes.resize(size);
}
break;
case kReference:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name = word(in);
if(verbose)
std::cerr << "Reference to " << stringDictionary[name] << " at\n";
Reloc reloc;
reloc.name1 = name;
if(verbose)
std::cerr << "Reference to " << stringDictionary[name] << " at\n";
Reloc reloc;
reloc.name1 = name;
if(flags & kUnknownReferenceFlags)
{
std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
if(flags & kA5Relative)
{
std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
flags &= ~kFromData; // FIXME: sticking data bits in the text section, not nice, but might sometimes work
if(flags & kUnknownReferenceFlags)
{
std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
if(flags & kA5Relative)
{
std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
flags &= ~kFromData; // FIXME: sticking data bits in the text section, not nice, but might sometimes work
reloc.size = (flags & k16BitPatch ? 2 : 4);
reloc.size = (flags & k16BitPatch ? 2 : 4);
assert(module);
assert(module);
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
case kEntryPoint:
{
int flags = byte(in);
stringid name = word(in);
long offset = longword(in);
if(verbose)
std::cerr << "EntryPoint " << stringDictionary[name] << " at offset " << offset << "\n";
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
case kEntryPoint:
{
int flags = byte(in);
stringid name = word(in);
long offset = longword(in);
if(verbose)
std::cerr << "EntryPoint " << stringDictionary[name] << " at offset " << offset << "\n";
if((flags & kExtern) == 0)
localLabels.insert(name);
assert(module);
module->labels[offset].push_back(name);
}
break;
case kComputedRef:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name1 = word(in);
stringid name2 = word(in);
assert(module);
module->labels[offset].push_back(name);
}
break;
case kComputedRef:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name1 = word(in);
stringid name2 = word(in);
Reloc reloc;
reloc.name1 = name1;
reloc.name2 = name2;
reloc.size = 2;
Reloc reloc;
reloc.name1 = name1;
reloc.name2 = name2;
reloc.size = 2;
assert(flags == 0x90);
assert(module);
assert(flags == 0x90);
assert(module);
if(auto p = sectionMap.find(name1); p != sectionMap.end())
sectionMap[module->name] = p->second;
if(verbose)
std::cerr << "ComputedReference to "
if(verbose)
std::cerr << "ComputedReference to "
<< stringDictionary[name1] << " - " << stringDictionary[name2] << " at\n";
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
case kFilename:
/* int flags = */ byte(in);
/* short nameref = */ word(in);
/* long date = */ longword(in);
break;
case kLast:
byte(in);
endOfObject = true;
break;
default:
std::cerr << "Unknown record (type " << recordType << ") at " << std::hex << in.tellg() << std::endl;
return 1;
}
}
if(shouldSortModules)
sortModules(modules);
for(auto& m : modules)
m->write(std::cout);
return 0;
case kLast:
byte(in);
endOfObject = true;
break;
default:
std::cerr << "Unknown record (type " << recordType << ") at " << std::hex << in.tellg() << std::endl;
return 1;
}
}
if(shouldSortModules)
sortModules(modules);
for(auto& m : modules)
m->write(std::cout);
return 0;
}
+6 -6
View File
@@ -18,12 +18,12 @@
find_package(Boost COMPONENTS REQUIRED)
add_executable(Elf2Mac
Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc
Reloc.h Reloc.cc
Symbol.h Symbol.cc
Symtab.h Symtab.cc
Section.h Section.cc
Object.h Object.cc)
Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc
Reloc.h Reloc.cc
Symbol.h Symbol.cc
Symtab.h Symtab.cc
Section.h Section.cc
Object.h Object.cc)
target_link_libraries(Elf2Mac ResourceFiles ELF)
target_include_directories(Elf2Mac PRIVATE ${CMAKE_INSTALL_PREFIX}/include)
+161 -161
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Elf2Mac.h"
@@ -45,179 +45,179 @@ string argvZero;
void RealLD(vector<string> args)
{
vector<const char*> argv;
string realLD = argvZero + ".real";
argv.push_back(realLD.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
vector<const char*> argv;
string realLD = argvZero + ".real";
argv.push_back(realLD.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
exit(-1);
}
else if(pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
exit(-1);
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
errx(EXIT_FAILURE, "ld process did not exit properly");
}
else
{
int exitcode = WEXITSTATUS(wstatus);
if(exitcode)
exit(exitcode);
}
}
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
exit(-1);
}
else if(pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
exit(-1);
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
errx(EXIT_FAILURE, "ld process did not exit properly");
}
else
{
int exitcode = WEXITSTATUS(wstatus);
if(exitcode)
exit(exitcode);
}
}
}
int main(int argc, char *argv[])
{
vector<string> args;
std::copy(argv + 1, argv+argc, std::back_inserter(args));
argvZero = argv[0];
vector<string> args;
std::copy(argv + 1, argv+argc, std::back_inserter(args));
argvZero = argv[0];
if(boost::algorithm::ends_with(argv[0], "ld"))
{
string outputFile = "a.out";
if(boost::algorithm::ends_with(argv[0], "ld"))
{
string outputFile = "a.out";
string entryPoint = "_start";
bool elf2mac = false;
bool flatoutput = false;
bool segments = true;
bool stripMacsbug = false;
bool elf2mac = false;
bool flatoutput = false;
bool segments = true;
bool stripMacsbug = false;
bool saveLdScript = false;
SegmentMap segmentMap;
SegmentMap segmentMap;
vector<string> args2;
for(auto p = args.begin(), e = args.end(); p != e; ++p)
{
if(*p == "-o")
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-o missing argument");
outputFile = *p;
}
else if(boost::algorithm::starts_with(*p, "-o"))
{
outputFile = (*p).substr(2);
}
else if(*p == "-elf2mac" || *p == "--elf2mac")
{
elf2mac = true;
}
vector<string> args2;
for(auto p = args.begin(), e = args.end(); p != e; ++p)
{
if(*p == "-o")
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-o missing argument");
outputFile = *p;
}
else if(boost::algorithm::starts_with(*p, "-o"))
{
outputFile = (*p).substr(2);
}
else if(*p == "-elf2mac" || *p == "--elf2mac")
{
elf2mac = true;
}
else if(*p == "-e")
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-e missing argument");
entryPoint = *p;
}
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-e missing argument");
entryPoint = *p;
}
else if(boost::algorithm::starts_with(*p, "-e"))
{
entryPoint = (*p).substr(2);
}
else if(*p == "--mac-flat")
{
elf2mac = true;
flatoutput = true;
segments = false;
}
else if(*p == "--mac-single")
{
elf2mac = true;
flatoutput = false;
segments = false;
}
else if(*p == "--mac-segments")
{
elf2mac = true;
if(flatoutput)
errx(EXIT_FAILURE, "--mac-segments can't be used with --mac-flat");
++p;
if(p == e)
errx(EXIT_FAILURE, "--mac-segments missing argument");
segmentMap = SegmentMap(*p);
}
else if(*p == "--mac-strip-macsbug")
{
stripMacsbug = true;
}
else if(*p == "--mac-flat")
{
elf2mac = true;
flatoutput = true;
segments = false;
}
else if(*p == "--mac-single")
{
elf2mac = true;
flatoutput = false;
segments = false;
}
else if(*p == "--mac-segments")
{
elf2mac = true;
if(flatoutput)
errx(EXIT_FAILURE, "--mac-segments can't be used with --mac-flat");
++p;
if(p == e)
errx(EXIT_FAILURE, "--mac-segments missing argument");
segmentMap = SegmentMap(*p);
}
else if(*p == "--mac-strip-macsbug")
{
stripMacsbug = true;
}
else if(*p == "--mac-keep-ldscript")
{
saveLdScript = true;
}
else
{
args2.push_back(*p);
}
}
else
{
args2.push_back(*p);
}
}
if(elf2mac)
{
char tmpfile[] = "/tmp/ldscriptXXXXXX";
int fd = mkstemp(tmpfile);
if(fd < 0)
errx(EXIT_FAILURE, "can't create temp file");
if(elf2mac)
{
char tmpfile[] = "/tmp/ldscriptXXXXXX";
int fd = mkstemp(tmpfile);
if(fd < 0)
errx(EXIT_FAILURE, "can't create temp file");
{
ofstream out(tmpfile);
if(segments)
{
segmentMap.CreateLdScript(out, entryPoint, stripMacsbug);
}
else
{
CreateFlatLdScript(out, entryPoint, stripMacsbug);
}
}
{
ofstream out(tmpfile);
if(segments)
{
segmentMap.CreateLdScript(out, entryPoint, stripMacsbug);
}
else
{
CreateFlatLdScript(out, entryPoint, stripMacsbug);
}
}
args2.push_back("-o");
args2.push_back(outputFile + ".gdb");
args2.push_back("-T");
args2.push_back(tmpfile);
RealLD(args2);
if(saveLdScript)
args2.push_back("-o");
args2.push_back(outputFile + ".gdb");
args2.push_back("-T");
args2.push_back(tmpfile);
RealLD(args2);
if(saveLdScript)
std::cerr << "Ld Script at: " << tmpfile << std::endl;
else
unlink(tmpfile);
Object theObject(outputFile + ".gdb");
if(flatoutput)
theObject.FlatCode(outputFile);
else if(segments)
theObject.MultiSegmentApp(outputFile, segmentMap);
else
theObject.SingleSegmentApp(outputFile);
}
else
{
RealLD(args);
}
return 0;
}
else
{
if(argc != 2)
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
Object theObject(argv[1]);
SegmentMap segmentMap;
theObject.MultiSegmentApp("out.bin", segmentMap);
}
return 0;
Object theObject(outputFile + ".gdb");
if(flatoutput)
theObject.FlatCode(outputFile);
else if(segments)
theObject.MultiSegmentApp(outputFile, segmentMap);
else
theObject.SingleSegmentApp(outputFile);
}
else
{
RealLD(args);
}
return 0;
}
else
{
if(argc != 2)
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
Object theObject(argv[1]);
SegmentMap segmentMap;
theObject.MultiSegmentApp("out.bin", segmentMap);
}
return 0;
}
+12 -12
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ELF2MAC_H
+103 -103
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Elf2Mac.h"
@@ -34,7 +34,7 @@ SECTIONS
)ld";
const char * textSection = R"ld(/* ld script for Elf2Mac */
.text : {
.text : {
_stext = . ;
PROVIDE(_rsrc_start = .);
*(.rsrcheader)
@@ -142,7 +142,7 @@ const char * scriptEnd = R"ld(
* Keep them for now, they are discarded by Elf2Mac. */
/DISCARD/ : { *(.note.GNU-stack) }
/* Stabs debugging sections. */
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
@@ -184,120 +184,120 @@ const char * scriptEnd = R"ld(
void CreateFlatLdScript(std::ostream& out, string entryPoint, bool stripMacsbug)
{
out << "_MULTISEG_APP = 0;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
out << boost::replace_all_copy<string>(textSection, "@entryPoint@", entryPoint) << scriptEnd;
out << "_MULTISEG_APP = 0;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
out << boost::replace_all_copy<string>(textSection, "@entryPoint@", entryPoint) << scriptEnd;
}
void SegmentInfo::WriteFilters(std::ostream &out, string section)
{
for(string filter : filters)
{
out << " " << filter << "(" << section << ")\n";
out << " " << filter << "(" << section << ".*)\n";
}
for(string filter : filters)
{
out << " " << filter << "(" << section << ")\n";
out << " " << filter << "(" << section << ".*)\n";
}
}
void SegmentInfo::WriteFiltersKeep(std::ostream &out, string section)
{
for(string filter : filters)
{
out << "\t\tKEEP(" << filter << "(" << section << "))\n";
out << "\t\tKEEP(" << filter << "(" << section << ".*))\n";
}
for(string filter : filters)
{
out << "\t\tKEEP(" << filter << "(" << section << "))\n";
out << "\t\tKEEP(" << filter << "(" << section << ".*))\n";
}
}
void SegmentInfo::CreateLdScript(std::ostream &out, string entryPoint)
{
out << "\t.code" << id << " : {\n";
out << "\t\tFILL(0x4E71);\n";
if(id == 1)
{
out << boost::replace_all_copy<string>(R"ld(
_stext = .;
FILL(0x4E71);
PROVIDE(_rsrc_start = .);
. = ALIGN (2);
_entry_trampoline = .;
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
LONG(0x61000002); /* bsr *+2 */
SHORT(0x0697); /* addi.l #_, (a7) */
LONG(@entryPoint@ - _entry_trampoline - 6);
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
SHORT(0x4e75); /* rts */
out << "\t.code" << id << " : {\n";
out << "\t\tFILL(0x4E71);\n";
if(id == 1)
{
out << boost::replace_all_copy<string>(R"ld(
_stext = .;
FILL(0x4E71);
PROVIDE(_rsrc_start = .);
. = ALIGN (2);
_entry_trampoline = .;
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
LONG(0x61000002); /* bsr *+2 */
SHORT(0x0697); /* addi.l #_, (a7) */
LONG(@entryPoint@ - _entry_trampoline - 6);
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
SHORT(0x4e75); /* rts */
FILL(0);
*(.relocvars)
FILL(0x4E71);
FILL(0);
*(.relocvars)
FILL(0x4E71);
)ld", "@entryPoint@", entryPoint);
}
WriteFilters(out, ".text");
}
WriteFilters(out, ".text");
if(id == 2)
{
out << "\t\t*(.gnu.linkonce.t*)\n";
}
if(id == 1)
{
out << R"ld(
. = ALIGN (4) ;
__init_section = .;
KEEP (*(.init))
__init_section_end = .;
__fini_section = .;
KEEP (*(.fini))
__fini_section_end = .;
if(id == 2)
{
out << "\t\t*(.gnu.linkonce.t*)\n";
}
if(id == 1)
{
out << R"ld(
. = ALIGN (4) ;
__init_section = .;
KEEP (*(.init))
__init_section_end = .;
__fini_section = .;
KEEP (*(.fini))
__fini_section_end = .;
)ld";
}
}
out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason.
if(id == 1)
out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n";
else
out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n";
WriteFiltersKeep(out, ".eh_frame");
out << "\t\tLONG(0);\n";
WriteFiltersKeep(out, ".gcc_except_table");
out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason.
if(id == 1)
out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n";
else
out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n";
WriteFiltersKeep(out, ".eh_frame");
out << "\t\tLONG(0);\n";
WriteFiltersKeep(out, ".gcc_except_table");
if(id == 1)
{
out << R"ld(
. = ALIGN(0x4) ;
_etext = . ;
if(id == 1)
{
out << R"ld(
. = ALIGN(0x4) ;
_etext = . ;
)ld";
}
else
{
out << boost::replace_all_copy<string>(R"ld(
. = ALIGN(0x4);
FILL(0);
. += 32;
LONG(__EH_FRAME_BEGIN__@N@ - .);
}
else
{
out << boost::replace_all_copy<string>(R"ld(
. = ALIGN(0x4);
FILL(0);
. += 32;
LONG(__EH_FRAME_BEGIN__@N@ - .);
)ld", "@N@", boost::lexical_cast<string>(id));
}
}
out << "\t}\n";
out << "\t}\n";
}
void SegmentMap::CreateLdScript(std::ostream &out, string entryPoint, bool stripMacsbug)
{
out << "_MULTISEG_APP = 1;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
for(SegmentInfo& seg: segments)
{
seg.CreateLdScript(out, entryPoint);
}
out << "_MULTISEG_APP = 1;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
for(SegmentInfo& seg: segments)
{
seg.CreateLdScript(out, entryPoint);
}
out << scriptEnd;
out << scriptEnd;
}
+260 -260
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Object.h"
@@ -52,173 +52,173 @@ Object::~Object()
Object::Object(string input)
{
if(elf_version ( EV_CURRENT ) == EV_NONE)
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
if(elf_version ( EV_CURRENT ) == EV_NONE)
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
int fd = open(input.c_str(), O_RDONLY, 0);
elf = elf_begin(fd, ELF_C_READ, NULL);
int fd = open(input.c_str(), O_RDONLY, 0);
elf = elf_begin(fd, ELF_C_READ, NULL);
elf_getshdrstrndx(elf, &sectionHeaderStringTableIdx);
elf_getshdrstrndx(elf, &sectionHeaderStringTableIdx);
GElf_Ehdr ehdr;
gelf_getehdr(elf, &ehdr);
GElf_Ehdr ehdr;
gelf_getehdr(elf, &ehdr);
int idx;
int idx;
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
if(shdr.sh_type == SHT_STRTAB)
{
if(name == ".strtab")
mainStringTableIdx = idx;
}
}
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
if(shdr.sh_type == SHT_STRTAB)
{
if(name == ".strtab")
mainStringTableIdx = idx;
}
}
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
//std::cout << "section #" << idx << ": " << name << std::endl;
//std::cout << " =" << shdr.sh_addr << " + " << shdr.sh_size << std::endl;
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
//std::cout << "section #" << idx << ": " << name << std::endl;
//std::cout << " =" << shdr.sh_addr << " + " << shdr.sh_size << std::endl;
if(shdr.sh_type == SHT_SYMTAB
&& !symtab)
{
symtab.reset(new Symtab(*this, scn));
}
if(shdr.sh_type == SHT_RELA)
{
if(boost::algorithm::starts_with(name,".rela."))
{
string progbitsName = name.substr(5);
assert(sections.find(progbitsName) != sections.end());
sections[progbitsName]->SetRela(scn);
}
}
if(shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC))
{
SectionKind kind = SectionKind::code;
if(shdr.sh_type == SHT_SYMTAB
&& !symtab)
{
symtab.reset(new Symtab(*this, scn));
}
if(shdr.sh_type == SHT_RELA)
{
if(boost::algorithm::starts_with(name,".rela."))
{
string progbitsName = name.substr(5);
assert(sections.find(progbitsName) != sections.end());
sections[progbitsName]->SetRela(scn);
}
}
if(shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC))
{
SectionKind kind = SectionKind::code;
if(name == ".data")
kind = SectionKind::data;
if(name == ".strippedmacsbugnames")
kind = SectionKind::undefined;
if(name == ".data")
kind = SectionKind::data;
if(name == ".strippedmacsbugnames")
kind = SectionKind::undefined;
auto section = make_shared<Section>(*this, name, idx, kind, scn);
auto section = make_shared<Section>(*this, name, idx, kind, scn);
sections[name] = sectionsByElfIndex[idx] = section;
if(kind == SectionKind::data)
dataSection = section;
else if(kind == SectionKind::code)
codeSections.push_back(section);
}
if(shdr.sh_type == SHT_NOBITS)
{
bssSection = sections[name] = sectionsByElfIndex[idx] =
make_shared<Section>(*this, name, idx, SectionKind::bss, scn);
}
}
sections[name] = sectionsByElfIndex[idx] = section;
if(kind == SectionKind::data)
dataSection = section;
else if(kind == SectionKind::code)
codeSections.push_back(section);
}
if(shdr.sh_type == SHT_NOBITS)
{
bssSection = sections[name] = sectionsByElfIndex[idx] =
make_shared<Section>(*this, name, idx, SectionKind::bss, scn);
}
}
std::sort(codeSections.begin(), codeSections.end(),
[](shared_ptr<Section> a, shared_ptr<Section> b) { return a->name < b->name; });
std::sort(codeSections.begin(), codeSections.end(),
[](shared_ptr<Section> a, shared_ptr<Section> b) { return a->name < b->name; });
}
void Object::FlatCode(std::ostream& out)
{
for(auto sec : codeSections)
{
sec->FixRelocs(true);
out << sec->GetData();
}
dataSection->FixRelocs(true);
out << dataSection->GetData();
for(auto sec : codeSections)
{
sec->FixRelocs(true);
out << sec->GetData();
}
dataSection->FixRelocs(true);
out << dataSection->GetData();
std::vector<RuntimeReloc> relocs;
for(auto sec : codeSections)
{
auto tmp = sec->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
{
auto tmp = dataSection->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
out << SerializeRelocs(relocs);
std::vector<RuntimeReloc> relocs;
for(auto sec : codeSections)
{
auto tmp = sec->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
{
auto tmp = dataSection->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
out << SerializeRelocs(relocs);
}
void Object::FlatCode(string fn)
{
ofstream out(fn);
FlatCode(out);
ofstream out(fn);
FlatCode(out);
}
std::string fromhex(std::string hex)
{
std::string bin;
int nibble;
bool haveNibble = false;
for(std::string::iterator p = hex.begin(); p != hex.end(); ++p)
{
if(std::isspace(*p))
continue;
assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f'));
int digit;
if(isdigit(*p))
digit = *p - '0';
else
digit = tolower(*p) - 'a' + 0xA;
std::string bin;
int nibble;
bool haveNibble = false;
for(std::string::iterator p = hex.begin(); p != hex.end(); ++p)
{
if(std::isspace(*p))
continue;
assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f'));
int digit;
if(isdigit(*p))
digit = *p - '0';
else
digit = tolower(*p) - 'a' + 0xA;
if(haveNibble)
{
bin += (char) ((nibble << 4) | digit);
haveNibble = false;
}
else
{
nibble = digit;
haveNibble = true;
}
}
return bin;
if(haveNibble)
{
bin += (char) ((nibble << 4) | digit);
haveNibble = false;
}
else
{
nibble = digit;
haveNibble = true;
}
}
return bin;
}
void Object::SingleSegmentApp(string output)
{
ResourceFile file(output);
Resources& rsrc = file.resources;
ResourceFile file(output);
Resources& rsrc = file.resources;
rsrc.addResource(Resource(ResType("CODE"), 0,
fromhex(
"00000028 00000000 00000008 00000020"
"0000 3F3C 0001 A9F0"
)
));
rsrc.addResource(Resource(ResType("CODE"), 0,
fromhex(
"00000028 00000000 00000008 00000020"
"0000 3F3C 0001 A9F0"
)
));
{
std::ostringstream code1;
word(code1, 0);
word(code1, 1);
FlatCode(code1);
{
std::ostringstream code1;
word(code1, 0);
word(code1, 1);
FlatCode(code1);
rsrc.addResource(Resource(ResType("CODE"), 1,
code1.str()));
}
rsrc.addResource(Resource(ResType("CODE"), 1,
code1.str()));
}
file.creator = ResType("????");
file.type = ResType("APPL");
file.creator = ResType("????");
file.type = ResType("APPL");
file.write();
file.write();
}
@@ -227,70 +227,70 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
{
bool noisy = false;
ResourceFile file(output);
Resources& rsrc = file.resources;
ResourceFile file(output);
Resources& rsrc = file.resources;
for(auto namedSec : sections)
{
namedSec.second->ScanRelocs();
}
for(auto namedSec : sections)
{
namedSec.second->ScanRelocs();
}
int jtEntryCount = 0;
unordered_map<int, vector<Symbol*>> jtEntries;
for(Symbol& sym : symtab->symbols)
{
if(sym.valid)
{
if(sym.referencedExternally && sym.sectionKind == SectionKind::code)
{
sym.needsJT = true;
sym.jtIndex = -1;
sym.section->jtEntries.push_back(&sym);
++jtEntryCount;
}
}
}
int jtEntryCount = 0;
unordered_map<int, vector<Symbol*>> jtEntries;
for(Symbol& sym : symtab->symbols)
{
if(sym.valid)
{
if(sym.referencedExternally && sym.sectionKind == SectionKind::code)
{
sym.needsJT = true;
sym.jtIndex = -1;
sym.section->jtEntries.push_back(&sym);
++jtEntryCount;
}
}
}
uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size;
uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size;
{
std::ostringstream code0;
longword(code0, 0x20 + 8 * (jtEntryCount+2));
longword(code0, data_and_bss_size);
longword(code0, 8 * (jtEntryCount+2));
longword(code0, 0x20);
{
std::ostringstream code0;
longword(code0, 0x20 + 8 * (jtEntryCount+2));
longword(code0, data_and_bss_size);
longword(code0, 8 * (jtEntryCount+2));
longword(code0, 0x20);
code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint
code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here
code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint
code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here
int jtIndex = 2;
int id = 1;
for(auto sec : codeSections)
{
sec->codeID = id;
int jtIndex = 2;
int id = 1;
for(auto sec : codeSections)
{
sec->codeID = id;
sec->firstJTEntryIndex = jtIndex;
sec->firstJTEntryIndex = jtIndex;
GElf_Shdr &shdr = sec->shdr;
GElf_Shdr &shdr = sec->shdr;
for(Symbol* jtEntry : sec->jtEntries)
{
word(code0, id);
word(code0, 0xA9F0);
uint32_t offset = jtEntry->st_value - shdr.sh_addr;
if(id == 1)
offset += 4;
else
offset += 40;
longword(code0, offset);
for(Symbol* jtEntry : sec->jtEntries)
{
word(code0, id);
word(code0, 0xA9F0);
uint32_t offset = jtEntry->st_value - shdr.sh_addr;
if(id == 1)
offset += 4;
else
offset += 40;
longword(code0, offset);
jtEntry->jtIndex = jtIndex++;
jtEntry->jtIndex = jtIndex++;
//std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl;
}
//std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl;
}
id++;
}
id++;
}
if(noisy)
{
@@ -302,69 +302,69 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
std::cout << ".bss: " << bssSection->shdr.sh_size << " bytes at A5-"
<< std::hex << bssSection->shdr.sh_size << std::dec << "\n";
}
rsrc.addResource(Resource(ResType("CODE"), 0, code0.str()));
}
rsrc.addResource(Resource(ResType("CODE"), 0, code0.str()));
}
for(auto sec : codeSections)
{
int id = sec->codeID;
if(id == 1)
sec->outputBase = 4; // standard 'CODE' header
else
sec->outputBase = 40; // far-model 'CODE' header
for(auto sec : codeSections)
{
int id = sec->codeID;
if(id == 1)
sec->outputBase = 4; // standard 'CODE' header
else
sec->outputBase = 40; // far-model 'CODE' header
string exceptionInfoMarker = "__EH_FRAME_BEGIN__";
if(id != 1)
exceptionInfoMarker += boost::lexical_cast<string>(id);
int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker);
if(exceptionInfoSym != -1)
{
Symbol& s = symtab->GetSym(exceptionInfoSym);
sec->exceptionInfoStart = s.st_value;
string exceptionInfoMarker = "__EH_FRAME_BEGIN__";
if(id != 1)
exceptionInfoMarker += boost::lexical_cast<string>(id);
int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker);
if(exceptionInfoSym != -1)
{
Symbol& s = symtab->GetSym(exceptionInfoSym);
sec->exceptionInfoStart = s.st_value;
int codeSize = sec->shdr.sh_size;
int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart;
double percent = 100.0 * exceptionSize / codeSize;
int codeSize = sec->shdr.sh_size;
int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart;
double percent = 100.0 * exceptionSize / codeSize;
if(noisy)
if(noisy)
std::cout << "CODE " << id << " has " << exceptionSize << " bytes of exception info (" << percent << "%)\n";
}
else if(noisy)
std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl;
}
dataSection->outputBase = -data_and_bss_size;
bssSection->outputBase = -bssSection->shdr.sh_size;
}
else if(noisy)
std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl;
}
dataSection->outputBase = -data_and_bss_size;
bssSection->outputBase = -bssSection->shdr.sh_size;
for(auto namedSec : sections)
{
namedSec.second->FixRelocs(false);
}
for(auto namedSec : sections)
{
namedSec.second->FixRelocs(false);
}
for(auto sec : codeSections)
{
int id = sec->codeID;
std::ostringstream code;
if(id == 1)
{
word(code, 0);
word(code, 1);
}
else
{
word(code, 0xFFFF);
word(code, 0);
longword(code, 0);
longword(code, 0);
longword(code, 8 * sec->firstJTEntryIndex );
longword(code, sec->jtEntries.size());
longword(code, 0); // reloc info for A5
longword(code, 0); // assumed address for A5
longword(code, 0); // reloc info for code
longword(code, 0); // assumed address for start of code resource
longword(code, 0);
}
code << sec->GetData();
for(auto sec : codeSections)
{
int id = sec->codeID;
std::ostringstream code;
if(id == 1)
{
word(code, 0);
word(code, 1);
}
else
{
word(code, 0xFFFF);
word(code, 0);
longword(code, 0);
longword(code, 0);
longword(code, 8 * sec->firstJTEntryIndex );
longword(code, sec->jtEntries.size());
longword(code, 0); // reloc info for A5
longword(code, 0); // assumed address for A5
longword(code, 0); // reloc info for code
longword(code, 0); // assumed address for start of code resource
longword(code, 0);
}
code << sec->GetData();
if(noisy)
{
@@ -377,24 +377,24 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
}
}
string segmentName = segmentMap.GetSegmentName(id);
string segmentName = segmentMap.GetSegmentName(id);
rsrc.addResource(Resource(ResType("CODE"), id,
code.str(),
segmentName));
rsrc.addResource(Resource(ResType("CODE"), id,
code.str(),
segmentName));
rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true))));
}
rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true))));
}
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true))));
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true))));
if(noisy)
std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n";
std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n";
file.creator = ResType("????");
file.type = ResType("APPL");
file.creator = ResType("????");
file.type = ResType("APPL");
file.write();
file.write();
}
+26 -26
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OBJECT_H
@@ -36,25 +36,25 @@ class SegmentMap;
class Object
{
public:
Elf *elf;
std::unique_ptr<Symtab> symtab;
std::unordered_map<std::string, std::shared_ptr<Section>> sections;
std::unordered_map<int, std::shared_ptr<Section>> sectionsByElfIndex;
Elf *elf;
std::unique_ptr<Symtab> symtab;
std::unordered_map<std::string, std::shared_ptr<Section>> sections;
std::unordered_map<int, std::shared_ptr<Section>> sectionsByElfIndex;
std::vector<std::shared_ptr<Section>> codeSections;
std::shared_ptr<Section> dataSection, bssSection;
size_t sectionHeaderStringTableIdx;
size_t mainStringTableIdx;
std::vector<std::shared_ptr<Section>> codeSections;
std::shared_ptr<Section> dataSection, bssSection;
size_t sectionHeaderStringTableIdx;
size_t mainStringTableIdx;
Object(std::string input);
~Object();
Object(std::string input);
~Object();
void FlatCode(std::ostream& out);
void FlatCode(std::string fn);
void FlatCode(std::ostream& out);
void FlatCode(std::string fn);
void SingleSegmentApp(std::string output);
void MultiSegmentApp(std::string output, SegmentMap &segmentMap);
void SingleSegmentApp(std::string output);
void MultiSegmentApp(std::string output, SegmentMap &segmentMap);
};
+36 -36
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Reloc.h"
@@ -32,38 +32,38 @@ Reloc::Reloc(const GElf_Rela &rela)
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs)
{
std::ostringstream out;
for(const auto& r : relocs)
{
longword(out, r.offset | ((int)r.base << 24));
}
longword(out, -1);
return out.str();
std::ostringstream out;
for(const auto& r : relocs)
{
longword(out, r.offset | ((int)r.base << 24));
}
longword(out, -1);
return out.str();
}
std::string SerializeRelocs(std::vector<RuntimeReloc> relocs)
{
std::ostringstream out;
uint32_t offset = -1;
std::ostringstream out;
uint32_t offset = -1;
for(const auto& r : relocs)
{
uint32_t delta = r.offset - offset;
offset = r.offset;
for(const auto& r : relocs)
{
uint32_t delta = r.offset - offset;
offset = r.offset;
uint32_t base = (uint32_t) r.base;
uint32_t base = (uint32_t) r.base;
uint32_t encoded = (delta << 2) | base;
uint32_t encoded = (delta << 2) | base;
while(encoded >= 128)
{
byte(out, (encoded & 0x7F) | 0x80);
encoded >>= 7;
}
byte(out, encoded);
}
while(encoded >= 128)
{
byte(out, (encoded & 0x7F) | 0x80);
encoded >>= 7;
}
byte(out, encoded);
}
byte(out, 0);
byte(out, 0);
return out.str();
return out.str();
}
+24 -24
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RELOC_H
@@ -28,30 +28,30 @@
enum class RelocBase
{
code = 0,
data,
bss,
jumptable,
code1
code = 0,
data,
bss,
jumptable,
code1
};
class Reloc : public GElf_Rela
{
public:
RelocBase relocBase;
RelocBase relocBase;
Reloc();
Reloc(const GElf_Rela& rela);
Reloc();
Reloc(const GElf_Rela& rela);
};
class RuntimeReloc
{
public:
RelocBase base;
uint32_t offset;
RelocBase base;
uint32_t offset;
RuntimeReloc() : base(RelocBase::code), offset(0) {}
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
RuntimeReloc() : base(RelocBase::code), offset(0) {}
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
};
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs);
+159 -159
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Section.h"
@@ -43,198 +43,198 @@ Section::Section(Object& theObject, string name, int idx, SectionKind kind, Elf_
exceptionInfoStart(0),
codeID(-1), firstJTEntryIndex(0)
{
data = elf_getdata(elfsec, NULL);
gelf_getshdr(elfsec, &shdr);
outputBase = shdr.sh_addr;
data = elf_getdata(elfsec, NULL);
gelf_getshdr(elfsec, &shdr);
outputBase = shdr.sh_addr;
}
void Section::SetRela(Elf_Scn *scn)
{
relasec = scn;
GElf_Shdr rshdr;
gelf_getshdr(relasec, &rshdr);
relasec = scn;
GElf_Shdr rshdr;
gelf_getshdr(relasec, &rshdr);
int nRela = rshdr.sh_size / rshdr.sh_entsize;
Elf_Data *data = elf_getdata(relasec, NULL);
for(int i = 0; i < nRela; i++)
{
GElf_Rela rela;
gelf_getrela(data, i, &rela);
int nRela = rshdr.sh_size / rshdr.sh_entsize;
Elf_Data *data = elf_getdata(relasec, NULL);
for(int i = 0; i < nRela; i++)
{
GElf_Rela rela;
gelf_getrela(data, i, &rela);
if(rela.r_offset < shdr.sh_addr || rela.r_offset > shdr.sh_addr + shdr.sh_size - 4)
{
// FIXME: There are sometimes relocations beyond the end of the sections
// in LD output for some reason. That's bad. Let's ignore it.
continue;
}
relocs.push_back(rela);
}
if(rela.r_offset < shdr.sh_addr || rela.r_offset > shdr.sh_addr + shdr.sh_size - 4)
{
// FIXME: There are sometimes relocations beyond the end of the sections
// in LD output for some reason. That's bad. Let's ignore it.
continue;
}
relocs.push_back(rela);
}
std::sort(relocs.begin(), relocs.end(),
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
std::sort(relocs.begin(), relocs.end(),
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
}
uint32_t Section::GetSize()
{
return data->d_size;
return data->d_size;
}
string Section::GetData()
{
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
}
std::vector<RuntimeReloc> Section::GetRelocations(bool useOffsets)
{
std::vector<RuntimeReloc> outRelocs;
std::vector<RuntimeReloc> outRelocs;
for(auto& rela : relocs)
{
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
for(auto& rela : relocs)
{
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol& sym = theObject.symtab->GetSym(symidx);
Symbol& sym = theObject.symtab->GetSym(symidx);
if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue;
if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue;
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
{
assert(sym.sectionKind != SectionKind::undefined);
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
{
assert(sym.sectionKind != SectionKind::undefined);
uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
//longword(out, offset | ((int)rela.relocBase << 24));
outRelocs.emplace_back(rela.relocBase, offset);
}
}
//longword(out, offset | ((int)rela.relocBase << 24));
outRelocs.emplace_back(rela.relocBase, offset);
}
}
return outRelocs;
return outRelocs;
}
void Section::ScanRelocs()
{
for(Reloc& rela : relocs)
{
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
for(Reloc& rela : relocs)
{
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol *sym = &theObject.symtab->GetSym(symidx);
Symbol *sym = &theObject.symtab->GetSym(symidx);
if(sym->st_shndx == SHN_UNDEF)
continue;
if(sym->st_shndx == SHN_UNDEF)
continue;
if(rela.r_addend != 0)
{
int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
if(symidx2 != -1)
{
sym = &theObject.symtab->GetSym(symidx2);
rela.r_addend = 0;
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
if(rela.r_addend != 0)
{
int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
if(symidx2 != -1)
{
sym = &theObject.symtab->GetSym(symidx2);
rela.r_addend = 0;
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
}
}
}
}
if(sym->st_shndx != idx)
sym->referencedExternally = true;
}
if(sym->st_shndx != idx)
sym->referencedExternally = true;
}
}
void Section::FixRelocs(bool allowDirectCodeRefs)
{
for(Reloc& rela : relocs)
{
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
continue;
for(Reloc& rela : relocs)
{
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
continue;
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol& sym = theObject.symtab->GetSym(symidx);
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol& sym = theObject.symtab->GetSym(symidx);
if(sym.sectionKind == SectionKind::undefined)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue;
RelocBase relocBase;
switch(sym.sectionKind)
{
case SectionKind::code:
relocBase = RelocBase::code;
if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0"))
{
if(rela.r_addend == 0)
{
relocBase = RelocBase::jumptable;
}
else
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
}
assert(sym.section.get() == this);
}
}
else if(!allowDirectCodeRefs)
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl;
std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl;
RelocBase relocBase;
switch(sym.sectionKind)
{
case SectionKind::code:
relocBase = RelocBase::code;
if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0"))
{
if(rela.r_addend == 0)
{
relocBase = RelocBase::jumptable;
}
else
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
}
assert(sym.section.get() == this);
}
}
else if(!allowDirectCodeRefs)
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl;
std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl;
}
assert(sym.section.get() == this);
}
break;
case SectionKind::data:
relocBase = RelocBase::data;
break;
case SectionKind::bss:
relocBase = RelocBase::bss;
break;
case SectionKind::undefined:
assert(false);
break;
}
rela.relocBase = relocBase;
}
assert(sym.section.get() == this);
}
break;
case SectionKind::data:
relocBase = RelocBase::data;
break;
case SectionKind::bss:
relocBase = RelocBase::bss;
break;
case SectionKind::undefined:
assert(false);
break;
}
rela.relocBase = relocBase;
uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr);
uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr);
if(relocBase == RelocBase::jumptable)
{
uint32_t dst = 0x20 + sym.jtIndex * 8 + 2;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
else
{
uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3];
uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
}
if(relocBase == RelocBase::jumptable)
{
uint32_t dst = 0x20 + sym.jtIndex * 8 + 2;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
else
{
uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3];
uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
}
}
+37 -37
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SECTION_H
@@ -33,41 +33,41 @@ class RuntimeReloc;
enum class SectionKind
{
undefined = -1,
code = 0,
data,
bss
undefined = -1,
code = 0,
data,
bss
};
class Section
{
public:
Object& theObject;
std::string name;
int idx;
SectionKind kind;
Elf_Scn *elfsec, *relasec;
Elf_Data *data;
GElf_Shdr shdr;
uint32_t outputBase;
uint32_t exceptionInfoStart;
Object& theObject;
std::string name;
int idx;
SectionKind kind;
Elf_Scn *elfsec, *relasec;
Elf_Data *data;
GElf_Shdr shdr;
uint32_t outputBase;
uint32_t exceptionInfoStart;
int codeID;
int codeID;
std::vector<Reloc> relocs;
std::vector<Symbol*> jtEntries;
int firstJTEntryIndex;
std::vector<Reloc> relocs;
std::vector<Symbol*> jtEntries;
int firstJTEntryIndex;
Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec);
~Section();
void SetRela(Elf_Scn *scn);
Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec);
~Section();
void SetRela(Elf_Scn *scn);
uint32_t GetSize();
std::string GetData();
std::vector<RuntimeReloc> GetRelocations(bool useOffsets);
uint32_t GetSize();
std::string GetData();
std::vector<RuntimeReloc> GetRelocations(bool useOffsets);
void ScanRelocs();
void FixRelocs(bool allowDirectCodeRefs);
void ScanRelocs();
void FixRelocs(bool allowDirectCodeRefs);
};
+88 -88
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SegmentMap.h"
@@ -29,98 +29,98 @@ SegmentInfo::SegmentInfo()
SegmentMap::SegmentMap()
{
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
"*/libInterface.a:*",
"*/libgcc.a:*",
"*/libc.a:*"
);
segments.emplace_back(5, "libstdc++ locale",
"*/libstdc++.a:locale.o",
"*/libstdc++.a:locale_faces.o",
"*/libstdc++.a:locale_init.o");
segments.emplace_back(7, "libstdc++ locale-inst",
"*/libstdc++.a:locale-inst.o");
segments.emplace_back(8, "libstdc++ wlocale-inst",
"*/libstdc++.a:wlocale-inst.o");
segments.emplace_back(6, "libstdc++ cp-demangle",
"*/libstdc++.a:cp-demangle.o");
segments.emplace_back(3, "libstdc++",
"*/libstdc++.a:*");
segments.emplace_back(4, "RetroConsole",
"*/libRetroConsole.a:*");
"*/libgcc.a:*",
"*/libc.a:*"
);
segments.emplace_back(5, "libstdc++ locale",
"*/libstdc++.a:locale.o",
"*/libstdc++.a:locale_faces.o",
"*/libstdc++.a:locale_init.o");
segments.emplace_back(7, "libstdc++ locale-inst",
"*/libstdc++.a:locale-inst.o");
segments.emplace_back(8, "libstdc++ wlocale-inst",
"*/libstdc++.a:wlocale-inst.o");
segments.emplace_back(6, "libstdc++ cp-demangle",
"*/libstdc++.a:cp-demangle.o");
segments.emplace_back(3, "libstdc++",
"*/libstdc++.a:*");
segments.emplace_back(4, "RetroConsole",
"*/libRetroConsole.a:*");
segments.emplace_back(2, "Main",
"*");
segments.emplace_back(2, "Main",
"*");
}
SegmentMap::SegmentMap(std::string filename)
{
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
"*/libInterface.a:*",
"*/libgcc.a:*",
"*/libc.a:*"
);
"*/libgcc.a:*",
"*/libc.a:*"
);
std::ifstream in(filename);
int id = -1;
int nextID = 3;
while(in)
{
std::string s;
in >> std::ws;
std::getline(in, s);
//std::cout << "segs: " << s << std::endl;
if(!in)
break;
std::ifstream in(filename);
int id = -1;
int nextID = 3;
while(in)
{
std::string s;
in >> std::ws;
std::getline(in, s);
//std::cout << "segs: " << s << std::endl;
if(!in)
break;
std::string upper;
std::transform(s.begin(), s.end(), std::back_inserter(upper), [](char c) { return std::toupper(c); });
std::string upper;
std::transform(s.begin(), s.end(), std::back_inserter(upper), [](char c) { return std::toupper(c); });
if(s[0] == '#')
continue;
else if(upper == "SEGMENT" || (upper.substr(0,7) == "SEGMENT" && std::isspace(upper[7])))
{
std::string name;
if(s[0] == '#')
continue;
else if(upper == "SEGMENT" || (upper.substr(0,7) == "SEGMENT" && std::isspace(upper[7])))
{
std::string name;
auto p = s.begin() + 7;
while(p != s.end() && std::isspace(*p))
++p;
name = std::string(p, s.end());
id = nextID++;
auto p = s.begin() + 7;
while(p != s.end() && std::isspace(*p))
++p;
name = std::string(p, s.end());
id = nextID++;
segments.emplace_back(id, name);
}
else
{
if(id < 0)
{
throw std::runtime_error("missing SEGMENT directive.\n");
}
segments.emplace_back(id, name);
}
else
{
if(id < 0)
{
throw std::runtime_error("missing SEGMENT directive.\n");
}
segments.back().filters.push_back(s);
}
}
segments.back().filters.push_back(s);
}
}
segments.emplace_back(2, "Main",
"*");
segments.emplace_back(2, "Main",
"*");
}
std::string SegmentMap::GetSegmentName(int id)
{
for(auto& seg : segments)
{
if(seg.id == id)
return seg.name;
}
return "";
for(auto& seg : segments)
{
if(seg.id == id)
return seg.name;
}
return "";
}
+29 -29
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SEGMENTMAP_H
@@ -26,31 +26,31 @@
class SegmentInfo
{
public:
int id;
std::string name;
std::vector<std::string> filters;
SegmentInfo();
int id;
std::string name;
std::vector<std::string> filters;
SegmentInfo();
template<typename... Args>
SegmentInfo(int id, std::string name, Args... args)
: id(id), name(name), filters { args... }
{
}
template<typename... Args>
SegmentInfo(int id, std::string name, Args... args)
: id(id), name(name), filters { args... }
{
}
void WriteFilters(std::ostream& out, std::string section);
void WriteFiltersKeep(std::ostream& out, std::string section);
void CreateLdScript(std::ostream& out, std::string entryPoint);
void WriteFilters(std::ostream& out, std::string section);
void WriteFiltersKeep(std::ostream& out, std::string section);
void CreateLdScript(std::ostream& out, std::string entryPoint);
};
class SegmentMap
{
std::vector<SegmentInfo> segments;
std::vector<SegmentInfo> segments;
public:
SegmentMap();
SegmentMap(std::string filename);
SegmentMap();
SegmentMap(std::string filename);
void CreateLdScript(std::ostream& out, std::string entryPoint, bool stripMacsbug);
std::string GetSegmentName(int id);
void CreateLdScript(std::ostream& out, std::string entryPoint, bool stripMacsbug);
std::string GetSegmentName(int id);
};
#endif // SEGMENTMAP_H
+21 -21
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Symbol.h"
@@ -33,13 +33,13 @@ Symbol::Symbol(Object& theObject, const GElf_Sym &sym)
sectionKind(SectionKind::undefined),
needsJT(false)
{
if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
{
section = theObject.sectionsByElfIndex[st_shndx];
sectionKind = section->kind;
}
if(st_name)
{
name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name);
}
if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
{
section = theObject.sectionsByElfIndex[st_shndx];
sectionKind = section->kind;
}
if(st_name)
{
name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name);
}
}
+21 -21
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SYMBOL_H
@@ -32,16 +32,16 @@ class Object;
class Symbol : public GElf_Sym
{
public:
bool valid;
bool referencedExternally;
SectionKind sectionKind;
bool needsJT;
int jtIndex;
std::shared_ptr<Section> section;
std::string name;
bool valid;
bool referencedExternally;
SectionKind sectionKind;
bool needsJT;
int jtIndex;
std::shared_ptr<Section> section;
std::string name;
Symbol();
Symbol(Object &theObject, const GElf_Sym& sym);
Symbol();
Symbol(Object &theObject, const GElf_Sym& sym);
};
+39 -39
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Symtab.h"
@@ -30,26 +30,26 @@ using std::string;
Symtab::Symtab(Object& theObject, Elf_Scn *elfsec)
: elfsec(elfsec)
{
data = elf_getdata(elfsec, NULL);
data = elf_getdata(elfsec, NULL);
GElf_Shdr shdr;
gelf_getshdr(elfsec, &shdr);
GElf_Shdr shdr;
gelf_getshdr(elfsec, &shdr);
int count = shdr.sh_size / shdr.sh_entsize;
symbols.reserve(count);
int count = shdr.sh_size / shdr.sh_entsize;
symbols.reserve(count);
for(int i = 0; i < count; i++)
{
GElf_Sym sym;
auto res = gelf_getsym(data, i, &sym);
assert(res != 0);
symbols.emplace_back(theObject, sym);
for(int i = 0; i < count; i++)
{
GElf_Sym sym;
auto res = gelf_getsym(data, i, &sym);
assert(res != 0);
symbols.emplace_back(theObject, sym);
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
if(sym.st_name)
symbolsByName[symbols.back().name] = i;
}
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
if(sym.st_name)
symbolsByName[symbols.back().name] = i;
}
}
Symtab::~Symtab()
@@ -59,23 +59,23 @@ Symtab::~Symtab()
Symbol &Symtab::GetSym(int idx)
{
return symbols[idx];
return symbols[idx];
}
int Symtab::FindSym(int secidx, uint32_t addr)
{
auto p = symbolsByAddress.find(make_pair(secidx, addr));
if(p != symbolsByAddress.end())
return p->second;
else
return -1;
auto p = symbolsByAddress.find(make_pair(secidx, addr));
if(p != symbolsByAddress.end())
return p->second;
else
return -1;
}
int Symtab::FindSym(string name)
{
auto p = symbolsByName.find(name);
if(p != symbolsByName.end())
return p->second;
else
return -1;
auto p = symbolsByName.find(name);
if(p != symbolsByName.end())
return p->second;
else
return -1;
}
+22 -22
View File
@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SYMTAB_H
@@ -33,18 +33,18 @@ class Symbol;
class Symtab
{
public:
Elf_Scn *elfsec;
Elf_Data *data;
std::vector<Symbol> symbols;
std::map<std::pair<int,uint32_t>, int> symbolsByAddress;
std::unordered_map<std::string, int> symbolsByName;
Elf_Scn *elfsec;
Elf_Data *data;
std::vector<Symbol> symbols;
std::map<std::pair<int,uint32_t>, int> symbolsByAddress;
std::unordered_map<std::string, int> symbolsByName;
Symtab(Object &theObject, Elf_Scn *elfsec);
~Symtab();
Symtab(Object &theObject, Elf_Scn *elfsec);
~Symtab();
Symbol& GetSym(int idx);
int FindSym(int secidx, uint32_t addr);
int FindSym(std::string name);
Symbol& GetSym(int idx);
int FindSym(int secidx, uint32_t addr);
int FindSym(std::string name);
};
+16 -16
View File
@@ -1,8 +1,8 @@
find_package(Boost COMPONENTS filesystem program_options)
set(LAUNCHMETHODS
Executor.h Executor.cc
MiniVMac.h MiniVMac.cc
Executor.h Executor.cc
MiniVMac.h MiniVMac.cc
SSH.h SSH.cc
StreamBasedLauncher.h StreamBasedLauncher.cc
Serial.h Serial.cc
@@ -11,32 +11,32 @@ set(LAUNCHMETHODS
)
if(APPLE)
LIST(APPEND LAUNCHMETHODS
Classic.h Classic.cc
)
LIST(APPEND LAUNCHMETHODS
Carbon.h Carbon.cc)
LIST(APPEND LAUNCHMETHODS
Classic.h Classic.cc
)
LIST(APPEND LAUNCHMETHODS
Carbon.h Carbon.cc)
endif()
add_definitions(-DRETRO68_PREFIX="${CMAKE_INSTALL_PREFIX}")
add_executable(LaunchAPPL
LaunchAPPL.cc
MakeExecutable.cc
LaunchAPPL.cc
MakeExecutable.cc
LaunchMethod.h LaunchMethod.cc
Launcher.h Launcher.cc
LaunchMethod.h LaunchMethod.cc
Launcher.h Launcher.cc
Utilities.h Utilities.cc
Utilities.h Utilities.cc
${LAUNCHMETHODS})
${LAUNCHMETHODS})
target_include_directories(LaunchAPPL PRIVATE ${CMAKE_INSTALL_PREFIX}/include ${Boost_INCLUDE_DIR})
target_link_libraries(LaunchAPPL ResourceFiles LaunchAPPLCommon ${Boost_LIBRARIES})
if(APPLE)
find_library(APPLICATIONSERVICES_FW ApplicationServices)
target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW})
find_library(APPLICATIONSERVICES_FW ApplicationServices)
target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW})
endif()
install(TARGETS LaunchAPPL RUNTIME DESTINATION bin)
+10 -10
View File
@@ -3,17 +3,17 @@
#include "Utilities.h"
const std::string launchCFM =
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
namespace po = boost::program_options;
class CarbonLauncher : public Launcher
{
public:
CarbonLauncher(po::variables_map& options);
virtual ~CarbonLauncher();
CarbonLauncher(po::variables_map& options);
virtual ~CarbonLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -30,18 +30,18 @@ CarbonLauncher::~CarbonLauncher()
bool CarbonLauncher::Go(int timeout)
{
return ChildProcess(launchCFM, { appPath.string() }, timeout) == 0;
return ChildProcess(launchCFM, { appPath.string() }, timeout) == 0;
}
bool Carbon::CheckPlatform()
{
/* If LaunchCFMApp doesn't exist, we're likely on a Mac OS X version
where it doesn't exist anymore (10.7 Lion or later),
or on an entirely different platform. */
return CheckExecutable(launchCFM);
/* If LaunchCFMApp doesn't exist, we're likely on a Mac OS X version
where it doesn't exist anymore (10.7 Lion or later),
or on an entirely different platform. */
return CheckExecutable(launchCFM);
}
std::unique_ptr<Launcher> Carbon::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new CarbonLauncher(options));
return std::unique_ptr<Launcher>(new CarbonLauncher(options));
}
+3 -3
View File
@@ -6,10 +6,10 @@
class Carbon : public LaunchMethod
{
public:
virtual std::string GetName() { return "carbon"; }
virtual std::string GetName() { return "carbon"; }
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // CARBON_METHOD_H
+40 -40
View File
@@ -12,10 +12,10 @@ namespace po = boost::program_options;
class ClassicLauncher : public Launcher
{
public:
ClassicLauncher(po::variables_map& options);
virtual ~ClassicLauncher();
ClassicLauncher(po::variables_map& options);
virtual ~ClassicLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -31,52 +31,52 @@ ClassicLauncher::~ClassicLauncher()
}
bool ClassicLauncher::Go(int timeout)
{
FSRef ref;
FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL);
LSApplicationParameters params;
memset(&params, 0, sizeof(params));
params.flags = kLSLaunchStartClassic
| kLSLaunchInClassic
| kLSLaunchDontAddToRecents
| kLSLaunchNewInstance;
params.application = &ref;
ProcessSerialNumber psn;
LSOpenApplication(&params, &psn);
// Classic startup takes place before LSOpenApplication returns,
// so no extra timeout is needed
for(int i = 0; i < timeout || timeout == 0; i++)
{
sleep(1);
ProcessInfoRec pi;
pi.processInfoLength = sizeof(pi);
pi.processName = NULL;
pi.processAppSpec = 0;
if(GetProcessInformation(&psn, &pi) == procNotFound)
return true;
}
{
FSRef ref;
FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL);
LSApplicationParameters params;
memset(&params, 0, sizeof(params));
params.flags = kLSLaunchStartClassic
| kLSLaunchInClassic
| kLSLaunchDontAddToRecents
| kLSLaunchNewInstance;
params.application = &ref;
ProcessSerialNumber psn;
LSOpenApplication(&params, &psn);
// Classic startup takes place before LSOpenApplication returns,
// so no extra timeout is needed
for(int i = 0; i < timeout || timeout == 0; i++)
{
sleep(1);
ProcessInfoRec pi;
pi.processInfoLength = sizeof(pi);
pi.processName = NULL;
pi.processAppSpec = 0;
if(GetProcessInformation(&psn, &pi) == procNotFound)
return true;
}
KillProcess(&psn);
KillProcess(&psn);
return false;
return false;
}
bool Classic::CheckPlatform()
{
long sysver = 0;
Gestalt(gestaltSystemVersion, &sysver);
if(sysver >= 0x1050)
return false;
else
return true;
long sysver = 0;
Gestalt(gestaltSystemVersion, &sysver);
if(sysver >= 0x1050)
return false;
else
return true;
}
std::unique_ptr<Launcher> Classic::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new ClassicLauncher(options));
return std::unique_ptr<Launcher>(new ClassicLauncher(options));
}
#endif
+3 -3
View File
@@ -6,10 +6,10 @@
class Classic : public LaunchMethod
{
public:
virtual std::string GetName() { return "classic"; }
virtual std::string GetName() { return "classic"; }
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // CLASSIC_H
+21 -21
View File
@@ -7,10 +7,10 @@ namespace po = boost::program_options;
class ExecutorLauncher : public Launcher
{
public:
ExecutorLauncher(po::variables_map& options);
virtual ~ExecutorLauncher();
ExecutorLauncher(po::variables_map& options);
virtual ~ExecutorLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -27,37 +27,37 @@ ExecutorLauncher::~ExecutorLauncher()
bool ExecutorLauncher::Go(int timeout)
{
std::vector<std::string> args;
if(options.count("executor-option"))
args = options["executor-option"].as<std::vector<std::string>>();
args.push_back(appPath.string());
std::vector<std::string> args;
if(options.count("executor-option"))
args = options["executor-option"].as<std::vector<std::string>>();
args.push_back(appPath.string());
if(options.count("executor-system-folder"))
setenv("SystemFolder", options["executor-system-folder"].as<std::string>().c_str(), true);
if(options.count("executor-system-folder"))
setenv("SystemFolder", options["executor-system-folder"].as<std::string>().c_str(), true);
return ChildProcess(options["executor-path"].as<std::string>(), args, timeout) == 0;
return ChildProcess(options["executor-path"].as<std::string>(), args, timeout) == 0;
}
void Executor::GetOptions(options_description &desc)
{
desc.add_options()
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
("executor-system-folder", po::value<std::string>(),
"system folder for executor (overrides SystemFolder environment variable)")
("executor-option", po::value<std::vector<std::string>>(),
"pass an option to executor")
;
desc.add_options()
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
("executor-system-folder", po::value<std::string>(),
"system folder for executor (overrides SystemFolder environment variable)")
("executor-option", po::value<std::vector<std::string>>(),
"pass an option to executor")
;
}
bool Executor::CheckOptions(variables_map &options)
{
if(options.count("executor-path") == 0)
return false;
return CheckExecutable(options["executor-path"].as<std::string>());
if(options.count("executor-path") == 0)
return false;
return CheckExecutable(options["executor-path"].as<std::string>());
}
std::unique_ptr<Launcher> Executor::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
}
+4 -4
View File
@@ -6,11 +6,11 @@
class Executor : public LaunchMethod
{
public:
virtual std::string GetName() { return "executor"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "executor"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H
+191 -191
View File
@@ -9,13 +9,13 @@
#include "Launcher.h"
#if defined(__APPLE__)
# define ResType MacResType
# include <ApplicationServices/ApplicationServices.h>
# undef ResType
# if TARGET_CPU_PPC
# include "Classic.h"
# endif
# include "Carbon.h"
# define ResType MacResType
# include <ApplicationServices/ApplicationServices.h>
# undef ResType
# if TARGET_CPU_PPC
# include "Classic.h"
# endif
# include "Carbon.h"
#endif
#include "Executor.h"
#include "MiniVMac.h"
@@ -37,224 +37,224 @@ static vector<LaunchMethod*> launchMethods;
static void RegisterLaunchMethods()
{
vector<LaunchMethod*> methods = {
vector<LaunchMethod*> methods = {
#if defined(__APPLE__)
# if TARGET_CPU_PPC
new Classic(),
# endif
new Carbon(),
# if TARGET_CPU_PPC
new Classic(),
# endif
new Carbon(),
#endif
new Executor(), new MiniVMac(),
new SSH(),
new Executor(), new MiniVMac(),
new SSH(),
new Serial(),
new TCP(),
new SharedFile()
// #### Add new `LaunchMethod`s here.
};
for(LaunchMethod *m : methods)
{
if(m->CheckPlatform())
launchMethods.push_back(m);
}
// #### Add new `LaunchMethod`s here.
};
for(LaunchMethod *m : methods)
{
if(m->CheckPlatform())
launchMethods.push_back(m);
}
}
static void usage()
{
std::cerr << "Usage: " << "LaunchAPPL [options] appl-file\n";
std::cerr << desc << std::endl;
std::cerr << "Defaults are read from:\n";
for(string str : configFiles)
{
std::cerr << "\t" << str;
if(!std::ifstream(str))
std::cerr << " (not found)";
std::cerr << std::endl;
}
std::cerr << std::endl;
std::cerr << "Usage: " << "LaunchAPPL [options] appl-file\n";
std::cerr << desc << std::endl;
std::cerr << "Defaults are read from:\n";
for(string str : configFiles)
{
std::cerr << "\t" << str;
if(!std::ifstream(str))
std::cerr << " (not found)";
std::cerr << std::endl;
}
std::cerr << std::endl;
vector<string> configuredMethods, unconfiguredMethods;
for(LaunchMethod *method : launchMethods)
(method->CheckOptions(options) ? configuredMethods : unconfiguredMethods)
.push_back(method->GetName());
vector<string> configuredMethods, unconfiguredMethods;
for(LaunchMethod *method : launchMethods)
(method->CheckOptions(options) ? configuredMethods : unconfiguredMethods)
.push_back(method->GetName());
if(!configuredMethods.empty())
{
std::cerr << "Available emulators/environments:\n";
for(string m : configuredMethods)
std::cerr << "\t" << m << std::endl;
}
if(!unconfiguredMethods.empty())
{
std::cerr << "Emulators/environments needing more configuration:\n";
for(string m : unconfiguredMethods)
std::cerr << "\t" << m << std::endl;
}
if(!configuredMethods.empty())
{
std::cerr << "Available emulators/environments:\n";
for(string m : configuredMethods)
std::cerr << "\t" << m << std::endl;
}
if(!unconfiguredMethods.empty())
{
std::cerr << "Emulators/environments needing more configuration:\n";
for(string m : unconfiguredMethods)
std::cerr << "\t" << m << std::endl;
}
if(options.count("emulator"))
{
string e = options["emulator"].as<string>();
std::cerr << "\nChosen emulator/environment: " << e;
if(std::find(configuredMethods.begin(), configuredMethods.end(), e)
!= configuredMethods.end())
std::cerr << "\n";
else if(std::find(unconfiguredMethods.begin(), unconfiguredMethods.end(), e)
!= unconfiguredMethods.end())
std::cerr << " (needs more configuration)\n";
else
std::cerr << " (UNKNOWN)\n";
}
else
{
std::cerr << "\nNo emulator/environment chosen (-e)\n";
}
if(options.count("emulator"))
{
string e = options["emulator"].as<string>();
std::cerr << "\nChosen emulator/environment: " << e;
if(std::find(configuredMethods.begin(), configuredMethods.end(), e)
!= configuredMethods.end())
std::cerr << "\n";
else if(std::find(unconfiguredMethods.begin(), unconfiguredMethods.end(), e)
!= unconfiguredMethods.end())
std::cerr << " (needs more configuration)\n";
else
std::cerr << " (UNKNOWN)\n";
}
else
{
std::cerr << "\nNo emulator/environment chosen (-e)\n";
}
}
void MakeExecutable(string filepath);
int main(int argc, char *argv[])
{
RegisterLaunchMethods();
configFiles = { string(getenv("HOME")) + "/.LaunchAPPL.cfg", RETRO68_PREFIX "/LaunchAPPL.cfg"};
RegisterLaunchMethods();
configFiles = { string(getenv("HOME")) + "/.LaunchAPPL.cfg", RETRO68_PREFIX "/LaunchAPPL.cfg"};
desc.add_options()
("help,h", "show this help message")
("list-emulators,l", "get the list of available, fully configured emulators/environments")
("make-executable,x", po::value<std::string>(), "make a MacBinary file executable")
;
po::options_description configdesc;
configdesc.add_options()
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
;
for(LaunchMethod *lm : launchMethods)
lm->GetOptions(configdesc);
desc.add(configdesc);
desc.add_options()
("help,h", "show this help message")
("list-emulators,l", "get the list of available, fully configured emulators/environments")
("make-executable,x", po::value<std::string>(), "make a MacBinary file executable")
;
po::options_description configdesc;
configdesc.add_options()
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
;
for(LaunchMethod *lm : launchMethods)
lm->GetOptions(configdesc);
desc.add(configdesc);
desc.add_options()
("timeout,t", po::value<int>(),"abort after timeout")
desc.add_options()
("timeout,t", po::value<int>(),"abort after timeout")
("upgrade-server", "upgrade the server application")
;
po::options_description hidden, alldesc;
hidden.add_options()
("application,a", po::value<std::string>(), "application" )
;
alldesc.add(desc).add(hidden);
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("application", -1))
.style(po::command_line_style::default_style)
.run();
;
po::options_description hidden, alldesc;
hidden.add_options()
("application,a", po::value<std::string>(), "application" )
;
alldesc.add(desc).add(hidden);
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("application", -1))
.style(po::command_line_style::default_style)
.run();
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
for(string configFileName : configFiles)
{
try
{
std::ifstream cfg(configFileName);
if(cfg)
{
auto parsed = po::parse_config_file<char>(cfg,configdesc,false);
for(string configFileName : configFiles)
{
try
{
std::ifstream cfg(configFileName);
if(cfg)
{
auto parsed = po::parse_config_file<char>(cfg,configdesc,false);
po::store(parsed, options);
}
}
catch(po::error& e)
{
std::cerr << "CONFIG FILE ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
}
po::store(parsed, options);
}
}
catch(po::error& e)
{
std::cerr << "CONFIG FILE ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
}
po::notify(options);
po::notify(options);
vector<string> commandModes = {"application", "help", "make-executable", "list-emulators"};
int nModes = 0;
string mode;
vector<string> commandModes = {"application", "help", "make-executable", "list-emulators"};
int nModes = 0;
string mode;
for(string aMode : commandModes)
{
if(options.count(aMode))
{
nModes++;
mode = aMode;
}
}
if(nModes > 1)
{
std::cerr << "Need to specify either an application file or exactly one of ";
for(int i = 1, n = commandModes.size(); i < n-1; i++)
std::cerr << "--" << commandModes[i] << ", ";
std::cerr << "or " << commandModes.back() << "." << std::endl << std::endl;
usage();
return 1;
}
if(mode == "" || mode == "help")
{
usage();
return 0;
}
else if(mode == "make-executable")
{
string fn = options["make-executable"].as<std::string>();
MakeExecutable(fn);
return 0;
}
else if(mode == "list-emulators")
{
for(LaunchMethod *method : launchMethods)
if(method->CheckOptions(options))
std::cout << method->GetName() << std::endl;
return 0;
}
for(string aMode : commandModes)
{
if(options.count(aMode))
{
nModes++;
mode = aMode;
}
}
if(nModes > 1)
{
std::cerr << "Need to specify either an application file or exactly one of ";
for(int i = 1, n = commandModes.size(); i < n-1; i++)
std::cerr << "--" << commandModes[i] << ", ";
std::cerr << "or " << commandModes.back() << "." << std::endl << std::endl;
usage();
return 1;
}
if(mode == "" || mode == "help")
{
usage();
return 0;
}
else if(mode == "make-executable")
{
string fn = options["make-executable"].as<std::string>();
MakeExecutable(fn);
return 0;
}
else if(mode == "list-emulators")
{
for(LaunchMethod *method : launchMethods)
if(method->CheckOptions(options))
std::cout << method->GetName() << std::endl;
return 0;
}
if(!options.count("emulator"))
{
std::cerr << "ERROR: emulator/environment not specified.\n";
usage();
return 1;
}
if(!options.count("emulator"))
{
std::cerr << "ERROR: emulator/environment not specified.\n";
usage();
return 1;
}
LaunchMethod *method = NULL;
for(LaunchMethod *lm : launchMethods)
{
if(lm->GetName() == options["emulator"].as<string>())
{
method = lm;
break;
}
}
if(!method)
{
std::cerr << "ERROR: unknown emulator/environment: " << options["emulator"].as<string>() << "\n";
return 1;
}
LaunchMethod *method = NULL;
for(LaunchMethod *lm : launchMethods)
{
if(lm->GetName() == options["emulator"].as<string>())
{
method = lm;
break;
}
}
if(!method)
{
std::cerr << "ERROR: unknown emulator/environment: " << options["emulator"].as<string>() << "\n";
return 1;
}
if(!method->CheckOptions(options))
{
std::cerr << "Need more configuration.\n";
usage();
return 1;
}
if(!method->CheckOptions(options))
{
std::cerr << "Need more configuration.\n";
usage();
return 1;
}
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
bool result = launcher->Go(timeout);
bool result = launcher->Go(timeout);
launcher->DumpOutput();
launcher->DumpOutput();
return result ? 0 : 1;
return result ? 0 : 1;
}
+2 -2
View File
@@ -16,10 +16,10 @@ void LaunchMethod::GetOptions(boost::program_options::options_description &desc)
bool LaunchMethod::CheckPlatform()
{
return true;
return true;
}
bool LaunchMethod::CheckOptions(boost::program_options::variables_map &options)
{
return true;
return true;
}
+40 -40
View File
@@ -18,52 +18,52 @@ class Launcher;
class LaunchMethod
{
public:
typedef boost::program_options::options_description options_description;
typedef boost::program_options::variables_map variables_map;
typedef boost::program_options::options_description options_description;
typedef boost::program_options::variables_map variables_map;
LaunchMethod();
virtual ~LaunchMethod();
LaunchMethod();
virtual ~LaunchMethod();
/**
* @brief GetName
* @return the name of the launch method, as it will be specified on the command line
*/
virtual std::string GetName() = 0;
/**
* @brief GetName
* @return the name of the launch method, as it will be specified on the command line
*/
virtual std::string GetName() = 0;
/**
* @brief GetOptions
* @param desc
*
* Add any command line options for this LaunchMethod
* to the options_description structure.
*/
virtual void GetOptions(options_description& desc);
/**
* @brief GetOptions
* @param desc
*
* Add any command line options for this LaunchMethod
* to the options_description structure.
*/
virtual void GetOptions(options_description& desc);
/**
* @brief CheckPlatform
*
* Check whether this is the right kind of machine to use this method.
* For things like Apple's Classic Environment, which is only available on some system versions.
* The default implementation returns true.
*/
virtual bool CheckPlatform();
/**
* @brief CheckPlatform
*
* Check whether this is the right kind of machine to use this method.
* For things like Apple's Classic Environment, which is only available on some system versions.
* The default implementation returns true.
*/
virtual bool CheckPlatform();
/**
* @brief CheckOptions
* @param options
* @return are we ready to run?
*
* Check whether all necessary options have been specified.
* Don't output error messages here, this is also called when outputting usage information
*/
virtual bool CheckOptions(variables_map& options);
/**
* @brief CheckOptions
* @param options
* @return are we ready to run?
*
* Check whether all necessary options have been specified.
* Don't output error messages here, this is also called when outputting usage information
*/
virtual bool CheckOptions(variables_map& options);
/**
* @brief MakeLauncher
* @param options
* @return a new instance of a subclass of Launcher which will do the actual work
*/
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
/**
* @brief MakeLauncher
* @param options
* @return a new instance of a subclass of Launcher which will do the actual work
*/
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
protected:
};
+26 -26
View File
@@ -11,47 +11,47 @@ using std::vector;
Launcher::Launcher(boost::program_options::variables_map &options)
: options(options)
{
string fn = options["application"].as<std::string>();
if(fn == "-")
{
std::stringstream tmp;
tmp << std::cin.rdbuf();
if(!app.read(tmp, ResourceFile::Format::macbin))
throw std::runtime_error("Could not load application from stdin.");
}
else
{
app.assign(fn);
if(!app.read())
throw std::runtime_error("Could not load application file.");
}
tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir);
string fn = options["application"].as<std::string>();
if(fn == "-")
{
std::stringstream tmp;
tmp << std::cin.rdbuf();
if(!app.read(tmp, ResourceFile::Format::macbin))
throw std::runtime_error("Could not load application from stdin.");
}
else
{
app.assign(fn);
if(!app.read())
throw std::runtime_error("Could not load application file.");
}
tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir);
appPath = tempDir / "Application";
outPath = tempDir / "out";
appPath = tempDir / "Application";
outPath = tempDir / "out";
fs::ofstream out(outPath);
fs::ofstream out(outPath);
}
Launcher::Launcher(boost::program_options::variables_map &options, ResourceFile::Format f)
: Launcher(options)
{
app.assign(appPath.string(), f);
app.write();
app.assign(appPath.string(), f);
app.write();
}
void Launcher::DumpOutput()
{
fs::ifstream in(outPath);
std::cout << in.rdbuf();
fs::ifstream in(outPath);
std::cout << in.rdbuf();
}
Launcher::~Launcher()
{
fs::remove_all(tempDir);
fs::remove_all(tempDir);
}
+47 -47
View File
@@ -14,61 +14,61 @@
class Launcher
{
protected:
boost::program_options::variables_map& options;
boost::program_options::variables_map& options;
ResourceFile app;
boost::filesystem::path tempDir, appPath, outPath;
bool keepTempFiles;
ResourceFile app;
boost::filesystem::path tempDir, appPath, outPath;
bool keepTempFiles;
public:
/**
* @brief Launcher
* @param options
*
* Create a Launcher object and set up a temporary directory to play in.
* Reads the Applicatio specified on the command line into the `app` member variable.
* Also create an empty file named 'out' in the temporary directory, for test suite programs.
*/
Launcher(boost::program_options::variables_map& options);
/**
* @brief Launcher
* @param options
*
* Create a Launcher object and set up a temporary directory to play in.
* Reads the Applicatio specified on the command line into the `app` member variable.
* Also create an empty file named 'out' in the temporary directory, for test suite programs.
*/
Launcher(boost::program_options::variables_map& options);
/**
* @brief Launcher
* @param options
* @param f
*
* Create a Launcher object, set up a temporary directory
* and store the application to be executed at `appPath` in the temporary directory,
* using format `f`.
*/
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
/**
* @brief Launcher
* @param options
* @param f
*
* Create a Launcher object, set up a temporary directory
* and store the application to be executed at `appPath` in the temporary directory,
* using format `f`.
*/
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
/**
* @brief ~Launcher
* Delete our temporary directory.
*/
virtual ~Launcher();
/**
* @brief ~Launcher
* Delete our temporary directory.
*/
virtual ~Launcher();
/**
* @brief Go
* @param timeout
* @return true for success
*
* Launch the application, return true on success and false on error or timeout.
*/
virtual bool Go(int timeout = 0) = 0;
/**
* @brief Go
* @param timeout
* @return true for success
*
* Launch the application, return true on success and false on error or timeout.
*/
virtual bool Go(int timeout = 0) = 0;
/**
* @brief DumpOutput
*
* After the application has been run, copy the contents of the 'out' file to stdout.
*/
virtual void DumpOutput();
/**
* @brief DumpOutput
*
* After the application has been run, copy the contents of the 'out' file to stdout.
*/
virtual void DumpOutput();
/**
* @brief KeepTempFiles
* Inhibit deletion of the temporary directory.
*/
void KeepTempFiles() { keepTempFiles = true; }
/**
* @brief KeepTempFiles
* Inhibit deletion of the temporary directory.
*/
void KeepTempFiles() { keepTempFiles = true; }
};
#endif // LAUNCHER_H
+34 -34
View File
@@ -11,43 +11,43 @@ namespace fs = boost::filesystem;
void MakeExecutable(string fn)
{
ResourceFile rsrcFile(fn);
if(!rsrcFile.read())
{
std::cerr << "Cannot read application file: " << fn << std::endl;
exit(1);
}
if(!rsrcFile.hasPlainDataFork())
{
std::cerr << "--make-executable can not be used with this data format.\n";
exit(1);
}
ResourceFile rsrcFile(fn);
if(!rsrcFile.read())
{
std::cerr << "Cannot read application file: " << fn << std::endl;
exit(1);
}
if(!rsrcFile.hasPlainDataFork())
{
std::cerr << "--make-executable can not be used with this data format.\n";
exit(1);
}
string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n";
string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n";
bool hadShebang = false;
if(rsrcFile.data.size())
{
if(headerString.substr(2) == "#!")
{
string::size_type eol = headerString.find('\n');
if(eol != string::npos && eol >= 13 && eol < 4096)
{
if(headerString.substr(eol-11,11) == "/LaunchAPPL")
hadShebang = true;
}
}
bool hadShebang = false;
if(rsrcFile.data.size())
{
if(headerString.substr(2) == "#!")
{
string::size_type eol = headerString.find('\n');
if(eol != string::npos && eol >= 13 && eol < 4096)
{
if(headerString.substr(eol-11,11) == "/LaunchAPPL")
hadShebang = true;
}
}
if(!hadShebang)
{
std::cerr << "Unfortunately, the application already has a data fork.\n";
std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n";
// TODO: if it's a PEF container, move it back a little and update cfrg
exit(1);
}
}
if(!hadShebang)
{
std::cerr << "Unfortunately, the application already has a data fork.\n";
std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n";
// TODO: if it's a PEF container, move it back a little and update cfrg
exit(1);
}
}
std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString;
std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString;
fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms);
fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms);
}
+4 -4
View File
@@ -6,11 +6,11 @@
class MiniVMac : public LaunchMethod
{
public:
virtual std::string GetName() { return "minivmac"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "minivmac"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // MINIVMAC_H
+86 -86
View File
@@ -16,10 +16,10 @@ using std::vector;
class SSHLauncher : public Launcher
{
public:
SSHLauncher(po::variables_map& options);
virtual ~SSHLauncher();
SSHLauncher(po::variables_map& options);
virtual ~SSHLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -36,115 +36,115 @@ SSHLauncher::~SSHLauncher()
static void insertArgs(vector<string>& args, po::variables_map& options, string name)
{
if(options.count(name))
{
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
}
if(options.count(name))
{
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
}
}
bool SSHLauncher::Go(int timeout)
{
std::vector<std::string> args;
args.push_back(options["ssh-host"].as<string>());
insertArgs(args, options, "ssh-args");
args.push_back("--");
args.push_back(options["ssh-remote-path"].as<string>());
insertArgs(args, options, "ssh-remote-args");
if(timeout)
{
args.push_back("--timeout");
args.push_back(boost::lexical_cast<std::string>(timeout));
}
args.push_back("-");
std::vector<std::string> args;
args.push_back(options["ssh-host"].as<string>());
insertArgs(args, options, "ssh-args");
args.push_back("--");
args.push_back(options["ssh-remote-path"].as<string>());
insertArgs(args, options, "ssh-remote-args");
if(timeout)
{
args.push_back("--timeout");
args.push_back(boost::lexical_cast<std::string>(timeout));
}
args.push_back("-");
std::string program = options["ssh-path"].as<std::string>();
std::string program = options["ssh-path"].as<std::string>();
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(std::string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(std::string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
int fd[2];
pipe(fd);
const int READ_END = 0;
const int WRITE_END = 1;
int fd[2];
pipe(fd);
const int READ_END = 0;
const int WRITE_END = 1;
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
else
{
close(fd[READ_END]);
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
else
{
close(fd[READ_END]);
std::ostringstream tmp;
app.write(tmp, ResourceFile::Format::macbin);
const std::string data = tmp.str();
std::ostringstream tmp;
app.write(tmp, ResourceFile::Format::macbin);
const std::string data = tmp.str();
write(fd[WRITE_END], data.data(), data.size());
close(fd[WRITE_END]);
write(fd[WRITE_END], data.data(), data.size());
close(fd[WRITE_END]);
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
return false;
}
else
{
//int exitcode = WEXITSTATUS(wstatus);
return true;
}
}
if(!WIFEXITED(wstatus))
{
return false;
}
else
{
//int exitcode = WEXITSTATUS(wstatus);
return true;
}
}
}
void SSH::GetOptions(options_description &desc)
{
desc.add_options()
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
("ssh-host", po::value<string>(),
"[username@]address of remote host")
("ssh-args", po::value<vector<string>>(),
"additional arguments for ssh")
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
"path to LaunchAPPL on remote host")
("ssh-remote-args", po::value<vector<string>>(),
"additional arguments for LaunchAPPL on remote host")
;
desc.add_options()
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
("ssh-host", po::value<string>(),
"[username@]address of remote host")
("ssh-args", po::value<vector<string>>(),
"additional arguments for ssh")
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
"path to LaunchAPPL on remote host")
("ssh-remote-args", po::value<vector<string>>(),
"additional arguments for LaunchAPPL on remote host")
;
}
bool SSH::CheckOptions(variables_map &options)
{
return options.count("ssh-host") != 0;
return options.count("ssh-host") != 0;
}
std::unique_ptr<Launcher> SSH::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new SSHLauncher(options));
return std::unique_ptr<Launcher>(new SSHLauncher(options));
}
+4 -4
View File
@@ -6,11 +6,11 @@
class SSH : public LaunchMethod
{
public:
virtual std::string GetName() { return "ssh"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "ssh"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // SSH_H
+3 -3
View File
@@ -36,7 +36,7 @@ class SerialLauncher : public StreamBasedLauncher
SerialStream stream;
ReliableStream rStream;
public:
SerialLauncher(po::variables_map& options);
SerialLauncher(po::variables_map& options);
};
@@ -146,10 +146,10 @@ void Serial::GetOptions(options_description &desc)
bool Serial::CheckOptions(variables_map &options)
{
return true;
return true;
}
std::unique_ptr<Launcher> Serial::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new SerialLauncher(options));
return std::unique_ptr<Launcher>(new SerialLauncher(options));
}
+4 -4
View File
@@ -6,11 +6,11 @@
class Serial : public LaunchMethod
{
public:
virtual std::string GetName() { return "serial"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "serial"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H
+3 -3
View File
@@ -30,7 +30,7 @@ class SharedFileLauncher : public StreamBasedLauncher
{
SharedFileStream stream;
public:
SharedFileLauncher(po::variables_map& options);
SharedFileLauncher(po::variables_map& options);
};
SharedFileStream::SharedFileStream(po::variables_map &options)
@@ -90,10 +90,10 @@ void SharedFile::GetOptions(options_description &desc)
bool SharedFile::CheckOptions(variables_map &options)
{
return options.count("shared-directory") != 0;
return options.count("shared-directory") != 0;
}
std::unique_ptr<Launcher> SharedFile::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new SharedFileLauncher(options));
return std::unique_ptr<Launcher>(new SharedFileLauncher(options));
}
+4 -4
View File
@@ -5,9 +5,9 @@
class SharedFile : public LaunchMethod
{
public:
virtual std::string GetName() { return "shared"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "shared"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
+4 -4
View File
@@ -12,11 +12,11 @@ class StreamBasedLauncher : public Launcher
std::vector<char> outputBytes;
bool upgradeMode = false;
public:
StreamBasedLauncher(boost::program_options::variables_map& options);
virtual ~StreamBasedLauncher();
StreamBasedLauncher(boost::program_options::variables_map& options);
virtual ~StreamBasedLauncher();
virtual bool Go(int timeout = 0);
virtual void DumpOutput();
virtual bool Go(int timeout = 0);
virtual void DumpOutput();
protected:
void SetupStream(WaitableStream* aStream, Stream* wrapped = nullptr);
+3 -3
View File
@@ -34,7 +34,7 @@ class TCPLauncher : public StreamBasedLauncher
{
TCPStream stream;
public:
TCPLauncher(po::variables_map& options);
TCPLauncher(po::variables_map& options);
};
@@ -85,10 +85,10 @@ void TCP::GetOptions(options_description &desc)
bool TCP::CheckOptions(variables_map &options)
{
return options.count("tcp-address") != 0;
return options.count("tcp-address") != 0;
}
std::unique_ptr<Launcher> TCP::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new TCPLauncher(options));
return std::unique_ptr<Launcher>(new TCPLauncher(options));
}
+4 -4
View File
@@ -6,11 +6,11 @@
class TCP : public LaunchMethod
{
public:
virtual std::string GetName() { return "tcp"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "tcp"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H
+149 -149
View File
@@ -13,90 +13,90 @@ using std::vector;
int ChildProcess(string program, vector<string> args, int timeout)
{
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
pid_t worker_pid = timeout ? fork() : 0;
if(worker_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(worker_pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
pid_t worker_pid = timeout ? fork() : 0;
if(worker_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(worker_pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
pid_t timeout_pid = fork();
if(timeout_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(timeout_pid == 0)
{
sleep(timeout);
_exit(0);
}
int wstatus;
pid_t exited_pid = wait(&wstatus);
if(exited_pid == worker_pid)
{
kill(timeout_pid, SIGKILL);
wait(NULL);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
_exit(exitcode);
}
}
else
{
kill(worker_pid, SIGKILL);
wait(NULL);
_exit(1);
}
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
pid_t timeout_pid = fork();
if(timeout_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(timeout_pid == 0)
{
sleep(timeout);
_exit(0);
}
int wstatus;
pid_t exited_pid = wait(&wstatus);
if(exited_pid == worker_pid)
{
kill(timeout_pid, SIGKILL);
wait(NULL);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
_exit(exitcode);
}
}
else
{
kill(worker_pid, SIGKILL);
wait(NULL);
_exit(1);
}
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
return exitcode;
}
}
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
return exitcode;
}
}
}
@@ -104,89 +104,89 @@ int ChildProcess(string program, vector<string> args, int timeout)
bool CheckExecutable(std::string program)
{
if(access(program.c_str(), X_OK) == 0)
return true;
if(program.find("/") != std::string::npos)
return false;
const char *PATH = getenv("PATH");
if(access(program.c_str(), X_OK) == 0)
return true;
if(program.find("/") != std::string::npos)
return false;
const char *PATH = getenv("PATH");
if(PATH)
{
bool endFound = false;
do
{
const char *end = strchr(PATH, ':');
if(!end)
{
end = strchr(PATH, '\0');
endFound = true;
}
std::string pathElement(PATH, end);
if(PATH)
{
bool endFound = false;
do
{
const char *end = strchr(PATH, ':');
if(!end)
{
end = strchr(PATH, '\0');
endFound = true;
}
std::string pathElement(PATH, end);
if(pathElement == "")
pathElement = ".";
if(pathElement == "")
pathElement = ".";
fs::path f = fs::path(pathElement) / program;
fs::path f = fs::path(pathElement) / program;
if(access(f.string().c_str(), X_OK) == 0)
return true;
if(access(f.string().c_str(), X_OK) == 0)
return true;
PATH = end + 1;
} while(!endFound);
}
PATH = end + 1;
} while(!endFound);
}
return false;
return false;
}
vector<string> SplitArguments(std::string str)
{
bool backslash = false;
bool quote = false;
bool begun = false;
vector<string> args;
bool backslash = false;
bool quote = false;
bool begun = false;
vector<string> args;
for(char c : str)
{
if(!backslash && !quote && isspace(c))
{
begun = false;
}
else if(!backslash && c == '"')
{
quote = !quote;
if(quote && !begun)
{
args.emplace_back();
begun = true;
}
}
else if(!backslash && c == '\\')
{
backslash = true;
}
else
{
backslash = false;
for(char c : str)
{
if(!backslash && !quote && isspace(c))
{
begun = false;
}
else if(!backslash && c == '"')
{
quote = !quote;
if(quote && !begun)
{
args.emplace_back();
begun = true;
}
}
else if(!backslash && c == '\\')
{
backslash = true;
}
else
{
backslash = false;
if(!begun)
{
args.emplace_back();
begun = true;
}
args.back() += c;
}
}
if(!begun)
{
args.emplace_back();
begun = true;
}
args.back() += c;
}
}
return args;
return args;
}
vector<string> SplitArguments(vector<string> strs)
{
vector<string> args;
for(string str : strs)
{
vector<string> args1 = SplitArguments(str);
args.insert(args.end(), args1.begin(), args1.end());
}
return args;
vector<string> args;
for(string str : strs)
{
vector<string> args1 = SplitArguments(str);
args.insert(args.end(), args1.begin(), args1.end());
}
return args;
}
+9 -9
View File
@@ -645,20 +645,20 @@ int main()
#if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
short& ROM85 = *(short*) 0x028E;
Boolean is128KROM = (ROM85 > 0);
Boolean hasWaitNextEvent = false;
Boolean is128KROM = (ROM85 > 0);
Boolean hasWaitNextEvent = false;
Boolean hasGestalt = false;
Boolean hasAppleEvents = false;
hasIconUtils = false;
hasColorQD = false;
if (is128KROM)
{
UniversalProcPtr trapUnimpl = GetToolTrapAddress(_Unimplemented);
if (is128KROM)
{
UniversalProcPtr trapUnimpl = GetToolTrapAddress(_Unimplemented);
UniversalProcPtr trapWaitNextEvent = GetToolTrapAddress(_WaitNextEvent);
UniversalProcPtr trapGestalt = GetOSTrapAddress(_Gestalt);
hasWaitNextEvent = (trapWaitNextEvent != trapUnimpl);
hasWaitNextEvent = (trapWaitNextEvent != trapUnimpl);
hasGestalt = (trapGestalt != trapUnimpl);
if(hasGestalt)
@@ -676,10 +676,10 @@ int main()
err = Gestalt(gestaltStandardFileAttr, &response);
hasSys7StdFile = err == noErr && (response & (1 << gestaltStandardFile58)) != 0;
}
}
}
#else
#if !TARGET_API_MAC_CARBON
const Boolean hasWaitNextEvent = true;
const Boolean hasWaitNextEvent = true;
#endif
const Boolean hasGestalt = true;
const Boolean hasAppleEvents = true;
@@ -816,5 +816,5 @@ int main()
}
WritePrefs();
return 0;
return 0;
}
+1 -1
View File
@@ -67,7 +67,7 @@ void MacSerialStream::write(const void* p, size_t n)
pb.ioParam.ioRefNum = outRefNum;
pb.ioParam.ioBuffer = (Ptr)p;
pb.ioParam.ioReqCount = n;
/*OSErr err =*/ PBWriteSync(&pb);
/*OSErr err =*/ PBWriteSync(&pb);
}
void MacSerialStream::idle()
+8 -8
View File
@@ -48,13 +48,13 @@ void MacTCPStream::startListening()
readPB.ioCRefNum = refNum;
readPB.tcpStream = tcpStream;
readPB.csCode = TCPPassiveOpen;
readPB.ioResult = 1;
readPB.csParam.open.ulpTimeoutValue = 5;// ###
readPB.csParam.open.ulpTimeoutAction = 1;
readPB.csParam.open.validityFlags = 0xC0;
readPB.csParam.open.commandTimeoutValue = 0;
readPB.csParam.open.localPort = 1984;
readPB.csCode = TCPPassiveOpen;
readPB.ioResult = 1;
readPB.csParam.open.ulpTimeoutValue = 5;// ###
readPB.csParam.open.ulpTimeoutAction = 1;
readPB.csParam.open.validityFlags = 0xC0;
readPB.csParam.open.commandTimeoutValue = 0;
readPB.csParam.open.localPort = 1984;
PBControlAsync((ParmBlkPtr)&readPB);
}
@@ -74,7 +74,7 @@ MacTCPStream::~MacTCPStream()
memset(&pb, 0, sizeof(pb));
pb.ioCRefNum = refNum;
pb.tcpStream = tcpStream;
pb.csCode = TCPRelease;
pb.csCode = TCPRelease;
PBControlSync((ParmBlkPtr)&pb);
}
+1 -1
View File
@@ -110,7 +110,7 @@ OpenTptStream::~OpenTptStream()
{
endpoint->SetNonBlocking();
if(connected)
endpoint->SndDisconnect(&call);
endpoint->SndDisconnect(&call);
endpoint->Unbind();
OTCloseProvider(endpoint);
}
+283 -283
View File
</
@@ -40,328 +40,328 @@ bool verboseFlag = false;
struct CFragMember
{
string name;
uint32_t architecture;
uint8_t usage;
char *data;
uint32_t length;
CFragMember() : architecture(0), usage(0), data(0), length(0) {}
CFragMember(string n, uint32_t a, uint8_t u, char *d, uint32_t l)
: name(n), architecture(a), usage(u), data(d), length(l)
{
}
string name;
uint32_t architecture;
uint8_t usage;
char *data;
uint32_t length;
CFragMember() : architecture(0), usage(0), data(0), length(0) {}
CFragMember(string n, uint32_t a, uint8_t u, char *d, uint32_t l)
: name(n), architecture(a), usage(u), data(d), length(l)
{
}
};
void RunCommand(const char *command, std::vector<std::string> args)
{
std::vector<const char*> ptrs;
ptrs.push_back(command);
for(auto& s : args)
ptrs.push_back(s.c_str());
ptrs.push_back(NULL);
std::vector<const char*> ptrs;
ptrs.push_back(command);
for(auto& s : args)
ptrs.push_back(s.c_str());
ptrs.push_back(NULL);
pid_t pid = fork();
if(pid == -1)
{
perror(command);
exit(1);
}
pid_t pid = fork();
if(pid == -1)
{
perror(command);
exit(1);