* Debugger: clicking on Symbolic names works as well as clicking on addresses

* Tracer: clicking on Symbolic names works as well as clicking on addresses
* Debugger: "Symbolic Debug" is enabled by default. "Symbolic trace", on the other hand, is not enabled by default, because it slows down tracing performance 2x (even when there's no NL files!)
This commit is contained in:
ansstuff 2013-09-20 18:12:16 +00:00
parent 0e2422f90a
commit 8f9e2be234
7 changed files with 210 additions and 75 deletions

View File

@ -82,7 +82,9 @@ char* debug_decoration_comment;
char* debug_decoration_comment_end_pos;
// this is used to keep track of addresses that lines of Disassembly window correspond to
std::vector<unsigned int> disassembly_addresses;
std::vector<uint16> disassembly_addresses;
// this is used to keep track of addresses in operands of each printed instruction
std::vector<std::vector<uint16>> disassembly_operands;
// this is used to autoscroll the Disassembly window while keeping relative position of the ">" pointer inside this window
unsigned int PC_pointerOffset = 0;
// this is used for dirty, but unavoidable hack, which is necessary to ensure the ">" pointer is visible when stepping/seeking to PC
@ -394,12 +396,11 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
PCPointerWasDrawn = false;
beginningOfPCPointerLine = -1;
// ################################## Start of SP CODE ###########################
if (symbDebugEnabled)
{
loadNameFiles();
// ################################## End of SP CODE ###########################
disassembly_operands.resize(0);
}
si.nPos = addr;
SetScrollInfo(GetDlgItem(hWnd,scrollid),SB_CTL,&si,TRUE);
@ -418,8 +419,6 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
instruction_addr = addr;
// ################################## Start of SP CODE ###########################
if (symbDebugEnabled)
{
// insert Name and Comment lines if needed
@ -432,6 +431,7 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
strcat(debug_str, ":\r\n");
// we added one line to the disassembly window
disassembly_addresses.push_back(addr);
disassembly_operands.resize(i + 1);
i++;
}
if (node->comment)
@ -450,6 +450,7 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
strcat(debug_str, "\r\n");
// we added one line to the disassembly window
disassembly_addresses.push_back(addr);
disassembly_operands.resize(i + 1);
i++;
debug_decoration_comment_end_pos += 2;
@ -460,8 +461,6 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
}
}
// ################################## End of SP CODE ###########################
if (addr == X.PC)
{
PC_pointerOffset = instructions_count;
@ -490,6 +489,8 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
// Add address
strcat(debug_str, chr);
disassembly_addresses.push_back(addr);
if (symbDebugEnabled)
disassembly_operands.resize(i + 1);
size = opsize[GetMem(addr)];
if (size == 0)
@ -519,18 +520,14 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr)
size++;
}
// ################################## Start of SP CODE ###########################
a = Disassemble(addr, opcode);
if (symbDebugEnabled)
{
replaceNames(ramBankNames, a);
replaceNames(loadedBankNames, a);
replaceNames(lastBankNames, a);
replaceNames(ramBankNames, a, &disassembly_operands[i]);
replaceNames(loadedBankNames, a, &disassembly_operands[i]);
replaceNames(lastBankNames, a, &disassembly_operands[i]);
}
// ################################## End of SP CODE ###########################
// special case: an RTS opcode
if (GetMem(instruction_addr) == 0x60)
@ -1380,7 +1377,7 @@ void LoadGameDebuggerData(HWND hwndDlg = hDebug)
}
// returns the address, or EOF if selection cursor points to something else
int Debugger_CheckClickingOnAnAddress(bool onlyCheckWhenNothingSelected)
int Debugger_CheckClickingOnAnAddressOrSymbolicName(unsigned int lineNumber, bool onlyCheckWhenNothingSelected)
{
// debug_str contains the text in the disassembly window
int sel_start, sel_end;
@ -1388,6 +1385,7 @@ int Debugger_CheckClickingOnAnAddress(bool onlyCheckWhenNothingSelected)
if (onlyCheckWhenNothingSelected)
if (sel_end > sel_start)
return EOF;
// find the ":" or "$" before sel_start
int i = sel_start - 1;
for (; i > sel_start - 6; i--)
@ -1414,6 +1412,64 @@ int Debugger_CheckClickingOnAnAddress(bool onlyCheckWhenNothingSelected)
}
}
}
if (symbDebugEnabled && lineNumber < disassembly_addresses.size())
{
uint16 addr;
Name* node;
char* name;
int nameLen;
char* start_pos;
char* pos;
// first, try finding the name of disassembly_addresses[lineNumber]
addr = disassembly_addresses[lineNumber];
node = findNode(getNamesPointerForAddress(addr), addr);
if (node && node->name && *(node->name))
{
name = node->name;
nameLen = strlen(name);
if (sel_start - nameLen <= 0)
start_pos = debug_str;
else
start_pos = debug_str + (sel_start - nameLen);
pos = strstr(start_pos, name);
if (pos && pos <= debug_str + sel_start)
{
// clicked on the Name
// select the text
SendDlgItemMessage(hDebug, IDC_DEBUGGER_DISASSEMBLY, EM_SETSEL, (WPARAM)(int)(pos - debug_str), (LPARAM)((int)(pos - debug_str) + nameLen));
PrintOffsetToSeekAndBookmarkFields(addr);
return (int)addr;
}
}
// then, try finding the name of disassembly_operands
for (i = disassembly_operands[lineNumber].size() - 1; i >= 0; i--)
{
addr = disassembly_operands[lineNumber][i];
node = findNode(getNamesPointerForAddress(addr), addr);
if (node && node->name && *(node->name))
{
name = node->name;
nameLen = strlen(name);
if (sel_start - nameLen <= 0)
start_pos = debug_str;
else
start_pos = debug_str + (sel_start - nameLen);
pos = strstr(start_pos, name);
if (pos && pos <= debug_str + sel_start)
{
// clicked on the operand name
// select the text
SendDlgItemMessage(hDebug, IDC_DEBUGGER_DISASSEMBLY, EM_SETSEL, (WPARAM)(int)(pos - debug_str), (LPARAM)((int)(pos - debug_str) + nameLen));
PrintOffsetToSeekAndBookmarkFields(addr);
return (int)addr;
}
}
}
}
return EOF;
}
@ -1423,7 +1479,7 @@ BOOL CALLBACK IDC_DEBUGGER_DISASSEMBLY_WndProc(HWND hwndDlg, UINT uMsg, WPARAM w
{
case WM_LBUTTONDBLCLK:
{
int offset = Debugger_CheckClickingOnAnAddress(false);
int offset = Debugger_CheckClickingOnAnAddressOrSymbolicName(GET_Y_LPARAM(lParam) / debugSystem->fixedFontHeight, false);
if (offset != EOF)
{
// bring "Add Breakpoint" dialog
@ -1437,7 +1493,7 @@ BOOL CALLBACK IDC_DEBUGGER_DISASSEMBLY_WndProc(HWND hwndDlg, UINT uMsg, WPARAM w
}
case WM_LBUTTONUP:
{
Debugger_CheckClickingOnAnAddress(true);
Debugger_CheckClickingOnAnAddressOrSymbolicName(GET_Y_LPARAM(lParam) / debugSystem->fixedFontHeight, true);
break;
}
case WM_RBUTTONDOWN:
@ -1456,7 +1512,7 @@ BOOL CALLBACK IDC_DEBUGGER_DISASSEMBLY_WndProc(HWND hwndDlg, UINT uMsg, WPARAM w
case WM_RBUTTONUP:
{
// if nothing is selected, try bringing Symbolic Debug Naming dialog
int offset = Debugger_CheckClickingOnAnAddress(true);
int offset = Debugger_CheckClickingOnAnAddressOrSymbolicName(GET_Y_LPARAM(lParam) / debugSystem->fixedFontHeight, true);
if (offset != EOF)
{
if (DoSymbolicDebugNaming(offset, hDebug))

View File

@ -40,7 +40,7 @@ int lastBank = -1;
int loadedBank = -1;
extern char LoadedRomFName[2048];
char NLfilename[2048];
bool symbDebugEnabled = false;
bool symbDebugEnabled = true;
int debuggerWasActive = 0;
char temp_chr[40] = {0};
char delimiterChar[2] = "#";
@ -463,8 +463,9 @@ void freeList(Name* n)
*
* @param list NL list of address definitions
* @param str The string where replacing takes place.
* @param addressesLog Vector for collecting addresses that were replaced by names
**/
void replaceNames(Name* list, char* str)
void replaceNames(Name* list, char* str, std::vector<uint16>* addressesLog)
{
static char buff[1001];
char* pos;
@ -484,6 +485,8 @@ void replaceNames(Name* list, char* str)
strcat(buff, src);
strcat(buff, list->name);
src = pos + 5; // 5 = strlen(beg->offset), because all offsets are in "$XXXX" format
if (addressesLog)
addressesLog->push_back(list->offsetNumeric);
}
// if any offsets were changed, replace str by buff
if (*buff)
@ -544,15 +547,16 @@ char* generateNLFilenameForAddress(uint16 address)
}
Name* getNamesPointerForAddress(uint16 address)
{
if (address < 0x8000)
// this function is called very often (when using "Symbolic trace"), so this is sorted by frequency
if (address >= 0xC000)
{
return ramBankNames;
} else if (address < 0xC000)
return lastBankNames;
} else if (address >= 0x8000)
{
return loadedBankNames;
} else
{
return lastBankNames;
return ramBankNames;
}
}
void setNamesPointerForAddress(uint16 address, Name* newNode)
@ -907,8 +911,14 @@ void AddNewSymbolicName(uint16 newAddress, char* newOffset, char* newName, char*
node->offsetNumeric = newAddress;
node->name = (char*)malloc(strlen(newName) + 1);
strcpy(node->name, newName);
node->comment = (char*)malloc(strlen(newComment) + 1);
strcpy(node->comment, newComment);
if (strlen(newComment))
{
node->comment = (char*)malloc(strlen(newComment) + 1);
strcpy(node->comment, newComment);
} else
{
node->comment = 0;
}
node->next = 0;
setNamesPointerForAddress(newAddress, node);
} else
@ -919,12 +929,20 @@ void AddNewSymbolicName(uint16 newAddress, char* newOffset, char* newName, char*
if (node->offsetNumeric == newAddress)
{
// found matching address - replace its name and comment
free(node->name);
if (node->name)
free(node->name);
node->name = (char*)malloc(strlen(newName) + 1);
strcpy(node->name, newName);
free(node->comment);
node->comment = (char*)malloc(strlen(newComment) + 1);
strcpy(node->comment, newComment);
if (node->comment)
{
free(node->comment);
node->comment = 0;
}
if (strlen(newComment))
{
node->comment = (char*)malloc(strlen(newComment) + 1);
strcpy(node->comment, newComment);
}
break;
}
if (node->next)
@ -940,8 +958,14 @@ void AddNewSymbolicName(uint16 newAddress, char* newOffset, char* newName, char*
newNode->offsetNumeric = newAddress;
newNode->name = (char*)malloc(strlen(newName) + 1);
strcpy(newNode->name, newName);
newNode->comment = (char*)malloc(strlen(newComment) + 1);
strcpy(newNode->comment, newComment);
if (strlen(newComment))
{
newNode->comment = (char*)malloc(strlen(newComment) + 1);
strcpy(newNode->comment, newComment);
} else
{
newNode->comment = 0;
}
newNode->next = 0;
break;
}
@ -956,9 +980,12 @@ void AddNewSymbolicName(uint16 newAddress, char* newOffset, char* newName, char*
if (node->offsetNumeric == newAddress)
{
// found matching address - delete it
free(node->offset);
free(node->name);
free(node->comment);
if (node->offset)
free(node->offset);
if (node->name)
free(node->name);
if (node->comment)
free(node->comment);
if (previousNode)
previousNode->next = node->next;
if (node == initialNode)

View File

@ -47,7 +47,7 @@ char* generateNLFilenameForAddress(uint16 address);
Name* getNamesPointerForAddress(uint16 address);
void setNamesPointerForAddress(uint16 address, Name* newNode);
void loadNameFiles();
void replaceNames(Name* list, char* str);
void replaceNames(Name* list, char* str, std::vector<uint16>* addressesLog = 0);
void AddDebuggerBookmark(HWND hwnd);
void AddDebuggerBookmark2(HWND hwnd, unsigned int addr);
void DeleteDebuggerBookmark(HWND hwnd);

View File

@ -224,7 +224,7 @@ void AddLogText(const char *text, unsigned int add_newline)
// also log the text into Trace Logger log if needed
if (logging && (logging_options & LOG_MESSAGES))
{
OutputLogLine(strdup(logtext[truncated_logcount()]), add_newline != 0);
OutputLogLine(strdup(logtext[truncated_logcount()]), 0, add_newline != 0);
log_old_emu_paused = false; // force Trace Logger update
}

View File

@ -720,7 +720,7 @@ void UpdateColorTable()
temp_offset = CurOffset + i - 16; // (minus iNES header)
if (temp_offset >= 0)
{
if (temp_offset < cdloggerdataSize)
if ((unsigned int)temp_offset < cdloggerdataSize)
{
// PRG
if ((cdloggerdata[temp_offset] & 3) == 3)
@ -744,7 +744,7 @@ void UpdateColorTable()
} else
{
temp_offset -= cdloggerdataSize;
if ((temp_offset < cdloggerVideoDataSize))
if (((unsigned int)temp_offset < cdloggerVideoDataSize))
{
// CHR
if ((cdloggervdata[temp_offset] & 3) == 3)

View File

@ -67,7 +67,9 @@ char *logfilename = 0;
int oldcodecount, olddatacount;
SCROLLINFO tracesi;
char **tracelogbuf;
std::vector<std::vector<uint16>> tracelogbufAddressesLog;
int tracelogbufsize, tracelogbufpos;
int tracelogbufusedsize;
@ -79,6 +81,7 @@ char str_decoration[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0};
char str_decoration_comment[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0};
char* tracer_decoration_comment;
char* tracer_decoration_comment_end_pos;
std::vector<uint16> tempAddressesLog;
bool log_old_emu_paused = true; // thanks to this flag the window only updates once after the game is paused
extern bool JustFrameAdvanced;
@ -100,7 +103,7 @@ void EnableTracerMenuItems(void);
int PromptForCDLogger(void);
// returns the address, or EOF if selection cursor points to something else
int Tracer_CheckClickingOnAnAddress(bool onlyCheckWhenNothingSelected)
int Tracer_CheckClickingOnAnAddressOrSymbolicName(unsigned int lineNumber, bool onlyCheckWhenNothingSelected)
{
// trace_str contains the text in the log window
int sel_start, sel_end;
@ -108,6 +111,7 @@ int Tracer_CheckClickingOnAnAddress(bool onlyCheckWhenNothingSelected)
if (onlyCheckWhenNothingSelected)
if (sel_end > sel_start)
return EOF;
// find the "$" before sel_start
int i = sel_start - 1;
for (; i > sel_start - 6; i--)
@ -135,6 +139,45 @@ int Tracer_CheckClickingOnAnAddress(bool onlyCheckWhenNothingSelected)
}
}
}
if (tracelogbufusedsize == tracelogbufsize)
lineNumber = (tracelogbufpos + lineNumber) % tracelogbufsize;
if (lineNumber < tracelogbufAddressesLog.size())
{
uint16 addr;
Name* node;
char* name;
int nameLen;
char* start_pos;
char* pos;
for (i = tracelogbufAddressesLog[lineNumber].size() - 1; i >= 0; i--)
{
addr = tracelogbufAddressesLog[lineNumber][i];
node = findNode(getNamesPointerForAddress(addr), addr);
if (node && node->name && *(node->name))
{
name = node->name;
nameLen = strlen(name);
if (sel_start - nameLen <= 0)
start_pos = trace_str;
else
start_pos = trace_str + (sel_start - nameLen);
pos = strstr(start_pos, name);
if (pos && pos <= trace_str + sel_start)
{
// clicked on the operand name
// select the text
SendDlgItemMessage(hTracer, IDC_TRACER_LOG, EM_SETSEL, (WPARAM)(int)(pos - trace_str), (LPARAM)((int)(pos - trace_str) + nameLen));
if (hDebug)
PrintOffsetToSeekAndBookmarkFields(addr);
return (int)addr;
}
}
}
}
return EOF;
}
@ -144,7 +187,7 @@ BOOL CALLBACK IDC_TRACER_LOG_WndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA
{
case WM_LBUTTONDBLCLK:
{
int offset = Tracer_CheckClickingOnAnAddress(false);
int offset = Tracer_CheckClickingOnAnAddressOrSymbolicName(tracesi.nPos + (GET_Y_LPARAM(lParam) / debugSystem->fixedFontHeight), false);
if (offset != EOF)
{
// open Debugger at this address
@ -159,7 +202,7 @@ BOOL CALLBACK IDC_TRACER_LOG_WndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA
}
case WM_LBUTTONUP:
{
Tracer_CheckClickingOnAnAddress(true);
Tracer_CheckClickingOnAnAddressOrSymbolicName(tracesi.nPos + (GET_Y_LPARAM(lParam) / debugSystem->fixedFontHeight), true);
break;
}
case WM_RBUTTONDOWN:
@ -178,19 +221,11 @@ BOOL CALLBACK IDC_TRACER_LOG_WndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA
case WM_RBUTTONUP:
{
// if nothing is selected, try bringing Symbolic Debug Naming dialog
int offset = Tracer_CheckClickingOnAnAddress(true);
int offset = Tracer_CheckClickingOnAnAddressOrSymbolicName(tracesi.nPos + (GET_Y_LPARAM(lParam) / debugSystem->fixedFontHeight), true);
if (offset != EOF)
{
if (DoSymbolicDebugNaming(offset, hTracer))
{
/*
// enable "Symbolic trace" if not yet enabled
if (!(logging_options & LOG_SYMBOLIC))
{
logging_options |= LOG_SYMBOLIC;
CheckDlgButton(hTracer, IDC_CHECK_SYMBOLIC_TRACING, BST_CHECKED);
}
*/
if (hDebug)
UpdateDebugger(false);
if (hMemView)
@ -438,9 +473,10 @@ void BeginLoggingSequence(void)
char str2[100];
int i, j;
if(!PromptForCDLogger())return; //do nothing if user selected no and CD Logger is needed
if (!PromptForCDLogger())
return; //do nothing if user selected no and CD Logger is needed
if(logtofile)
if (logtofile)
{
if(logfilename == NULL) ShowLogDirDialog();
if (!logfilename) return;
@ -460,14 +496,16 @@ void BeginLoggingSequence(void)
strcpy(trace_str, "Allocating Memory...\r\n");
SetDlgItemText(hTracer, IDC_TRACER_LOG, trace_str);
tracelogbufsize = j = log_optn_intlst[log_lines_option];
tracelogbuf = (char**)malloc(j*sizeof(char *)); //mbg merge 7/19/06 added cast
for(i = 0;i < j;i++)
tracelogbuf = (char**)malloc(j * sizeof(char *));
for (i = 0;i < j;i++)
{
tracelogbuf[i] = (char*)malloc(LOG_LINE_MAX_LEN); //mbg merge 7/19/06 added cast
tracelogbuf[i] = (char*)malloc(LOG_LINE_MAX_LEN);
tracelogbuf[i][0] = 0;
}
sprintf(str2, "%d Bytes Allocated...\r\n", j * LOG_LINE_MAX_LEN);
strcat(trace_str, str2);
tracelogbufAddressesLog.resize(0);
tracelogbufAddressesLog.resize(tracelogbufsize);
// Assemble the message to pause the game. Uses the current hotkey mapping dynamically
strcat(trace_str, "Pause the game (press ");
strcat(trace_str, GetKeyComboName(FCEUD_CommandMapping[EMUCMD_PAUSE]));
@ -567,6 +605,7 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size)
{
if (logging_options & LOG_SYMBOLIC)
{
tempAddressesLog.resize(0);
// Insert Name and Comment lines if needed
Name* node = findNode(getNamesPointerForAddress(addr), addr);
if (node)
@ -575,7 +614,8 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size)
{
strcpy(str_decoration, node->name);
strcat(str_decoration, ":");
OutputLogLine(str_decoration, true);
tempAddressesLog.push_back(addr);
OutputLogLine(str_decoration, &tempAddressesLog);
}
if (node->comment)
{
@ -590,16 +630,17 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size)
tracer_decoration_comment_end_pos[0] = 0; // set \0 instead of \r
strcpy(str_decoration, "; ");
strcat(str_decoration, tracer_decoration_comment);
OutputLogLine(str_decoration, true);
OutputLogLine(str_decoration, &tempAddressesLog);
tracer_decoration_comment_end_pos += 2;
tracer_decoration_comment = tracer_decoration_comment_end_pos;
tracer_decoration_comment_end_pos = strstr(tracer_decoration_comment_end_pos, "\r\n");
}
}
}
replaceNames(ramBankNames, a);
replaceNames(loadedBankNames, a);
replaceNames(lastBankNames, a);
replaceNames(ramBankNames, a, &tempAddressesLog);
replaceNames(loadedBankNames, a, &tempAddressesLog);
replaceNames(lastBankNames, a, &tempAddressesLog);
}
strncpy(str_disassembly, a, LOG_DISASSEMBLY_MAX_LEN);
str_disassembly[LOG_DISASSEMBLY_MAX_LEN - 1] = 0;
@ -703,13 +744,14 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size)
strcat(str_result, str_procstatus);
}
OutputLogLine(str_result);
OutputLogLine(str_result, &tempAddressesLog);
return;
}
void OutputLogLine(const char *str, bool add_newline)
void OutputLogLine(const char *str, std::vector<uint16>* addressesLog, bool add_newline)
{
if(logtofile)
if (logtofile)
{
fputs(str, LOG_FP);
if (add_newline)
@ -727,6 +769,12 @@ void OutputLogLine(const char *str, bool add_newline)
strncpy(tracelogbuf[tracelogbufpos], str, LOG_LINE_MAX_LEN - 1);
tracelogbuf[tracelogbufpos][LOG_LINE_MAX_LEN - 1] = 0;
}
if (addressesLog)
tracelogbufAddressesLog[tracelogbufpos] = (*addressesLog);
else
tracelogbufAddressesLog[tracelogbufpos].resize(0);
tracelogbufpos++;
if (tracelogbufusedsize < tracelogbufsize)
tracelogbufusedsize++;
@ -734,19 +782,25 @@ void OutputLogLine(const char *str, bool add_newline)
}
}
void EndLoggingSequence(void){
void EndLoggingSequence(void)
{
int j, i;
if(logtofile){
if (logtofile)
{
fclose(LOG_FP);
} else {
} else
{
j = tracelogbufsize;
for(i = 0;i < j;i++){
for(i = 0;i < j;i++)
{
free(tracelogbuf[i]);
}
free(tracelogbuf);
tracelogbufAddressesLog.resize(0);
SetDlgItemText(hTracer, IDC_TRACER_LOG, "Welcome to the Trace Logger.");
}
logging=0;
logging = 0;
SetDlgItemText(hTracer, IDC_BTN_START_STOP_LOGGING,"Start Logging");
}
@ -803,10 +857,8 @@ void UpdateLogText(void)
for (; i < last_line; i++)
{
j = i;
if(tracelogbufusedsize == tracelogbufsize)
{
if (tracelogbufusedsize == tracelogbufsize)
j = (tracelogbufpos + i) % tracelogbufsize;
}
strcat(trace_str, tracelogbuf[j]);
}
SetDlgItemText(hTracer, IDC_TRACER_LOG, trace_str);

View File

@ -43,4 +43,4 @@ void EnableTracerMenuItems(void);
void LogInstruction(void);
void DoTracer();
void UpdateLogWindow(void);
void OutputLogLine(const char *str, bool add_newline = true);
void OutputLogLine(const char *str, std::vector<uint16>* addressesLog = 0, bool add_newline = true);