1use gimli::{
2 write::{EndianVec, Writer},
3 DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType, Encoding, EndianSlice, Format,
4 Section,
5};
6use hashbrown::HashMap;
7use tracing::debug;
8
9use crate::{
10 error::{Error, Result},
11 ext::PackageFormatExt,
12};
13
14#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
16pub(crate) struct PackageStringOffset(usize);
17
18pub(crate) struct PackageStringTable {
28 data: Vec<u8>,
29 strings: HashMap<Vec<u8>, PackageStringOffset>,
30}
31
32impl PackageStringTable {
33 pub(crate) fn new() -> Self {
35 Self { data: Vec::new(), strings: HashMap::new() }
36 }
37
38 pub(crate) fn get_or_insert(&mut self, bytes: &[u8]) -> PackageStringOffset {
41 debug_assert!(!bytes.contains(&0));
42 if let Some(offset) = self.strings.get(bytes) {
43 return *offset;
44 }
45
46 let offset = PackageStringOffset(self.data.len());
49 self.strings.insert(bytes.into(), offset);
50
51 self.data.extend_from_slice(bytes);
53 self.data.push(0);
54
55 offset
56 }
57
58 pub(crate) fn remap_str_offsets_section<E: gimli::Endianity>(
62 &mut self,
63 debug_str: gimli::DebugStr<EndianSlice<E>>,
64 debug_str_offsets: gimli::DebugStrOffsets<EndianSlice<E>>,
65 section_size: u64,
66 endian: E,
67 encoding: Encoding,
68 ) -> Result<EndianVec<E>> {
69 let entry_size = match encoding.format {
70 Format::Dwarf32 => 4,
71 Format::Dwarf64 => 8,
72 };
73
74 self.data.reserve(debug_str.reader().len());
76
77 let mut data = EndianVec::new(endian);
78
79 let base: gimli::DebugStrOffsetsBase<usize> =
81 DebugStrOffsetsBase::default_for_encoding_and_file(encoding, DwarfFileType::Dwo);
82
83 if encoding.is_std_dwarf_package_format() {
84 match encoding.format {
85 Format::Dwarf32 => {
86 data.write_u32(
89 (section_size - 8)
90 .try_into()
91 .expect("section size w/out header larger than u32"),
92 )?;
93 }
94 Format::Dwarf64 => {
95 data.write_u32(u32::MAX)?;
98 data.write_u64(section_size - 16)?;
99 }
100 };
101 data.write_u16(5)?;
103 data.write_u16(0)?;
105 }
106 debug!(?base);
107
108 let base_offset: u64 = base.0.try_into().expect("base offset larger than u64");
109 let num_elements = (section_size - base_offset) / entry_size;
110 debug!(?section_size, ?base_offset, ?num_elements);
111
112 for i in 0..num_elements {
113 let dwo_index = DebugStrOffsetsIndex(i as usize);
114 let dwo_offset = debug_str_offsets
115 .get_str_offset(encoding.format, base, dwo_index)
116 .map_err(|e| Error::OffsetAtIndex(e, i))?;
117 let dwo_str =
118 debug_str.get_str(dwo_offset).map_err(|e| Error::StrAtOffset(e, dwo_offset.0))?;
119
120 let dwp_offset = self.get_or_insert(&dwo_str);
121
122 match encoding.format {
123 Format::Dwarf32 => {
124 let dwp_offset =
125 dwp_offset.0.try_into().expect("string offset larger than u32");
126 data.write_u32(dwp_offset)?;
127 }
128 Format::Dwarf64 => {
129 let dwp_offset =
130 dwp_offset.0.try_into().expect("string offset larger than u64");
131 data.write_u64(dwp_offset)?;
132 }
133 }
134 }
135
136 Ok(data)
137 }
138
139 pub(crate) fn finish(self) -> Vec<u8> {
141 self.data
142 }
143}