| 235 | } |
| 236 | |
| 237 | BinaryAnnotator::VTable *BinaryAnnotator::GetOrBuildVTable( |
| 238 | const uint64_t vtable_offset, const reflection::Object *const table, |
| 239 | const uint64_t offset_of_referring_table) { |
| 240 | // Get a list of vtables (if any) already defined at this offset. |
| 241 | std::list<VTable> &vtables = vtables_[vtable_offset]; |
| 242 | |
| 243 | // See if this vtable for the table type has been generated before. |
| 244 | for (VTable &vtable : vtables) { |
| 245 | if (vtable.referring_table == table) { return &vtable; } |
| 246 | } |
| 247 | |
| 248 | // If we are trying to make a new vtable and it is already encompassed by |
| 249 | // another binary section, something is corrupted. |
| 250 | if (vtables.empty() && ContainsSection(vtable_offset)) { return nullptr; } |
| 251 | |
| 252 | const std::string referring_table_name = table->name()->str(); |
| 253 | |
| 254 | BinaryRegionComment vtable_size_comment; |
| 255 | vtable_size_comment.type = BinaryRegionCommentType::VTableSize; |
| 256 | |
| 257 | const auto vtable_length = ReadScalar<uint16_t>(vtable_offset); |
| 258 | if (!vtable_length.has_value()) { |
| 259 | const uint64_t remaining = RemainingBytes(vtable_offset); |
| 260 | |
| 261 | SetError(vtable_size_comment, BinaryRegionStatus::ERROR_INCOMPLETE_BINARY, |
| 262 | "2"); |
| 263 | |
| 264 | AddSection(vtable_offset, |
| 265 | MakeSingleRegionBinarySection( |
| 266 | referring_table_name, BinarySectionType::VTable, |
| 267 | MakeBinaryRegion(vtable_offset, remaining, |
| 268 | BinaryRegionType::Unknown, remaining, 0, |
| 269 | vtable_size_comment))); |
| 270 | return nullptr; |
| 271 | } |
| 272 | |
| 273 | // Vtables start with the size of the vtable |
| 274 | const uint16_t vtable_size = vtable_length.value(); |
| 275 | |
| 276 | if (!IsValidOffset(vtable_offset + vtable_size - 1)) { |
| 277 | SetError(vtable_size_comment, BinaryRegionStatus::ERROR_LENGTH_TOO_LONG); |
| 278 | // The vtable_size points to off the end of the binary. |
| 279 | AddSection(vtable_offset, |
| 280 | MakeSingleRegionBinarySection( |
| 281 | referring_table_name, BinarySectionType::VTable, |
| 282 | MakeBinaryRegion(vtable_offset, sizeof(uint16_t), |
| 283 | BinaryRegionType::Uint16, 0, 0, |
| 284 | vtable_size_comment))); |
| 285 | |
| 286 | return nullptr; |
| 287 | } else if (vtable_size < 2 * sizeof(uint16_t)) { |
| 288 | SetError(vtable_size_comment, BinaryRegionStatus::ERROR_LENGTH_TOO_SHORT, |
| 289 | "4"); |
| 290 | // The size includes itself and the table size which are both uint16_t. |
| 291 | AddSection(vtable_offset, |
| 292 | MakeSingleRegionBinarySection( |
| 293 | referring_table_name, BinarySectionType::VTable, |
| 294 | MakeBinaryRegion(vtable_offset, sizeof(uint16_t), |
nothing calls this directly
no test coverage detected