Implement infobox in trace browser
This commit is contained in:
parent
b0c2702a10
commit
e046b86901
|
@ -836,11 +836,7 @@ extern "C" DLL_EXPORT duint _dbg_getbranchdestination(duint addr)
|
|||
});
|
||||
if(cp.OpCount() && cp[0].type == ZYDIS_OPERAND_TYPE_MEMORY)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
auto const tebseg = ZYDIS_REGISTER_GS;
|
||||
#else
|
||||
auto const tebseg = ZYDIS_REGISTER_FS;
|
||||
#endif //_WIN64
|
||||
auto const tebseg = ArchValue(ZYDIS_REGISTER_FS, ZYDIS_REGISTER_GS);
|
||||
if(cp[0].mem.segment == tebseg)
|
||||
opValue += duint(GetTEBLocation(hActiveThread));
|
||||
if(MemRead(opValue, &opValue, sizeof(opValue)))
|
||||
|
|
|
@ -55,6 +55,11 @@ TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent)
|
|||
|
||||
TraceBrowser::~TraceBrowser()
|
||||
{
|
||||
if(mTraceFile)
|
||||
{
|
||||
mTraceFile->Close();
|
||||
delete mTraceFile;
|
||||
}
|
||||
delete mDisasm;
|
||||
}
|
||||
|
||||
|
@ -741,7 +746,7 @@ void TraceBrowser::mousePressEvent(QMouseEvent* event)
|
|||
setSingleSelection(index);
|
||||
mHistory.addVaToHistory(index);
|
||||
updateViewport();
|
||||
selectionChanged();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
return;
|
||||
|
||||
break;
|
||||
|
@ -873,20 +878,16 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event)
|
|||
mHistory.addVaToHistory(visibleindex);
|
||||
updateViewport();
|
||||
|
||||
selectionChanged();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
else
|
||||
AbstractTableView::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void TraceBrowser::selectionChanged()
|
||||
void TraceBrowser::onSelectionChanged(unsigned long long selection)
|
||||
{
|
||||
if(mAutoDisassemblyFollowSelection)
|
||||
followDisassemblySlot();
|
||||
|
||||
REGDUMP temp;
|
||||
temp = mTraceFile->Registers(getInitialSelection());
|
||||
emit updateTraceRegistersView(&temp);
|
||||
}
|
||||
|
||||
void TraceBrowser::tokenizerConfigUpdatedSlot()
|
||||
|
@ -1103,7 +1104,7 @@ void TraceBrowser::gotoNextSlot()
|
|||
setSingleSelection(index);
|
||||
makeVisible(index);
|
||||
updateViewport();
|
||||
selectionChanged();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1115,7 +1116,7 @@ void TraceBrowser::gotoPreviousSlot()
|
|||
setSingleSelection(index);
|
||||
makeVisible(index);
|
||||
updateViewport();
|
||||
selectionChanged();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1527,9 +1528,6 @@ void TraceBrowser::updateSlot()
|
|||
mTraceFile->purgeLastPage();
|
||||
setRowCount(mTraceFile->Length());
|
||||
}
|
||||
REGDUMP reg;
|
||||
reg = mTraceFile->Registers(getInitialSelection());
|
||||
emit updateTraceRegistersView(®);
|
||||
}
|
||||
else
|
||||
setRowCount(0);
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
duint getSelectionEnd();
|
||||
|
||||
bool isFileOpened() const;
|
||||
TraceFileReader* getTraceFile() { return mTraceFile; }
|
||||
|
||||
private:
|
||||
enum TableColumnIndex
|
||||
|
@ -48,7 +49,6 @@ private:
|
|||
void pushSelectionInto(bool copyBytes, QTextStream & stream, QTextStream* htmlStream = nullptr);
|
||||
void copySelectionSlot(bool copyBytes);
|
||||
void copySelectionToFileSlot(bool copyBytes);
|
||||
void selectionChanged();
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
|
@ -117,7 +117,7 @@ private:
|
|||
|
||||
signals:
|
||||
void displayReferencesWidget();
|
||||
void updateTraceRegistersView(void* registers);
|
||||
void selectionChanged(unsigned long long selection);
|
||||
|
||||
public slots:
|
||||
void openFileSlot();
|
||||
|
@ -127,6 +127,7 @@ public slots:
|
|||
void closeDeleteSlot();
|
||||
void parseFinishedSlot();
|
||||
void tokenizerConfigUpdatedSlot();
|
||||
void onSelectionChanged(unsigned long long selection);
|
||||
|
||||
void gotoSlot();
|
||||
void gotoPreviousSlot();
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "TraceWidget.h"
|
||||
#include "ui_TraceWidget.h"
|
||||
#include "TraceBrowser.h"
|
||||
#include "TraceFileReader.h"
|
||||
#include "TraceRegisters.h"
|
||||
#include "CPUInfoBox.h"
|
||||
#include "StdTable.h"
|
||||
|
||||
TraceWidget::TraceWidget(QWidget* parent) :
|
||||
QWidget(parent),
|
||||
|
@ -12,7 +13,7 @@ TraceWidget::TraceWidget(QWidget* parent) :
|
|||
|
||||
mTraceWidget = new TraceBrowser(this);
|
||||
mOverview = new StdTable(this);
|
||||
mInfo = new CPUInfoBox(this);
|
||||
mInfo = new StdTable(this);
|
||||
mGeneralRegs = new TraceRegisters(this);
|
||||
//disasm
|
||||
ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceWidget);
|
||||
|
@ -30,7 +31,7 @@ TraceWidget::TraceWidget(QWidget* parent) :
|
|||
QPushButton* button_changeview = new QPushButton("", this);
|
||||
button_changeview->setStyleSheet("Text-align:left;padding: 4px;padding-left: 10px;");
|
||||
connect(button_changeview, SIGNAL(clicked()), mGeneralRegs, SLOT(onChangeFPUViewAction()));
|
||||
connect(mTraceWidget, SIGNAL(updateTraceRegistersView(void*)), this, SLOT(updateTraceRegistersView(void*)));
|
||||
connect(mTraceWidget, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long)));
|
||||
connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot()));
|
||||
|
||||
mGeneralRegs->SetChangeButton(button_changeview);
|
||||
|
@ -39,13 +40,22 @@ TraceWidget::TraceWidget(QWidget* parent) :
|
|||
ui->mTopRightUpperFrameLayout->addWidget(upperScrollArea);
|
||||
//info
|
||||
ui->mTopLeftLowerFrameLayout->addWidget(mInfo);
|
||||
int height = mInfo->getHeight();
|
||||
int height = (mInfo->getRowHeight() + 1) * 4;
|
||||
ui->mTopLeftLowerFrame->setMinimumHeight(height + 2);
|
||||
|
||||
mInfo->addColumnAt(0, "", true);
|
||||
mInfo->setShowHeader(false);
|
||||
mInfo->setRowCount(4);
|
||||
mInfo->setCellContent(0, 0, QString());
|
||||
mInfo->setCellContent(1, 0, QString());
|
||||
mInfo->setCellContent(2, 0, QString());
|
||||
mInfo->setCellContent(3, 0, QString());
|
||||
//overview
|
||||
ui->mTopRightLowerFrameLayout->addWidget(mOverview);
|
||||
|
||||
//set up overview
|
||||
mOverview->addColumnAt(500, tr("Overview"), true);
|
||||
mOverview->addColumnAt(0, "", true);
|
||||
mOverview->setShowHeader(false);
|
||||
mOverview->setRowCount(4);
|
||||
mOverview->setCellContent(0, 0, "hello");
|
||||
mOverview->setCellContent(1, 0, "world");
|
||||
|
@ -58,9 +68,22 @@ TraceWidget::~TraceWidget()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void TraceWidget::updateTraceRegistersView(void* registers)
|
||||
void TraceWidget::traceSelectionChanged(unsigned long long selection)
|
||||
{
|
||||
mGeneralRegs->setRegisters((REGDUMP*)registers);
|
||||
REGDUMP registers;
|
||||
TraceFileReader* traceFile;
|
||||
traceFile = mTraceWidget->getTraceFile();
|
||||
if(traceFile != nullptr && traceFile->Progress() == 100)
|
||||
{
|
||||
if(selection < traceFile->Length())
|
||||
{
|
||||
registers = traceFile->Registers(selection);
|
||||
updateInfobox(selection, traceFile, registers);
|
||||
}
|
||||
else
|
||||
memset(®isters, 0, sizeof(registers));
|
||||
}
|
||||
mGeneralRegs->setRegisters(®isters);
|
||||
}
|
||||
|
||||
void TraceWidget::updateSlot()
|
||||
|
@ -72,3 +95,198 @@ TraceBrowser* TraceWidget::getTraceBrowser()
|
|||
{
|
||||
return mTraceWidget;
|
||||
}
|
||||
|
||||
void TraceWidget::updateInfobox(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers)
|
||||
{
|
||||
int infoline = 0;
|
||||
Zydis zydis;
|
||||
unsigned char opcode[16];
|
||||
QString line;
|
||||
int opsize;
|
||||
traceFile->OpCode(selection, opcode, &opsize);
|
||||
mInfo->setRowCount(4);
|
||||
mInfo->setCellContent(0, 0, QString());
|
||||
mInfo->setCellContent(1, 0, QString());
|
||||
mInfo->setCellContent(2, 0, QString());
|
||||
mInfo->setCellContent(3, 0, QString());
|
||||
auto resolveRegValue = [registers](ZydisRegister regname)
|
||||
{
|
||||
switch(regname)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
case ZYDIS_REGISTER_RAX:
|
||||
return registers.regcontext.cax;
|
||||
case ZYDIS_REGISTER_RCX:
|
||||
return registers.regcontext.ccx;
|
||||
case ZYDIS_REGISTER_RDX:
|
||||
return registers.regcontext.cdx;
|
||||
case ZYDIS_REGISTER_RBX:
|
||||
return registers.regcontext.cbx;
|
||||
case ZYDIS_REGISTER_RSP:
|
||||
return registers.regcontext.csp;
|
||||
case ZYDIS_REGISTER_RBP:
|
||||
return registers.regcontext.cbp;
|
||||
case ZYDIS_REGISTER_RSI:
|
||||
return registers.regcontext.csi;
|
||||
case ZYDIS_REGISTER_RDI:
|
||||
return registers.regcontext.cdi;
|
||||
case ZYDIS_REGISTER_R8:
|
||||
return registers.regcontext.r8;
|
||||
case ZYDIS_REGISTER_R9:
|
||||
return registers.regcontext.r9;
|
||||
case ZYDIS_REGISTER_R10:
|
||||
return registers.regcontext.r10;
|
||||
case ZYDIS_REGISTER_R11:
|
||||
return registers.regcontext.r11;
|
||||
case ZYDIS_REGISTER_R12:
|
||||
return registers.regcontext.r12;
|
||||
case ZYDIS_REGISTER_R13:
|
||||
return registers.regcontext.r13;
|
||||
case ZYDIS_REGISTER_R14:
|
||||
return registers.regcontext.r14;
|
||||
case ZYDIS_REGISTER_R15:
|
||||
return registers.regcontext.r15;
|
||||
case ZYDIS_REGISTER_R8D:
|
||||
return registers.regcontext.r8 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R9D:
|
||||
return registers.regcontext.r9 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R10D:
|
||||
return registers.regcontext.r10 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R11D:
|
||||
return registers.regcontext.r11 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R12D:
|
||||
return registers.regcontext.r12 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R13D:
|
||||
return registers.regcontext.r13 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R15D:
|
||||
return registers.regcontext.r15 & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_R8W:
|
||||
return registers.regcontext.r8 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R9W:
|
||||
return registers.regcontext.r9 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R10W:
|
||||
return registers.regcontext.r10 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R11W:
|
||||
return registers.regcontext.r11 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R12W:
|
||||
return registers.regcontext.r12 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R13W:
|
||||
return registers.regcontext.r13 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R15W:
|
||||
return registers.regcontext.r15 & 0xFFFF;
|
||||
case ZYDIS_REGISTER_R8B:
|
||||
return registers.regcontext.r8 & 0xFF;
|
||||
case ZYDIS_REGISTER_R9B:
|
||||
return registers.regcontext.r9 & 0xFF;
|
||||
case ZYDIS_REGISTER_R10B:
|
||||
return registers.regcontext.r10 & 0xFF;
|
||||
case ZYDIS_REGISTER_R11B:
|
||||
return registers.regcontext.r11 & 0xFF;
|
||||
case ZYDIS_REGISTER_R12B:
|
||||
return registers.regcontext.r12 & 0xFF;
|
||||
case ZYDIS_REGISTER_R13B:
|
||||
return registers.regcontext.r13 & 0xFF;
|
||||
case ZYDIS_REGISTER_R15B:
|
||||
return registers.regcontext.r15 & 0xFF;
|
||||
#endif //_WIN64
|
||||
case ZYDIS_REGISTER_EAX:
|
||||
return registers.regcontext.cax & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_ECX:
|
||||
return registers.regcontext.ccx & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_EDX:
|
||||
return registers.regcontext.cdx & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_EBX:
|
||||
return registers.regcontext.cbx & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_ESP:
|
||||
return registers.regcontext.csp & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_EBP:
|
||||
return registers.regcontext.cbp & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_ESI:
|
||||
return registers.regcontext.csi & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_EDI:
|
||||
return registers.regcontext.cdi & 0xFFFFFFFF;
|
||||
case ZYDIS_REGISTER_AX:
|
||||
return registers.regcontext.cax & 0xFFFF;
|
||||
case ZYDIS_REGISTER_CX:
|
||||
return registers.regcontext.ccx & 0xFFFF;
|
||||
case ZYDIS_REGISTER_DX:
|
||||
return registers.regcontext.cdx & 0xFFFF;
|
||||
case ZYDIS_REGISTER_BX:
|
||||
return registers.regcontext.cbx & 0xFFFF;
|
||||
case ZYDIS_REGISTER_SP:
|
||||
return registers.regcontext.csp & 0xFFFF;
|
||||
case ZYDIS_REGISTER_BP:
|
||||
return registers.regcontext.cbp & 0xFFFF;
|
||||
case ZYDIS_REGISTER_SI:
|
||||
return registers.regcontext.csi & 0xFFFF;
|
||||
case ZYDIS_REGISTER_DI:
|
||||
return registers.regcontext.cdi & 0xFFFF;
|
||||
case ZYDIS_REGISTER_AL:
|
||||
return registers.regcontext.cax & 0xFF;
|
||||
case ZYDIS_REGISTER_CL:
|
||||
return registers.regcontext.ccx & 0xFF;
|
||||
case ZYDIS_REGISTER_DL:
|
||||
return registers.regcontext.cdx & 0xFF;
|
||||
case ZYDIS_REGISTER_BL:
|
||||
return registers.regcontext.cbx & 0xFF;
|
||||
case ZYDIS_REGISTER_AH:
|
||||
return (registers.regcontext.cax & 0xFF00) >> 8;
|
||||
case ZYDIS_REGISTER_CH:
|
||||
return (registers.regcontext.ccx & 0xFF00) >> 8;
|
||||
case ZYDIS_REGISTER_DH:
|
||||
return (registers.regcontext.cdx & 0xFF00) >> 8;
|
||||
case ZYDIS_REGISTER_BH:
|
||||
return (registers.regcontext.cbx & 0xFF00) >> 8;
|
||||
default:
|
||||
return static_cast<size_t>(0);
|
||||
}
|
||||
};
|
||||
if(zydis.Disassemble(registers.regcontext.cip, opcode, opsize))
|
||||
{
|
||||
int opindex;
|
||||
//Jumps
|
||||
if(zydis.IsBranchType(Zydis::BTCondJmp))
|
||||
{
|
||||
if(zydis.IsBranchGoingToExecute(registers.regcontext.eflags, registers.regcontext.ccx))
|
||||
{
|
||||
line = tr("Jump is taken");
|
||||
}
|
||||
else
|
||||
{
|
||||
line = tr("Jump is not taken");
|
||||
}
|
||||
mInfo->setCellContent(infoline, 0, line);
|
||||
infoline++;
|
||||
}
|
||||
//Operands
|
||||
for(opindex = 0; opindex < zydis.OpCount(); opindex++)
|
||||
{
|
||||
line.clear();
|
||||
size_t value = zydis.ResolveOpValue(opindex, resolveRegValue);
|
||||
if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY)
|
||||
{
|
||||
const char* memsize = zydis.MemSizeName(zydis[opindex].size / 8);
|
||||
if(memsize != nullptr)
|
||||
{
|
||||
line += memsize;
|
||||
}
|
||||
line += " ptr ";
|
||||
line += zydis.RegName(zydis[opindex].mem.segment);
|
||||
line += ":[";
|
||||
line += ToPtrString(value);
|
||||
line += "]";
|
||||
mInfo->setCellContent(infoline, 0, line);
|
||||
infoline++;
|
||||
}
|
||||
else if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_REGISTER)
|
||||
{
|
||||
line += zydis.RegName(zydis[opindex].reg.value);
|
||||
line += " = ";
|
||||
line += ToPtrString(value);
|
||||
mInfo->setCellContent(infoline, 0, line);
|
||||
infoline++;
|
||||
}
|
||||
}
|
||||
}
|
||||
mInfo->reloadData();
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
#define TRACEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "Bridge.h"
|
||||
|
||||
class QVBoxLayout;
|
||||
class CPUWidget;
|
||||
class TraceRegisters;
|
||||
class TraceBrowser;
|
||||
class CPUInfoBox;
|
||||
class TraceFileReader;
|
||||
class StdTable;
|
||||
|
||||
namespace Ui
|
||||
|
@ -26,15 +27,17 @@ public:
|
|||
TraceBrowser* getTraceBrowser();
|
||||
|
||||
protected slots:
|
||||
void updateTraceRegistersView(void* registers);
|
||||
void traceSelectionChanged(unsigned long long selection);
|
||||
void updateSlot();
|
||||
|
||||
protected:
|
||||
TraceBrowser* mTraceWidget;
|
||||
TraceRegisters* mGeneralRegs;
|
||||
CPUInfoBox* mInfo;
|
||||
StdTable* mInfo;
|
||||
StdTable* mOverview;
|
||||
|
||||
void updateInfobox(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers);
|
||||
|
||||
private:
|
||||
Ui::TraceWidget* ui;
|
||||
};
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
<number>1</number>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QFrame" name="mTopLeftUpperRightFrame">
|
||||
<property name="frameShape">
|
||||
|
@ -95,6 +95,12 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<widget class="QFrame" name="mTopLeftLowerFrame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
|
@ -137,6 +143,12 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QFrame" name="mTopRightUpperFrame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
|
@ -162,6 +174,12 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<widget class="QFrame" name="mTopRightLowerFrame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
|
|
|
@ -560,7 +560,7 @@ bool Zydis::IsNop() const
|
|||
case ZYDIS_MNEMONIC_JRCXZ:
|
||||
case ZYDIS_MNEMONIC_JS:
|
||||
case ZYDIS_MNEMONIC_JZ:
|
||||
// jmp 0
|
||||
// jmp $0
|
||||
return ops[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE
|
||||
&& ops[0].imm.value.u == this->Address() + this->Size();
|
||||
case ZYDIS_MNEMONIC_SHL:
|
||||
|
@ -615,7 +615,9 @@ bool Zydis::IsUnusual() const
|
|||
|| id == ZYDIS_MNEMONIC_RDRAND
|
||||
|| id == ZYDIS_MNEMONIC_RDSEED
|
||||
|| id == ZYDIS_MNEMONIC_UD1
|
||||
|| id == ZYDIS_MNEMONIC_UD2;
|
||||
|| id == ZYDIS_MNEMONIC_UD2
|
||||
|| id == ZYDIS_MNEMONIC_VMCALL
|
||||
|| id == ZYDIS_MNEMONIC_VMFUNC;
|
||||
}
|
||||
|
||||
std::string Zydis::Mnemonic() const
|
||||
|
|
Loading…
Reference in New Issue