| 134 | } // namespace |
| 135 | |
| 136 | bool ExtractSourceFromModule( |
| 137 | const std::vector<uint32_t>& binary, |
| 138 | std::unordered_map<std::string, std::string>* output) { |
| 139 | auto context = spvtools::SpirvTools(kDefaultEnvironment); |
| 140 | context.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); |
| 141 | |
| 142 | // There is nothing valuable in the header. |
| 143 | spvtools::HeaderParser headerParser = [](const spv_endianness_t, |
| 144 | const spv_parsed_header_t&) { |
| 145 | return SPV_SUCCESS; |
| 146 | }; |
| 147 | |
| 148 | std::unordered_map<uint32_t, std::string> stringMap; |
| 149 | std::vector<std::pair<spv::Id, std::string>> sources; |
| 150 | spv::Op lastOpcode = spv::Op::Max; |
| 151 | size_t instructionIndex = 0; |
| 152 | |
| 153 | spvtools::InstructionParser instructionParser = |
| 154 | [&stringMap, &sources, &lastOpcode, |
| 155 | &instructionIndex](const spv_parsed_instruction_t& instruction) { |
| 156 | const spv_position_t loc = {0, 0, instructionIndex + 1}; |
| 157 | spv_result_t result = SPV_SUCCESS; |
| 158 | |
| 159 | if (instruction.opcode == static_cast<unsigned>(spv::Op::OpString)) { |
| 160 | std::string content; |
| 161 | result = extractOpString(loc, instruction, &content); |
| 162 | if (result == SPV_SUCCESS) { |
| 163 | stringMap.emplace(instruction.result_id, std::move(content)); |
| 164 | } |
| 165 | } else if (instruction.opcode == |
| 166 | static_cast<unsigned>(spv::Op::OpSource)) { |
| 167 | spv::Id filenameId; |
| 168 | std::string code; |
| 169 | result = extractOpSource(loc, instruction, &filenameId, &code); |
| 170 | if (result == SPV_SUCCESS) { |
| 171 | sources.emplace_back(std::make_pair(filenameId, std::move(code))); |
| 172 | } |
| 173 | } else if (instruction.opcode == |
| 174 | static_cast<unsigned>(spv::Op::OpSourceContinued)) { |
| 175 | if (lastOpcode != spv::Op::OpSource) { |
| 176 | spvtools::Error(spvtools::utils::CLIMessageConsumer, "", loc, |
| 177 | "OpSourceContinued MUST follow an OpSource."); |
| 178 | return SPV_ERROR_INVALID_BINARY; |
| 179 | } |
| 180 | |
| 181 | assert(sources.size() > 0); |
| 182 | result = extractOpSourceContinued(loc, instruction, |
| 183 | &sources.back().second); |
| 184 | } |
| 185 | |
| 186 | ++instructionIndex; |
| 187 | lastOpcode = static_cast<spv::Op>(instruction.opcode); |
| 188 | return result; |
| 189 | }; |
| 190 | |
| 191 | if (!context.Parse(binary, headerParser, instructionParser)) { |
| 192 | return false; |
| 193 | } |