source: CLRX/CLRadeonExtender/trunk/amdasm/Disassembler.cpp @ 2516

Last change on this file since 2516 was 2516, checked in by matszpk, 3 years ago

CLRadeonExtender: Small fixes in ROCmBinaries. remove obsolete flags arguments from getGalliumDisasmInputFromBinary.
First code in DisasmROCm. Add ROCm to binary type list.

File size: 19.2 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <string>
22#include <cstring>
23#include <ostream>
24#include <cstring>
25#include <memory>
26#include <vector>
27#include <utility>
28#include <algorithm>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/amdbin/GalliumBinaries.h>
31#include <CLRX/utils/MemAccess.h>
32#include <CLRX/utils/GPUId.h>
33#include <CLRX/amdasm/Disassembler.h>
34#include "DisasmInternals.h"
35
36using namespace CLRX;
37
38ISADisassembler::ISADisassembler(Disassembler& _disassembler, cxuint outBufSize)
39        : disassembler(_disassembler), output(outBufSize, _disassembler.getOutput())
40{ }
41
42ISADisassembler::~ISADisassembler()
43{ }
44
45void ISADisassembler::writeLabelsToPosition(size_t pos, LabelIter& labelIter,
46              NamedLabelIter& namedLabelIter)
47{
48    if ((namedLabelIter != namedLabels.end() && namedLabelIter->first <= pos) ||
49            (labelIter != labels.end() && *labelIter <= pos))
50    {
51        size_t curPos = SIZE_MAX;
52        if (labelIter != labels.end())
53            curPos = *labelIter;
54        if (namedLabelIter != namedLabels.end())
55            curPos = std::min(curPos, namedLabelIter->first);
56       
57        bool haveLabel;
58        do {
59            haveLabel = false;
60            const bool haveNumberedLabel =
61                    labelIter != labels.end() && *labelIter <= pos;
62            const bool haveNamedLabel =
63                    (namedLabelIter != namedLabels.end() && namedLabelIter->first <= pos);
64           
65            size_t namedPos = SIZE_MAX;
66            size_t numberedPos = SIZE_MAX;
67            if (haveNumberedLabel)
68                numberedPos = *labelIter;
69            if (haveNamedLabel)
70                namedPos = namedLabelIter->first;
71           
72            /// print numbered (not named) label in form .L[position]_[sectionCount]
73            if (numberedPos <= namedPos && haveNumberedLabel)
74            {
75                curPos = *labelIter;
76                char* buf = output.reserve(70);
77                size_t bufPos = 0;
78                buf[bufPos++] = '.';
79                buf[bufPos++] = 'L';
80                bufPos += itocstrCStyle(*labelIter, buf+bufPos, 22, 10, 0, false);
81                buf[bufPos++] = '_';
82                bufPos += itocstrCStyle(disassembler.sectionCount,
83                                buf+bufPos, 22, 10, 0, false);
84                if (curPos != pos)
85                {   // if label shifted back by some bytes before encoded instruction
86                    buf[bufPos++] = '=';
87                    buf[bufPos++] = '.';
88                    buf[bufPos++] = '-';
89                    bufPos += itocstrCStyle((pos-curPos), buf+bufPos, 22, 10, 0, false);
90                    buf[bufPos++] = '\n';
91                }
92                else
93                {
94                    buf[bufPos++] = ':';
95                    buf[bufPos++] = '\n';
96                }
97                output.forward(bufPos);
98                ++labelIter;
99                haveLabel = true;
100            }
101           
102            /// print named label
103            if(namedPos <= numberedPos && haveNamedLabel)
104            {
105                curPos = namedLabelIter->first;
106                output.write(namedLabelIter->second.size(),
107                       namedLabelIter->second.c_str());
108                char* buf = output.reserve(50);
109                size_t bufPos = 0;
110                if (curPos != pos)
111                {   // if label shifted back by some bytes before encoded instruction
112                    buf[bufPos++] = '=';
113                    buf[bufPos++] = '.';
114                    buf[bufPos++] = '-';
115                    bufPos += itocstrCStyle((pos-curPos), buf+bufPos, 22, 10, 0, false);
116                    buf[bufPos++] = '\n';
117                }
118                else
119                {
120                    buf[bufPos++] = ':';
121                    buf[bufPos++] = '\n';
122                }
123                output.forward(bufPos);
124                ++namedLabelIter;
125                haveLabel = true;
126            }
127           
128        } while(haveLabel);
129    }
130}
131
132void ISADisassembler::writeLabelsToEnd(size_t start, LabelIter labelIter,
133                   NamedLabelIter namedLabelIter)
134{
135    size_t pos = start;
136    while (namedLabelIter != namedLabels.end() || labelIter != labels.end())
137    {
138        size_t namedPos = SIZE_MAX;
139        size_t numberedPos = SIZE_MAX;
140        if (labelIter != labels.end())
141            numberedPos = *labelIter;
142        if (namedLabelIter != namedLabels.end())
143            namedPos = namedLabelIter->first;
144        if (numberedPos <= namedPos && labelIter != labels.end())
145        {
146            if (pos != *labelIter)
147            {   // print shift position to label (.org pseudo-op)
148                char* buf = output.reserve(30);
149                size_t bufPos = 0;
150                memcpy(buf+bufPos, ".org ", 5);
151                bufPos += 5;
152                bufPos += itocstrCStyle(*labelIter, buf+bufPos, 20, 16);
153                buf[bufPos++] = '\n';
154                output.forward(bufPos);
155            }
156            char* buf = output.reserve(50);
157            size_t bufPos = 0;
158            buf[bufPos++] = '.';
159            buf[bufPos++] = 'L';
160            bufPos += itocstrCStyle(*labelIter, buf+bufPos, 22, 10, 0, false);
161            buf[bufPos++] = '_';
162            bufPos += itocstrCStyle(disassembler.sectionCount,
163                            buf+bufPos, 22, 10, 0, false);
164            buf[bufPos++] = ':';
165            buf[bufPos++] = '\n';
166            output.forward(bufPos);
167            pos = *labelIter;
168            ++labelIter;
169        }
170        if (namedPos <= numberedPos && namedLabelIter != namedLabels.end())
171        {
172            if (pos != namedLabelIter->first)
173            {   // print shift position to label (.org pseudo-op)
174                char* buf = output.reserve(30);
175                size_t bufPos = 0;
176                memcpy(buf+bufPos, ".org ", 5);
177                bufPos += 5;
178                bufPos += itocstrCStyle(namedLabelIter->first, buf+bufPos, 20, 16);
179                buf[bufPos++] = '\n';
180                output.forward(bufPos);
181            }
182            output.write(namedLabelIter->second.size(),
183                        namedLabelIter->second.c_str());
184            pos = namedLabelIter->first;
185            ++namedLabelIter;
186        }
187    }
188}
189
190void ISADisassembler::writeLocation(size_t pos)
191{
192    const auto namedLabelIt = binaryMapFind(namedLabels.begin(), namedLabels.end(), pos);
193    if (namedLabelIt != namedLabels.end())
194    {   /* print named label */
195        output.write(namedLabelIt->second.size(), namedLabelIt->second.c_str());
196        return;
197    }
198    /* otherwise we print numbered label */
199    char* buf = output.reserve(50);
200    size_t bufPos = 0;
201    buf[bufPos++] = '.';
202    buf[bufPos++] = 'L';
203    bufPos += itocstrCStyle(pos, buf+bufPos, 22, 10, 0, false);
204    buf[bufPos++] = '_';
205    bufPos += itocstrCStyle(disassembler.sectionCount, buf+bufPos, 22, 10, 0, false);
206    output.forward(bufPos);
207}
208
209bool ISADisassembler::writeRelocation(size_t pos, RelocIter& relocIter)
210{
211    while (relocIter != relocations.end() && relocIter->first < pos)
212        relocIter++;
213    if (relocIter == relocations.end() || relocIter->first != pos)
214        return false;
215    const Relocation& reloc = relocIter->second;
216    if (reloc.addend != 0 && 
217        (reloc.type==RELTYPE_LOW_32BIT || reloc.type==RELTYPE_HIGH_32BIT))
218        output.write(1, "(");
219    /// write name+value
220    output.writeString(relSymbols[reloc.symbol].c_str());
221    char* buf = output.reserve(50);
222    size_t bufPos = 0;
223    if (reloc.addend != 0)
224    {
225        if (reloc.addend > 0)
226            buf[bufPos++] = '+';
227        bufPos += itocstrCStyle(reloc.addend, buf+bufPos, 22, 10, 0, false);
228        if (reloc.type==RELTYPE_LOW_32BIT || reloc.type==RELTYPE_HIGH_32BIT)
229            buf[bufPos++] = ')';
230    }
231    if (reloc.type==RELTYPE_LOW_32BIT)
232    {
233        ::memcpy(buf+bufPos, "&0xffffffff", 11);
234        bufPos += 11;
235    }
236    else if (reloc.type==RELTYPE_HIGH_32BIT)
237    {
238        ::memcpy(buf+bufPos, ">>32", 4);
239        bufPos += 4;
240    }
241    output.forward(bufPos);
242    ++relocIter;
243    return true;
244}
245
246Disassembler::Disassembler(const AmdMainGPUBinary32& binary, std::ostream& _output,
247            Flags _flags) : fromBinary(true), binaryFormat(BinaryFormat::AMD),
248            amdInput(nullptr), output(_output), flags(_flags), sectionCount(0)
249{
250    isaDisassembler.reset(new GCNDisassembler(*this));
251    amdInput = getAmdDisasmInputFromBinary32(binary, flags);
252}
253
254Disassembler::Disassembler(const AmdMainGPUBinary64& binary, std::ostream& _output,
255            Flags _flags) : fromBinary(true), binaryFormat(BinaryFormat::AMD),
256            amdInput(nullptr), output(_output), flags(_flags), sectionCount(0)
257{
258    isaDisassembler.reset(new GCNDisassembler(*this));
259    amdInput = getAmdDisasmInputFromBinary64(binary, flags);
260}
261
262Disassembler::Disassembler(const AmdCL2MainGPUBinary& binary, std::ostream& _output,
263           Flags _flags) : fromBinary(true), binaryFormat(BinaryFormat::AMDCL2),
264            amdCL2Input(nullptr), output(_output), flags(_flags), sectionCount(0)
265{
266    isaDisassembler.reset(new GCNDisassembler(*this));
267    amdCL2Input = getAmdCL2DisasmInputFromBinary(binary);
268}
269
270Disassembler::Disassembler(const AmdDisasmInput* disasmInput, std::ostream& _output,
271            Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::AMD),
272            amdInput(disasmInput), output(_output), flags(_flags), sectionCount(0)
273{
274    isaDisassembler.reset(new GCNDisassembler(*this));
275}
276
277Disassembler::Disassembler(const AmdCL2DisasmInput* disasmInput, std::ostream& _output,
278            Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::AMDCL2),
279            amdCL2Input(disasmInput), output(_output), flags(_flags), sectionCount(0)
280{
281    isaDisassembler.reset(new GCNDisassembler(*this));
282}
283
284Disassembler::Disassembler(GPUDeviceType deviceType, const GalliumBinary& binary,
285           std::ostream& _output, Flags _flags) :
286           fromBinary(true), binaryFormat(BinaryFormat::GALLIUM),
287           galliumInput(nullptr), output(_output), flags(_flags), sectionCount(0)
288{
289    isaDisassembler.reset(new GCNDisassembler(*this));
290    galliumInput = getGalliumDisasmInputFromBinary(deviceType, binary);
291}
292
293Disassembler::Disassembler(const GalliumDisasmInput* disasmInput, std::ostream& _output,
294             Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::GALLIUM),
295            galliumInput(disasmInput), output(_output), flags(_flags), sectionCount(0)
296{
297    isaDisassembler.reset(new GCNDisassembler(*this));
298}
299
300Disassembler::Disassembler(GPUDeviceType deviceType, size_t rawCodeSize,
301           const cxbyte* rawCode, std::ostream& _output, Flags _flags)
302       : fromBinary(true), binaryFormat(BinaryFormat::RAWCODE),
303         output(_output), flags(_flags), sectionCount(0)
304{
305    isaDisassembler.reset(new GCNDisassembler(*this));
306    rawInput = new RawCodeInput{ deviceType, rawCodeSize, rawCode };
307}
308
309Disassembler::~Disassembler()
310{
311    if (fromBinary)
312    {
313        if (binaryFormat == BinaryFormat::AMD)
314            delete amdInput;
315        else if (binaryFormat == BinaryFormat::GALLIUM)
316            delete galliumInput;
317        else if (binaryFormat == BinaryFormat::AMDCL2)
318            delete amdCL2Input;
319        else // raw code input
320            delete rawInput;
321    }
322}
323
324GPUDeviceType Disassembler::getDeviceType() const
325{
326    if (binaryFormat == BinaryFormat::AMD)
327        return amdInput->deviceType;
328    else if (binaryFormat == BinaryFormat::AMDCL2)
329        return amdCL2Input->deviceType;
330    else if (binaryFormat == BinaryFormat::GALLIUM)
331        return galliumInput->deviceType;
332    else // rawcode
333        return rawInput->deviceType;
334}
335
336extern void CLRX::printDisasmData(size_t size, const cxbyte* data, std::ostream& output,
337                bool secondAlign)
338{
339    char buf[68];
340    /// const strings for .byte and fill pseudo-ops
341    const char* linePrefix = "    .byte ";
342    const char* fillPrefix = "    .fill ";
343    size_t prefixSize = 10;
344    if (secondAlign)
345    {   // const string for double alignment
346        linePrefix = "        .byte ";
347        fillPrefix = "        .fill ";
348        prefixSize += 4;
349    }
350    ::memcpy(buf, linePrefix, prefixSize);
351    for (size_t p = 0; p < size;)
352    {
353        size_t fillEnd;
354        // find max repetition of this element
355        for (fillEnd = p+1; fillEnd < size && data[fillEnd]==data[p]; fillEnd++);
356        if (fillEnd >= p+8)
357        {   // if element repeated for least 1 line
358            // print .fill pseudo-op
359            ::memcpy(buf, fillPrefix, prefixSize);
360            const size_t oldP = p;
361            p = (fillEnd != size) ? fillEnd&~size_t(7) : fillEnd;
362            size_t bufPos = prefixSize;
363            bufPos += itocstrCStyle(p-oldP, buf+bufPos, 22, 10);
364            memcpy(buf+bufPos, ", 1, ", 5);
365            bufPos += 5;
366            bufPos += itocstrCStyle(data[oldP], buf+bufPos, 6, 16, 2);
367            buf[bufPos++] = '\n';
368            output.write(buf, bufPos);
369            ::memcpy(buf, linePrefix, prefixSize);
370            continue;
371        }
372       
373        const size_t lineEnd = std::min(p+8, size);
374        size_t bufPos = prefixSize;
375        // print 8 or less (if end of data) bytes
376        for (; p < lineEnd; p++)
377        {
378            buf[bufPos++] = '0';
379            buf[bufPos++] = 'x';
380            {   // inline byte in hexadecimal
381                cxuint digit = data[p]>>4;
382                if (digit < 10)
383                    buf[bufPos++] = '0'+digit;
384                else
385                    buf[bufPos++] = 'a'+digit-10;
386                digit = data[p]&0xf;
387                if (digit < 10)
388                    buf[bufPos++] = '0'+digit;
389                else
390                    buf[bufPos++] = 'a'+digit-10;
391            }
392            if (p+1 < lineEnd)
393            {
394                buf[bufPos++] = ',';
395                buf[bufPos++] = ' ';
396            }
397        }
398        buf[bufPos++] = '\n';
399        output.write(buf, bufPos);
400    }
401}
402
403void CLRX::printDisasmDataU32(size_t size, const uint32_t* data, std::ostream& output,
404                bool secondAlign)
405{
406    char buf[68];
407    /// const strings for .byte and fill pseudo-ops
408    const char* linePrefix = "    .int ";
409    const char* fillPrefix = "    .fill ";
410    size_t fillPrefixSize = 10;
411    if (secondAlign)
412    {   // const string for double alignment
413        linePrefix = "        .int ";
414        fillPrefix = "        .fill ";
415        fillPrefixSize += 4;
416    }
417    const size_t intPrefixSize = fillPrefixSize-1;
418    ::memcpy(buf, linePrefix, intPrefixSize);
419    for (size_t p = 0; p < size;)
420    {
421        size_t fillEnd;
422        // find max repetition of this char
423        for (fillEnd = p+1; fillEnd < size && ULEV(data[fillEnd])==ULEV(data[p]);
424             fillEnd++);
425        if (fillEnd >= p+4)
426        {   // if element repeated for least 1 line
427            // print .fill pseudo-op
428            ::memcpy(buf, fillPrefix, fillPrefixSize);
429            const size_t oldP = p;
430            p = (fillEnd != size) ? fillEnd&~size_t(3) : fillEnd;
431            size_t bufPos = fillPrefixSize;
432            bufPos += itocstrCStyle(p-oldP, buf+bufPos, 22, 10);
433            memcpy(buf+bufPos, ", 4, ", 5);
434            bufPos += 5;
435            bufPos += itocstrCStyle(ULEV(data[oldP]), buf+bufPos, 12, 16, 8);
436            buf[bufPos++] = '\n';
437            output.write(buf, bufPos);
438            ::memcpy(buf, linePrefix, fillPrefixSize);
439            continue;
440        }
441       
442        const size_t lineEnd = std::min(p+4, size);
443        size_t bufPos = intPrefixSize;
444        // print four or less (if end of data) dwords
445        for (; p < lineEnd; p++)
446        {
447            bufPos += itocstrCStyle(ULEV(data[p]), buf+bufPos, 12, 16, 8);
448            if (p+1 < lineEnd)
449            {
450                buf[bufPos++] = ',';
451                buf[bufPos++] = ' ';
452            }
453        }
454        buf[bufPos++] = '\n';
455        output.write(buf, bufPos);
456    }
457}
458
459void CLRX::printDisasmLongString(size_t size, const char* data, std::ostream& output,
460            bool secondAlign)
461{
462   
463    const char* linePrefix = "    .ascii \"";
464    size_t prefixSize = 12;
465    if (secondAlign)
466    {
467        linePrefix = "        .ascii \"";
468        prefixSize += 4;
469    }
470    char buffer[96];
471    ::memcpy(buffer, linePrefix, prefixSize);
472   
473    for (size_t pos = 0; pos < size; )
474    {
475        const size_t end = std::min(pos+72, size);
476        const size_t oldPos = pos;
477        while (pos < end && data[pos] != '\n') pos++;
478        if (pos < end && data[pos] == '\n') pos++; // embrace newline
479        size_t escapeSize;
480        pos = oldPos + escapeStringCStyle(pos-oldPos, data+oldPos, 76,
481                      buffer+prefixSize, escapeSize);
482        buffer[prefixSize+escapeSize] = '\"';
483        buffer[prefixSize+escapeSize+1] = '\n';
484        output.write(buffer, prefixSize+escapeSize+2);
485    }
486}
487
488static void disassembleRawCode(std::ostream& output, const RawCodeInput* rawInput,
489       ISADisassembler* isaDisassembler, size_t& sectionCount, Flags flags)
490{
491    if ((flags & DISASM_DUMPCODE) != 0)
492    {
493        output.write(".text\n", 6);
494        isaDisassembler->setInput(rawInput->codeSize, rawInput->code);
495        isaDisassembler->beforeDisassemble();
496        isaDisassembler->disassemble();
497    }
498}
499
500void Disassembler::disassemble()
501{
502    const std::ios::iostate oldExceptions = output.exceptions();
503    output.exceptions(std::ios::failbit | std::ios::badbit);
504    try
505    {
506    if (binaryFormat == BinaryFormat::AMD)
507        output.write(".amd\n", 5);
508    else if (binaryFormat == BinaryFormat::AMDCL2)
509        output.write(".amdcl2\n", 8);
510    else if (binaryFormat == BinaryFormat::GALLIUM) // Gallium
511        output.write(".gallium\n", 9);
512    else // raw code
513        output.write(".rawcode\n", 9);
514   
515    const GPUDeviceType deviceType = getDeviceType();
516    output.write(".gpu ", 5);
517    const char* gpuName = getGPUDeviceTypeName(deviceType);
518    output.write(gpuName, ::strlen(gpuName));
519    output.put('\n');
520   
521    if (binaryFormat == BinaryFormat::AMD)
522        disassembleAmd(output, amdInput, isaDisassembler.get(), sectionCount, flags);
523    else if (binaryFormat == BinaryFormat::AMDCL2)
524        disassembleAmdCL2(output, amdCL2Input, isaDisassembler.get(), sectionCount, flags);
525    else if (binaryFormat == BinaryFormat::GALLIUM) // Gallium
526        disassembleGallium(output, galliumInput, isaDisassembler.get(),
527                   sectionCount, flags);
528    else // raw code input
529        disassembleRawCode(output, rawInput, isaDisassembler.get(), sectionCount, flags);
530    output.flush();
531    } /* try catch */
532    catch(...)
533    {
534        output.exceptions(oldExceptions);
535        throw;
536    }
537    output.exceptions(oldExceptions);
538}
Note: See TracBrowser for help on using the repository browser.