1use error::*;
4use intern::{Interner, Symbol};
5#[cfg(feature = "serde")]
6use intern::SerializeWithInterner;
7use reader::Reader;
8
9use byteorder::{BigEndian, ByteOrder};
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12
13use std::{fmt, u64};
14use std::collections::BTreeMap;
15use std::fs::File;
16use std::io::BufReader;
17use std::path::{Path, PathBuf};
18#[cfg(feature = "serde")]
19use std::result::Result as StdResult;
20use std::str::FromStr;
21
22derive_serialize_with_interner! {
26 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
28 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29 pub struct Gcov {
30 pub ty: Type,
32 pub version: Version,
34 pub stamp: u32,
37 pub records: Vec<Record>,
39 #[serde(skip)]
41 pub src: Option<PathBuf>,
42 }
43}
44
45impl Gcov {
46 pub fn open<P: AsRef<Path>>(p: P, interner: &mut Interner) -> Result<Gcov> {
60 debug!("open gcov file {:?}", p.as_ref());
61 let src = p.as_ref().to_owned();
62 Location::File(src.clone()).wrap(|| -> Result<Gcov> {
63 let reader = BufReader::new(File::open(p)?);
64 let mut gcov = Reader::new(reader, interner)?.parse()?;
65 gcov.src = Some(src);
66 Ok(gcov)
67 })
68 }
69}
70
71#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78pub enum Type {
79 Gcno,
81 Gcda,
83}
84
85impl fmt::Display for Type {
86 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
87 fmt.write_str(match *self {
88 Type::Gcno => "gcno",
89 Type::Gcda => "gcda",
90 })
91 }
92}
93
94#[derive(Copy, Clone, PartialEq, Eq, Hash)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101pub struct Tag(pub u32);
102
103pub const EOF_TAG: Tag = Tag(0);
105pub const FUNCTION_TAG: Tag = Tag(0x01_00_00_00);
107pub const BLOCKS_TAG: Tag = Tag(0x01_41_00_00);
109pub const ARCS_TAG: Tag = Tag(0x01_43_00_00);
111pub const LINES_TAG: Tag = Tag(0x01_45_00_00);
113pub const COUNTER_BASE_TAG: Tag = Tag(0x01_a1_00_00);
115pub const OBJECT_SUMMARY_TAG: Tag = Tag(0xa1_00_00_00);
117pub const PROGRAM_SUMMARY_TAG: Tag = Tag(0xa3_00_00_00);
119pub const AFDO_FILE_NAMES_TAG: Tag = Tag(0xaa_00_00_00);
121pub const AFDO_FUNCTION_TAG: Tag = Tag(0xac_00_00_00);
123pub const AFDO_WORKING_SET_TAG: Tag = Tag(0xaf_00_00_00);
125
126impl fmt::Display for Tag {
127 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
128 write!(fmt, "0x{:08x}", self.0)
129 }
130}
131
132impl fmt::Debug for Tag {
133 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
134 write!(fmt, "Tag(0x{:08x})", self.0)
135 }
136}
137
138impl fmt::LowerHex for Tag {
139 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
140 self.0.fmt(fmt)
141 }
142}
143
144impl fmt::UpperHex for Tag {
145 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
146 self.0.fmt(fmt)
147 }
148}
149
150#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
156pub struct Version(u32);
157
158pub const INVALID_VERSION: Version = Version(0);
160
161pub const VERSION_4_7: Version = Version(0x34_30_37_2a);
165
166impl Version {
167 pub fn try_from(raw_version: u32) -> Result<Version> {
175 ensure!(raw_version & 0x80_80_80_ff == 0x2a, ErrorKind::UnsupportedVersion(raw_version));
176 Ok(Version(raw_version))
177 }
178}
179
180
181impl fmt::Debug for Version {
182 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
183 write!(fmt, "Tag(\"{}\")", self)
184 }
185}
186
187impl fmt::Display for Version {
188 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
189 use std::fmt::Write;
190 fmt.write_char((self.0 >> 24 & 0xff) as u8 as char)?;
191 fmt.write_char((self.0 >> 16 & 0xff) as u8 as char)?;
192 fmt.write_char((self.0 >> 8 & 0xff) as u8 as char)?;
193 fmt.write_char((self.0 & 0xff) as u8 as char)?;
194 Ok(())
195 }
196}
197
198impl FromStr for Version {
199 type Err = Error;
200 fn from_str(s: &str) -> Result<Self> {
201 ensure!(s.len() == 4, ErrorKind::UnsupportedVersion(0));
202 let raw_version = BigEndian::read_u32(s.as_bytes());
203 Version::try_from(raw_version)
204 }
205}
206
207#[cfg(feature = "serde")]
208impl Serialize for Version {
209 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
210 serializer.collect_str(self)
211 }
212}
213
214#[cfg(feature = "serde")]
215impl<'de> Deserialize<'de> for Version {
216 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
217 use serde::de::Error;
218 let s = <&'de str>::deserialize(deserializer)?;
219 Version::from_str(s).map_err(D::Error::custom)
220 }
221}
222
223#[derive(Clone, PartialEq, Eq, Hash, Debug)]
229#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
230pub enum Record {
231 Function(Ident, Function),
233 Blocks(Blocks),
235 Arcs(Arcs),
237 Lines(Lines),
239 ArcCounts(ArcCounts),
241 Summary(Summary),
243}
244
245#[cfg(feature = "serde")]
246impl SerializeWithInterner for Record {
247 fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> StdResult<S::Ok, S::Error> {
248 match *self {
249 Record::Function(ref ident, ref function) => {
250 use serde::ser::SerializeTupleVariant;
251 let mut state = serializer.serialize_tuple_variant("Record", 0, "Function", 2)?;
252 state.serialize_field(ident)?;
253 state.serialize_field(&function.with_interner(interner))?;
254 state.end()
255 },
256 Record::Lines(ref lines) => serializer.serialize_newtype_variant("Record", 3, "Lines", &lines.with_interner(interner)),
257 _ => self.serialize(serializer),
258 }
259 }
260}
261
262derive_serialize_with_interner! {
267 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
269 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
270 pub struct Function {
271 pub lineno_checksum: u32,
273 pub cfg_checksum: u32,
275 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
277 pub source: Option<Source>,
278 }
279}
280
281#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
285pub struct Ident(pub u32);
286
287impl fmt::Debug for Ident {
288 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
289 write!(fmt, "Ident({})", self.0)
290 }
291}
292
293impl fmt::Display for Ident {
294 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
295 self.0.fmt(fmt)
296 }
297}
298
299derive_serialize_with_interner! {
300 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
302 #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
303 pub struct Source {
304 pub name: Symbol,
306 pub filename: Symbol,
308 pub line: u32,
310 }
311}
312
313macro_rules! derive_serde_for_attr {
318 ($flags:path, $kind:expr, $allowed_from_gcno:expr) => {
319 #[cfg(feature="serde")]
320 impl Serialize for $flags {
321 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
322 serializer.serialize_u16(self.bits())
323 }
324 }
325
326 #[cfg(feature="serde")]
327 impl<'de> Deserialize<'de> for $flags {
328 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
329 use ::serde::de::Error;
330 let b = u16::deserialize(deserializer)?;
331 <$flags>::from_bits(b).ok_or_else(|| D::Error::custom(ErrorKind::UnsupportedAttr($kind, b as u32)))
332 }
333 }
334
335 impl $flags {
336 pub fn from_gcno(flags: u32) -> Result<$flags> {
344 ensure!(flags & !($allowed_from_gcno.bits() as u32) == 0, ErrorKind::UnsupportedAttr($kind, flags));
345 Ok(<$flags>::from_bits_truncate(flags as u16))
346 }
347 }
348 }
349}
350
351#[derive(Clone, PartialEq, Eq, Hash, Debug)]
353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
354pub struct Blocks {
355 pub flags: Vec<BlockAttr>,
357}
358
359bitflags! {
360 #[derive(Default)]
362 pub struct BlockAttr: u16 {
363 const UNEXPECTED = 2;
367
368 const CALL_SITE = 0x1000;
370
371 const CALL_RETURN = 0x2000;
373
374 const NONLOCAL_RETURN = 0x4000;
376
377 const EXCEPTIONAL = 0x8000;
379 }
380}
381
382derive_serde_for_attr! {
383 BlockAttr, "block", BlockAttr::UNEXPECTED
384}
385
386#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
390#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
391pub struct BlockIndex(pub u32);
392
393impl fmt::Debug for BlockIndex {
394 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
395 write!(fmt, "BI({})", self.0)
396 }
397}
398
399impl From<BlockIndex> for usize {
400 fn from(i: BlockIndex) -> usize {
401 i.0 as usize
402 }
403}
404
405#[derive(Clone, PartialEq, Eq, Hash, Debug)]
411#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
412pub struct Arcs {
413 pub src_block: BlockIndex,
415 pub arcs: Vec<Arc>,
417}
418
419bitflags! {
420 #[derive(Default)]
424 pub struct ArcAttr: u16 {
425 const ON_TREE = 1;
430
431 const FAKE = 2;
436
437 const FALLTHROUGH = 4;
441
442 const THROW = 0x10;
444
445 const CALL_NON_RETURN = 0x20;
447
448 const NONLOCAL_RETURN = 0x40;
450
451 const UNCONDITIONAL = 0x80;
453 }
454}
455
456derive_serde_for_attr! {
457 ArcAttr, "arc", ArcAttr::ON_TREE | ArcAttr::FAKE | ArcAttr::FALLTHROUGH
458}
459
460#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
462#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
463pub struct Arc {
464 pub dest_block: BlockIndex,
468
469 pub flags: ArcAttr,
471}
472
473derive_serialize_with_interner! {
478 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
480 #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
481 pub struct Lines {
482 pub block_number: BlockIndex,
484 pub lines: Vec<Line>,
489 }
490}
491
492#[derive(Copy, Clone, PartialEq, Eq, Hash)]
494#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
495#[cfg_attr(feature = "serde", serde(untagged))]
496pub enum Line {
497 LineNumber(u32),
499 FileName(Symbol),
501}
502
503impl fmt::Debug for Line {
504 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
505 match *self {
506 Line::LineNumber(ref n) => write!(fmt, "Line({:?})", n),
507 Line::FileName(ref n) => write!(fmt, "Line({:?})", n),
508 }
509 }
510}
511
512#[cfg(feature = "serde")]
513impl SerializeWithInterner for Line {
514 fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> StdResult<S::Ok, S::Error> {
515 match *self {
516 Line::LineNumber(number) => number.serialize(serializer),
517 Line::FileName(symbol) => symbol.serialize_with_interner(serializer, interner),
518 }
519 }
520}
521
522#[derive(Clone, PartialEq, Eq, Hash, Debug)]
530#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
531pub struct ArcCounts {
532 pub counts: Vec<u64>,
534}
535
536#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
542#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
543pub struct Summary {
544 pub checksum: u32,
546 pub num: u32,
548 pub runs: u32,
550 pub sum: u64,
552 pub max: u64,
554 pub sum_max: u64,
556 pub histogram: Option<Histogram>,
558}
559
560#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
564#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
565pub struct Histogram {
566 pub buckets: BTreeMap<u32, HistogramBucket>,
570}
571
572#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
577pub struct HistogramBucket {
578 pub num: u32,
580 pub min: u64,
582 pub sum: u64,
584}
585
586impl Default for HistogramBucket {
587 fn default() -> HistogramBucket {
588 HistogramBucket {
589 num: 0,
590 min: u64::MAX,
591 sum: 0,
592 }
593 }
594}
595
596derive_serialize_with_interner! {
599 direct: Type, Tag, Version, Ident, BlockAttr, ArcAttr, Blocks, BlockIndex, Arcs, ArcCounts, Summary
600}