1 #include "disassembler.h"
2 #include "../plugins/assembler/algorithm/algorithm.h"
3 #include <algorithm>
4 #include <memory>
5
6 namespace REDasm {
7
Disassembler(AssemblerPlugin * assembler,LoaderPlugin * loader)8 Disassembler::Disassembler(AssemblerPlugin *assembler, LoaderPlugin *loader): DisassemblerBase(assembler, loader)
9 {
10 m_algorithm = REDasm::safe_ptr<AssemblerAlgorithm>(m_assembler->createAlgorithm(this));
11
12 m_analyzejob.setOneShot(true);
13 EVENT_CONNECT(&m_analyzejob, stateChanged, this, [&](Job*) { busyChanged(); });
14 m_analyzejob.work(std::bind(&Disassembler::analyzeStep, this), true); // Deferred
15 EVENT_CONNECT(&m_jobs, stateChanged, this, [&](Job*) { busyChanged(); });
16 }
17
disassembleStep(Job * job)18 void Disassembler::disassembleStep(Job* job)
19 {
20 if(m_algorithm->hasNext())
21 m_algorithm->next();
22 else
23 job->stop();
24
25 if(!m_jobs.active())
26 m_analyzejob.start();
27 }
28
analyzeStep()29 void Disassembler::analyzeStep()
30 {
31 m_algorithm->analyze();
32 auto duration = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - m_starttime);
33
34 if(duration.count())
35 {
36 std::stringstream ss;
37 ss << duration.count();
38 REDasm::log("Analysis completed in ~" + ss.str() + " second(s)");
39 }
40 else
41 REDasm::log("Analysis completed");
42 }
43
disassemble()44 void Disassembler::disassemble()
45 {
46 m_starttime = std::chrono::steady_clock::now();
47
48 if(!this->document()->segmentsCount())
49 {
50 REDasm::log("ERROR: Segment list is empty");
51 return;
52 }
53
54 const SymbolTable* symboltable = this->document()->symbols();
55
56 // Preload loader functions for analysis
57 symboltable->iterate(SymbolType::FunctionMask, [=](const Symbol* symbol) -> bool {
58 m_algorithm->enqueue(symbol->address);
59 return true;
60 });
61
62 const Symbol* entrypoint = this->document()->documentEntry();
63
64 if(entrypoint)
65 m_algorithm->enqueue(entrypoint->address); // Push entry point
66
67 REDasm::log("Disassembling with " + std::to_string(m_jobs.concurrency()) + " threads");
68 this->disassembleJob();
69 }
70
createPrinter()71 Printer *Disassembler::createPrinter() { return m_assembler->createPrinter(this); }
72
disassemble(address_t address)73 void Disassembler::disassemble(address_t address)
74 {
75 m_algorithm->enqueue(address);
76
77 if(m_jobs.active())
78 return;
79
80 this->disassembleJob();
81 }
82
stop()83 void Disassembler::stop() { m_jobs.stop(); }
pause()84 void Disassembler::pause() { m_jobs.pause(); }
resume()85 void Disassembler::resume() { m_jobs.resume(); }
state() const86 size_t Disassembler::state() const { return m_jobs.state(); }
busy() const87 bool Disassembler::busy() const { return m_analyzejob.active() || m_jobs.active(); }
disassembleJob()88 void Disassembler::disassembleJob() { m_jobs.work(std::bind(&Disassembler::disassembleStep, this, std::placeholders::_1)); }
89
disassembleInstruction(address_t address)90 InstructionPtr Disassembler::disassembleInstruction(address_t address)
91 {
92 InstructionPtr instruction = this->document()->instruction(address);
93
94 if(instruction)
95 return instruction;
96
97 instruction = std::make_shared<Instruction>();
98 m_algorithm->disassembleInstruction(address, instruction);
99 m_algorithm->done(address);
100 return instruction;
101 }
102
103 }
104